editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64pub use editor_settings::{
   65    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   66    ShowScrollbar,
   67};
   68use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   69pub use editor_settings_controls::*;
   70use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   71pub use element::{
   72    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   73};
   74use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   75use futures::{
   76    FutureExt,
   77    future::{self, Shared, join},
   78};
   79use fuzzy::StringMatchCandidate;
   80
   81use ::git::blame::BlameEntry;
   82use ::git::{Restore, blame::ParsedCommitMessage};
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use git::blame::{GitBlame, GlobalBlameRenderer};
   88use gpui::{
   89    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   90    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   91    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   92    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   93    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   94    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   95    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   96    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   97};
   98use highlight_matching_bracket::refresh_matching_bracket_highlights;
   99use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  100pub use hover_popover::hover_markdown_style;
  101use hover_popover::{HoverState, hide_hover};
  102use indent_guides::ActiveIndentGuidesState;
  103use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  104pub use inline_completion::Direction;
  105use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  106pub use items::MAX_TAB_TITLE_LEN;
  107use itertools::Itertools;
  108use language::{
  109    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  110    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  111    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  112    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  113    language_settings::{
  114        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  115        all_language_settings, language_settings,
  116    },
  117    point_from_lsp, text_diff_with_options,
  118};
  119use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  120use linked_editing_ranges::refresh_linked_ranges;
  121use markdown::Markdown;
  122use mouse_context_menu::MouseContextMenu;
  123use persistence::DB;
  124use project::{
  125    BreakpointWithPosition, ProjectPath,
  126    debugger::{
  127        breakpoint_store::{
  128            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  129            BreakpointStoreEvent,
  130        },
  131        session::{Session, SessionEvent},
  132    },
  133    project_settings::DiagnosticSeverity,
  134};
  135
  136pub use git::blame::BlameRenderer;
  137pub use proposed_changes_editor::{
  138    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  139};
  140use smallvec::smallvec;
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::SmallVec;
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  257};
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled(bool),
  720}
  721
  722impl MinimapVisibility {
  723    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  724        if mode.is_full() {
  725            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  726        } else {
  727            Self::Disabled
  728        }
  729    }
  730
  731    fn disabled(&self) -> bool {
  732        match *self {
  733            Self::Disabled => true,
  734            _ => false,
  735        }
  736    }
  737
  738    fn visible(&self) -> bool {
  739        match *self {
  740            Self::Enabled(visible) => visible,
  741            _ => false,
  742        }
  743    }
  744
  745    fn toggle_visibility(&self) -> Self {
  746        match *self {
  747            Self::Enabled(visible) => Self::Enabled(!visible),
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751}
  752
  753#[derive(Clone, Debug)]
  754struct RunnableTasks {
  755    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  756    offset: multi_buffer::Anchor,
  757    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  758    column: u32,
  759    // Values of all named captures, including those starting with '_'
  760    extra_variables: HashMap<String, String>,
  761    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  762    context_range: Range<BufferOffset>,
  763}
  764
  765impl RunnableTasks {
  766    fn resolve<'a>(
  767        &'a self,
  768        cx: &'a task::TaskContext,
  769    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  770        self.templates.iter().filter_map(|(kind, template)| {
  771            template
  772                .resolve_task(&kind.to_id_base(), cx)
  773                .map(|task| (kind.clone(), task))
  774        })
  775    }
  776}
  777
  778#[derive(Clone)]
  779struct ResolvedTasks {
  780    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  781    position: Anchor,
  782}
  783
  784#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  785struct BufferOffset(usize);
  786
  787// Addons allow storing per-editor state in other crates (e.g. Vim)
  788pub trait Addon: 'static {
  789    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  790
  791    fn render_buffer_header_controls(
  792        &self,
  793        _: &ExcerptInfo,
  794        _: &Window,
  795        _: &App,
  796    ) -> Option<AnyElement> {
  797        None
  798    }
  799
  800    fn to_any(&self) -> &dyn std::any::Any;
  801
  802    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  803        None
  804    }
  805}
  806
  807/// A set of caret positions, registered when the editor was edited.
  808pub struct ChangeList {
  809    changes: Vec<Vec<Anchor>>,
  810    /// Currently "selected" change.
  811    position: Option<usize>,
  812}
  813
  814impl ChangeList {
  815    pub fn new() -> Self {
  816        Self {
  817            changes: Vec::new(),
  818            position: None,
  819        }
  820    }
  821
  822    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  823    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  824    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  825        if self.changes.is_empty() {
  826            return None;
  827        }
  828
  829        let prev = self.position.unwrap_or(self.changes.len());
  830        let next = if direction == Direction::Prev {
  831            prev.saturating_sub(count)
  832        } else {
  833            (prev + count).min(self.changes.len() - 1)
  834        };
  835        self.position = Some(next);
  836        self.changes.get(next).map(|anchors| anchors.as_slice())
  837    }
  838
  839    /// Adds a new change to the list, resetting the change list position.
  840    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  841        self.position.take();
  842        if pop_state {
  843            self.changes.pop();
  844        }
  845        self.changes.push(new_positions.clone());
  846    }
  847
  848    pub fn last(&self) -> Option<&[Anchor]> {
  849        self.changes.last().map(|anchors| anchors.as_slice())
  850    }
  851}
  852
  853#[derive(Clone)]
  854struct InlineBlamePopoverState {
  855    scroll_handle: ScrollHandle,
  856    commit_message: Option<ParsedCommitMessage>,
  857    markdown: Entity<Markdown>,
  858}
  859
  860struct InlineBlamePopover {
  861    position: gpui::Point<Pixels>,
  862    show_task: Option<Task<()>>,
  863    hide_task: Option<Task<()>>,
  864    popover_bounds: Option<Bounds<Pixels>>,
  865    popover_state: InlineBlamePopoverState,
  866}
  867
  868/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  869/// a breakpoint on them.
  870#[derive(Clone, Copy, Debug)]
  871struct PhantomBreakpointIndicator {
  872    display_row: DisplayRow,
  873    /// There's a small debounce between hovering over the line and showing the indicator.
  874    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  875    is_active: bool,
  876    collides_with_existing_breakpoint: bool,
  877}
  878/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  879///
  880/// See the [module level documentation](self) for more information.
  881pub struct Editor {
  882    focus_handle: FocusHandle,
  883    last_focused_descendant: Option<WeakFocusHandle>,
  884    /// The text buffer being edited
  885    buffer: Entity<MultiBuffer>,
  886    /// Map of how text in the buffer should be displayed.
  887    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  888    pub display_map: Entity<DisplayMap>,
  889    pub selections: SelectionsCollection,
  890    pub scroll_manager: ScrollManager,
  891    /// When inline assist editors are linked, they all render cursors because
  892    /// typing enters text into each of them, even the ones that aren't focused.
  893    pub(crate) show_cursor_when_unfocused: bool,
  894    columnar_selection_tail: Option<Anchor>,
  895    add_selections_state: Option<AddSelectionsState>,
  896    select_next_state: Option<SelectNextState>,
  897    select_prev_state: Option<SelectNextState>,
  898    selection_history: SelectionHistory,
  899    autoclose_regions: Vec<AutocloseRegion>,
  900    snippet_stack: InvalidationStack<SnippetState>,
  901    select_syntax_node_history: SelectSyntaxNodeHistory,
  902    ime_transaction: Option<TransactionId>,
  903    pub diagnostics_max_severity: DiagnosticSeverity,
  904    active_diagnostics: ActiveDiagnostic,
  905    show_inline_diagnostics: bool,
  906    inline_diagnostics_update: Task<()>,
  907    inline_diagnostics_enabled: bool,
  908    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  909    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  910    hard_wrap: Option<usize>,
  911
  912    // TODO: make this a access method
  913    pub project: Option<Entity<Project>>,
  914    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  915    completion_provider: Option<Box<dyn CompletionProvider>>,
  916    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  917    blink_manager: Entity<BlinkManager>,
  918    show_cursor_names: bool,
  919    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  920    pub show_local_selections: bool,
  921    mode: EditorMode,
  922    show_breadcrumbs: bool,
  923    show_gutter: bool,
  924    show_scrollbars: bool,
  925    minimap_visibility: MinimapVisibility,
  926    disable_expand_excerpt_buttons: bool,
  927    show_line_numbers: Option<bool>,
  928    use_relative_line_numbers: Option<bool>,
  929    show_git_diff_gutter: Option<bool>,
  930    show_code_actions: Option<bool>,
  931    show_runnables: Option<bool>,
  932    show_breakpoints: Option<bool>,
  933    show_wrap_guides: Option<bool>,
  934    show_indent_guides: Option<bool>,
  935    placeholder_text: Option<Arc<str>>,
  936    highlight_order: usize,
  937    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  938    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  939    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  940    scrollbar_marker_state: ScrollbarMarkerState,
  941    active_indent_guides_state: ActiveIndentGuidesState,
  942    nav_history: Option<ItemNavHistory>,
  943    context_menu: RefCell<Option<CodeContextMenu>>,
  944    context_menu_options: Option<ContextMenuOptions>,
  945    mouse_context_menu: Option<MouseContextMenu>,
  946    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  947    inline_blame_popover: Option<InlineBlamePopover>,
  948    signature_help_state: SignatureHelpState,
  949    auto_signature_help: Option<bool>,
  950    find_all_references_task_sources: Vec<Anchor>,
  951    next_completion_id: CompletionId,
  952    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  953    code_actions_task: Option<Task<Result<()>>>,
  954    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  955    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    document_highlights_task: Option<Task<()>>,
  957    linked_editing_range_task: Option<Task<Option<()>>>,
  958    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  959    pending_rename: Option<RenameState>,
  960    searchable: bool,
  961    cursor_shape: CursorShape,
  962    current_line_highlight: Option<CurrentLineHighlight>,
  963    collapse_matches: bool,
  964    autoindent_mode: Option<AutoindentMode>,
  965    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  966    input_enabled: bool,
  967    use_modal_editing: bool,
  968    read_only: bool,
  969    leader_id: Option<CollaboratorId>,
  970    remote_id: Option<ViewId>,
  971    pub hover_state: HoverState,
  972    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  973    gutter_hovered: bool,
  974    hovered_link_state: Option<HoveredLinkState>,
  975    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  976    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  977    active_inline_completion: Option<InlineCompletionState>,
  978    /// Used to prevent flickering as the user types while the menu is open
  979    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  980    edit_prediction_settings: EditPredictionSettings,
  981    inline_completions_hidden_for_vim_mode: bool,
  982    show_inline_completions_override: Option<bool>,
  983    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  984    edit_prediction_preview: EditPredictionPreview,
  985    edit_prediction_indent_conflict: bool,
  986    edit_prediction_requires_modifier_in_indent_conflict: bool,
  987    inlay_hint_cache: InlayHintCache,
  988    next_inlay_id: usize,
  989    _subscriptions: Vec<Subscription>,
  990    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  991    gutter_dimensions: GutterDimensions,
  992    style: Option<EditorStyle>,
  993    text_style_refinement: Option<TextStyleRefinement>,
  994    next_editor_action_id: EditorActionId,
  995    editor_actions:
  996        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  997    use_autoclose: bool,
  998    use_auto_surround: bool,
  999    auto_replace_emoji_shortcode: bool,
 1000    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1001    show_git_blame_gutter: bool,
 1002    show_git_blame_inline: bool,
 1003    show_git_blame_inline_delay_task: Option<Task<()>>,
 1004    git_blame_inline_enabled: bool,
 1005    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1006    serialize_dirty_buffers: bool,
 1007    show_selection_menu: Option<bool>,
 1008    blame: Option<Entity<GitBlame>>,
 1009    blame_subscription: Option<Subscription>,
 1010    custom_context_menu: Option<
 1011        Box<
 1012            dyn 'static
 1013                + Fn(
 1014                    &mut Self,
 1015                    DisplayPoint,
 1016                    &mut Window,
 1017                    &mut Context<Self>,
 1018                ) -> Option<Entity<ui::ContextMenu>>,
 1019        >,
 1020    >,
 1021    last_bounds: Option<Bounds<Pixels>>,
 1022    last_position_map: Option<Rc<PositionMap>>,
 1023    expect_bounds_change: Option<Bounds<Pixels>>,
 1024    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1025    tasks_update_task: Option<Task<()>>,
 1026    breakpoint_store: Option<Entity<BreakpointStore>>,
 1027    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1028    in_project_search: bool,
 1029    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1030    breadcrumb_header: Option<String>,
 1031    focused_block: Option<FocusedBlock>,
 1032    next_scroll_position: NextScrollCursorCenterTopBottom,
 1033    addons: HashMap<TypeId, Box<dyn Addon>>,
 1034    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1035    load_diff_task: Option<Shared<Task<()>>>,
 1036    /// Whether we are temporarily displaying a diff other than git's
 1037    temporary_diff_override: bool,
 1038    selection_mark_mode: bool,
 1039    toggle_fold_multiple_buffers: Task<()>,
 1040    _scroll_cursor_center_top_bottom_task: Task<()>,
 1041    serialize_selections: Task<()>,
 1042    serialize_folds: Task<()>,
 1043    mouse_cursor_hidden: bool,
 1044    minimap: Option<Entity<Self>>,
 1045    hide_mouse_mode: HideMouseMode,
 1046    pub change_list: ChangeList,
 1047    inline_value_cache: InlineValueCache,
 1048}
 1049
 1050#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1051enum NextScrollCursorCenterTopBottom {
 1052    #[default]
 1053    Center,
 1054    Top,
 1055    Bottom,
 1056}
 1057
 1058impl NextScrollCursorCenterTopBottom {
 1059    fn next(&self) -> Self {
 1060        match self {
 1061            Self::Center => Self::Top,
 1062            Self::Top => Self::Bottom,
 1063            Self::Bottom => Self::Center,
 1064        }
 1065    }
 1066}
 1067
 1068#[derive(Clone)]
 1069pub struct EditorSnapshot {
 1070    pub mode: EditorMode,
 1071    show_gutter: bool,
 1072    show_line_numbers: Option<bool>,
 1073    show_git_diff_gutter: Option<bool>,
 1074    show_runnables: Option<bool>,
 1075    show_breakpoints: Option<bool>,
 1076    git_blame_gutter_max_author_length: Option<usize>,
 1077    pub display_snapshot: DisplaySnapshot,
 1078    pub placeholder_text: Option<Arc<str>>,
 1079    is_focused: bool,
 1080    scroll_anchor: ScrollAnchor,
 1081    ongoing_scroll: OngoingScroll,
 1082    current_line_highlight: CurrentLineHighlight,
 1083    gutter_hovered: bool,
 1084}
 1085
 1086#[derive(Default, Debug, Clone, Copy)]
 1087pub struct GutterDimensions {
 1088    pub left_padding: Pixels,
 1089    pub right_padding: Pixels,
 1090    pub width: Pixels,
 1091    pub margin: Pixels,
 1092    pub git_blame_entries_width: Option<Pixels>,
 1093}
 1094
 1095impl GutterDimensions {
 1096    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1097        Self {
 1098            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1099            ..Default::default()
 1100        }
 1101    }
 1102
 1103    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1104        -cx.text_system().descent(font_id, font_size)
 1105    }
 1106    /// The full width of the space taken up by the gutter.
 1107    pub fn full_width(&self) -> Pixels {
 1108        self.margin + self.width
 1109    }
 1110
 1111    /// The width of the space reserved for the fold indicators,
 1112    /// use alongside 'justify_end' and `gutter_width` to
 1113    /// right align content with the line numbers
 1114    pub fn fold_area_width(&self) -> Pixels {
 1115        self.margin + self.right_padding
 1116    }
 1117}
 1118
 1119#[derive(Debug)]
 1120pub struct RemoteSelection {
 1121    pub replica_id: ReplicaId,
 1122    pub selection: Selection<Anchor>,
 1123    pub cursor_shape: CursorShape,
 1124    pub collaborator_id: CollaboratorId,
 1125    pub line_mode: bool,
 1126    pub user_name: Option<SharedString>,
 1127    pub color: PlayerColor,
 1128}
 1129
 1130#[derive(Clone, Debug)]
 1131struct SelectionHistoryEntry {
 1132    selections: Arc<[Selection<Anchor>]>,
 1133    select_next_state: Option<SelectNextState>,
 1134    select_prev_state: Option<SelectNextState>,
 1135    add_selections_state: Option<AddSelectionsState>,
 1136}
 1137
 1138enum SelectionHistoryMode {
 1139    Normal,
 1140    Undoing,
 1141    Redoing,
 1142}
 1143
 1144#[derive(Clone, PartialEq, Eq, Hash)]
 1145struct HoveredCursor {
 1146    replica_id: u16,
 1147    selection_id: usize,
 1148}
 1149
 1150impl Default for SelectionHistoryMode {
 1151    fn default() -> Self {
 1152        Self::Normal
 1153    }
 1154}
 1155
 1156#[derive(Default)]
 1157struct SelectionHistory {
 1158    #[allow(clippy::type_complexity)]
 1159    selections_by_transaction:
 1160        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1161    mode: SelectionHistoryMode,
 1162    undo_stack: VecDeque<SelectionHistoryEntry>,
 1163    redo_stack: VecDeque<SelectionHistoryEntry>,
 1164}
 1165
 1166impl SelectionHistory {
 1167    fn insert_transaction(
 1168        &mut self,
 1169        transaction_id: TransactionId,
 1170        selections: Arc<[Selection<Anchor>]>,
 1171    ) {
 1172        self.selections_by_transaction
 1173            .insert(transaction_id, (selections, None));
 1174    }
 1175
 1176    #[allow(clippy::type_complexity)]
 1177    fn transaction(
 1178        &self,
 1179        transaction_id: TransactionId,
 1180    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1181        self.selections_by_transaction.get(&transaction_id)
 1182    }
 1183
 1184    #[allow(clippy::type_complexity)]
 1185    fn transaction_mut(
 1186        &mut self,
 1187        transaction_id: TransactionId,
 1188    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1189        self.selections_by_transaction.get_mut(&transaction_id)
 1190    }
 1191
 1192    fn push(&mut self, entry: SelectionHistoryEntry) {
 1193        if !entry.selections.is_empty() {
 1194            match self.mode {
 1195                SelectionHistoryMode::Normal => {
 1196                    self.push_undo(entry);
 1197                    self.redo_stack.clear();
 1198                }
 1199                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1200                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1201            }
 1202        }
 1203    }
 1204
 1205    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1206        if self
 1207            .undo_stack
 1208            .back()
 1209            .map_or(true, |e| e.selections != entry.selections)
 1210        {
 1211            self.undo_stack.push_back(entry);
 1212            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1213                self.undo_stack.pop_front();
 1214            }
 1215        }
 1216    }
 1217
 1218    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1219        if self
 1220            .redo_stack
 1221            .back()
 1222            .map_or(true, |e| e.selections != entry.selections)
 1223        {
 1224            self.redo_stack.push_back(entry);
 1225            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1226                self.redo_stack.pop_front();
 1227            }
 1228        }
 1229    }
 1230}
 1231
 1232#[derive(Clone, Copy)]
 1233pub struct RowHighlightOptions {
 1234    pub autoscroll: bool,
 1235    pub include_gutter: bool,
 1236}
 1237
 1238impl Default for RowHighlightOptions {
 1239    fn default() -> Self {
 1240        Self {
 1241            autoscroll: Default::default(),
 1242            include_gutter: true,
 1243        }
 1244    }
 1245}
 1246
 1247struct RowHighlight {
 1248    index: usize,
 1249    range: Range<Anchor>,
 1250    color: Hsla,
 1251    options: RowHighlightOptions,
 1252    type_id: TypeId,
 1253}
 1254
 1255#[derive(Clone, Debug)]
 1256struct AddSelectionsState {
 1257    above: bool,
 1258    stack: Vec<usize>,
 1259}
 1260
 1261#[derive(Clone)]
 1262struct SelectNextState {
 1263    query: AhoCorasick,
 1264    wordwise: bool,
 1265    done: bool,
 1266}
 1267
 1268impl std::fmt::Debug for SelectNextState {
 1269    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1270        f.debug_struct(std::any::type_name::<Self>())
 1271            .field("wordwise", &self.wordwise)
 1272            .field("done", &self.done)
 1273            .finish()
 1274    }
 1275}
 1276
 1277#[derive(Debug)]
 1278struct AutocloseRegion {
 1279    selection_id: usize,
 1280    range: Range<Anchor>,
 1281    pair: BracketPair,
 1282}
 1283
 1284#[derive(Debug)]
 1285struct SnippetState {
 1286    ranges: Vec<Vec<Range<Anchor>>>,
 1287    active_index: usize,
 1288    choices: Vec<Option<Vec<String>>>,
 1289}
 1290
 1291#[doc(hidden)]
 1292pub struct RenameState {
 1293    pub range: Range<Anchor>,
 1294    pub old_name: Arc<str>,
 1295    pub editor: Entity<Editor>,
 1296    block_id: CustomBlockId,
 1297}
 1298
 1299struct InvalidationStack<T>(Vec<T>);
 1300
 1301struct RegisteredInlineCompletionProvider {
 1302    provider: Arc<dyn InlineCompletionProviderHandle>,
 1303    _subscription: Subscription,
 1304}
 1305
 1306#[derive(Debug, PartialEq, Eq)]
 1307pub struct ActiveDiagnosticGroup {
 1308    pub active_range: Range<Anchor>,
 1309    pub active_message: String,
 1310    pub group_id: usize,
 1311    pub blocks: HashSet<CustomBlockId>,
 1312}
 1313
 1314#[derive(Debug, PartialEq, Eq)]
 1315
 1316pub(crate) enum ActiveDiagnostic {
 1317    None,
 1318    All,
 1319    Group(ActiveDiagnosticGroup),
 1320}
 1321
 1322#[derive(Serialize, Deserialize, Clone, Debug)]
 1323pub struct ClipboardSelection {
 1324    /// The number of bytes in this selection.
 1325    pub len: usize,
 1326    /// Whether this was a full-line selection.
 1327    pub is_entire_line: bool,
 1328    /// The indentation of the first line when this content was originally copied.
 1329    pub first_line_indent: u32,
 1330}
 1331
 1332// selections, scroll behavior, was newest selection reversed
 1333type SelectSyntaxNodeHistoryState = (
 1334    Box<[Selection<usize>]>,
 1335    SelectSyntaxNodeScrollBehavior,
 1336    bool,
 1337);
 1338
 1339#[derive(Default)]
 1340struct SelectSyntaxNodeHistory {
 1341    stack: Vec<SelectSyntaxNodeHistoryState>,
 1342    // disable temporarily to allow changing selections without losing the stack
 1343    pub disable_clearing: bool,
 1344}
 1345
 1346impl SelectSyntaxNodeHistory {
 1347    pub fn try_clear(&mut self) {
 1348        if !self.disable_clearing {
 1349            self.stack.clear();
 1350        }
 1351    }
 1352
 1353    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1354        self.stack.push(selection);
 1355    }
 1356
 1357    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1358        self.stack.pop()
 1359    }
 1360}
 1361
 1362enum SelectSyntaxNodeScrollBehavior {
 1363    CursorTop,
 1364    FitSelection,
 1365    CursorBottom,
 1366}
 1367
 1368#[derive(Debug)]
 1369pub(crate) struct NavigationData {
 1370    cursor_anchor: Anchor,
 1371    cursor_position: Point,
 1372    scroll_anchor: ScrollAnchor,
 1373    scroll_top_row: u32,
 1374}
 1375
 1376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1377pub enum GotoDefinitionKind {
 1378    Symbol,
 1379    Declaration,
 1380    Type,
 1381    Implementation,
 1382}
 1383
 1384#[derive(Debug, Clone)]
 1385enum InlayHintRefreshReason {
 1386    ModifiersChanged(bool),
 1387    Toggle(bool),
 1388    SettingsChange(InlayHintSettings),
 1389    NewLinesShown,
 1390    BufferEdited(HashSet<Arc<Language>>),
 1391    RefreshRequested,
 1392    ExcerptsRemoved(Vec<ExcerptId>),
 1393}
 1394
 1395impl InlayHintRefreshReason {
 1396    fn description(&self) -> &'static str {
 1397        match self {
 1398            Self::ModifiersChanged(_) => "modifiers changed",
 1399            Self::Toggle(_) => "toggle",
 1400            Self::SettingsChange(_) => "settings change",
 1401            Self::NewLinesShown => "new lines shown",
 1402            Self::BufferEdited(_) => "buffer edited",
 1403            Self::RefreshRequested => "refresh requested",
 1404            Self::ExcerptsRemoved(_) => "excerpts removed",
 1405        }
 1406    }
 1407}
 1408
 1409pub enum FormatTarget {
 1410    Buffers,
 1411    Ranges(Vec<Range<MultiBufferPoint>>),
 1412}
 1413
 1414pub(crate) struct FocusedBlock {
 1415    id: BlockId,
 1416    focus_handle: WeakFocusHandle,
 1417}
 1418
 1419#[derive(Clone)]
 1420enum JumpData {
 1421    MultiBufferRow {
 1422        row: MultiBufferRow,
 1423        line_offset_from_top: u32,
 1424    },
 1425    MultiBufferPoint {
 1426        excerpt_id: ExcerptId,
 1427        position: Point,
 1428        anchor: text::Anchor,
 1429        line_offset_from_top: u32,
 1430    },
 1431}
 1432
 1433pub enum MultibufferSelectionMode {
 1434    First,
 1435    All,
 1436}
 1437
 1438#[derive(Clone, Copy, Debug, Default)]
 1439pub struct RewrapOptions {
 1440    pub override_language_settings: bool,
 1441    pub preserve_existing_whitespace: bool,
 1442}
 1443
 1444impl Editor {
 1445    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1446        let buffer = cx.new(|cx| Buffer::local("", cx));
 1447        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1448        Self::new(
 1449            EditorMode::SingleLine { auto_width: false },
 1450            buffer,
 1451            None,
 1452            window,
 1453            cx,
 1454        )
 1455    }
 1456
 1457    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1458        let buffer = cx.new(|cx| Buffer::local("", cx));
 1459        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1460        Self::new(EditorMode::full(), buffer, None, window, cx)
 1461    }
 1462
 1463    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1464        let buffer = cx.new(|cx| Buffer::local("", cx));
 1465        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1466        Self::new(
 1467            EditorMode::SingleLine { auto_width: true },
 1468            buffer,
 1469            None,
 1470            window,
 1471            cx,
 1472        )
 1473    }
 1474
 1475    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1476        let buffer = cx.new(|cx| Buffer::local("", cx));
 1477        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1478        Self::new(
 1479            EditorMode::AutoHeight { max_lines },
 1480            buffer,
 1481            None,
 1482            window,
 1483            cx,
 1484        )
 1485    }
 1486
 1487    pub fn for_buffer(
 1488        buffer: Entity<Buffer>,
 1489        project: Option<Entity<Project>>,
 1490        window: &mut Window,
 1491        cx: &mut Context<Self>,
 1492    ) -> Self {
 1493        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1494        Self::new(EditorMode::full(), buffer, project, window, cx)
 1495    }
 1496
 1497    pub fn for_multibuffer(
 1498        buffer: Entity<MultiBuffer>,
 1499        project: Option<Entity<Project>>,
 1500        window: &mut Window,
 1501        cx: &mut Context<Self>,
 1502    ) -> Self {
 1503        Self::new(EditorMode::full(), buffer, project, window, cx)
 1504    }
 1505
 1506    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1507        let mut clone = Self::new(
 1508            self.mode.clone(),
 1509            self.buffer.clone(),
 1510            self.project.clone(),
 1511            window,
 1512            cx,
 1513        );
 1514        self.display_map.update(cx, |display_map, cx| {
 1515            let snapshot = display_map.snapshot(cx);
 1516            clone.display_map.update(cx, |display_map, cx| {
 1517                display_map.set_state(&snapshot, cx);
 1518            });
 1519        });
 1520        clone.folds_did_change(cx);
 1521        clone.selections.clone_state(&self.selections);
 1522        clone.scroll_manager.clone_state(&self.scroll_manager);
 1523        clone.searchable = self.searchable;
 1524        clone.read_only = self.read_only;
 1525        clone
 1526    }
 1527
 1528    pub fn new(
 1529        mode: EditorMode,
 1530        buffer: Entity<MultiBuffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        Editor::new_internal(mode, buffer, project, None, window, cx)
 1536    }
 1537
 1538    fn new_internal(
 1539        mode: EditorMode,
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        display_map: Option<Entity<DisplayMap>>,
 1543        window: &mut Window,
 1544        cx: &mut Context<Self>,
 1545    ) -> Self {
 1546        debug_assert!(
 1547            display_map.is_none() || mode.is_minimap(),
 1548            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1549        );
 1550
 1551        let full_mode = mode.is_full();
 1552        let diagnostics_max_severity = if full_mode {
 1553            EditorSettings::get_global(cx)
 1554                .diagnostics_max_severity
 1555                .unwrap_or(DiagnosticSeverity::Hint)
 1556        } else {
 1557            DiagnosticSeverity::Off
 1558        };
 1559        let style = window.text_style();
 1560        let font_size = style.font_size.to_pixels(window.rem_size());
 1561        let editor = cx.entity().downgrade();
 1562        let fold_placeholder = FoldPlaceholder {
 1563            constrain_width: true,
 1564            render: Arc::new(move |fold_id, fold_range, cx| {
 1565                let editor = editor.clone();
 1566                div()
 1567                    .id(fold_id)
 1568                    .bg(cx.theme().colors().ghost_element_background)
 1569                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1570                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1571                    .rounded_xs()
 1572                    .size_full()
 1573                    .cursor_pointer()
 1574                    .child("")
 1575                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1576                    .on_click(move |_, _window, cx| {
 1577                        editor
 1578                            .update(cx, |editor, cx| {
 1579                                editor.unfold_ranges(
 1580                                    &[fold_range.start..fold_range.end],
 1581                                    true,
 1582                                    false,
 1583                                    cx,
 1584                                );
 1585                                cx.stop_propagation();
 1586                            })
 1587                            .ok();
 1588                    })
 1589                    .into_any()
 1590            }),
 1591            merge_adjacent: true,
 1592            ..FoldPlaceholder::default()
 1593        };
 1594        let display_map = display_map.unwrap_or_else(|| {
 1595            cx.new(|cx| {
 1596                DisplayMap::new(
 1597                    buffer.clone(),
 1598                    style.font(),
 1599                    font_size,
 1600                    None,
 1601                    FILE_HEADER_HEIGHT,
 1602                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1603                    fold_placeholder,
 1604                    diagnostics_max_severity,
 1605                    cx,
 1606                )
 1607            })
 1608        });
 1609
 1610        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1611
 1612        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1613
 1614        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1615            .then(|| language_settings::SoftWrap::None);
 1616
 1617        let mut project_subscriptions = Vec::new();
 1618        if mode.is_full() {
 1619            if let Some(project) = project.as_ref() {
 1620                project_subscriptions.push(cx.subscribe_in(
 1621                    project,
 1622                    window,
 1623                    |editor, _, event, window, cx| match event {
 1624                        project::Event::RefreshCodeLens => {
 1625                            // we always query lens with actions, without storing them, always refreshing them
 1626                        }
 1627                        project::Event::RefreshInlayHints => {
 1628                            editor
 1629                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1630                        }
 1631                        project::Event::SnippetEdit(id, snippet_edits) => {
 1632                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1633                                let focus_handle = editor.focus_handle(cx);
 1634                                if focus_handle.is_focused(window) {
 1635                                    let snapshot = buffer.read(cx).snapshot();
 1636                                    for (range, snippet) in snippet_edits {
 1637                                        let editor_range =
 1638                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1639                                        editor
 1640                                            .insert_snippet(
 1641                                                &[editor_range],
 1642                                                snippet.clone(),
 1643                                                window,
 1644                                                cx,
 1645                                            )
 1646                                            .ok();
 1647                                    }
 1648                                }
 1649                            }
 1650                        }
 1651                        _ => {}
 1652                    },
 1653                ));
 1654                if let Some(task_inventory) = project
 1655                    .read(cx)
 1656                    .task_store()
 1657                    .read(cx)
 1658                    .task_inventory()
 1659                    .cloned()
 1660                {
 1661                    project_subscriptions.push(cx.observe_in(
 1662                        &task_inventory,
 1663                        window,
 1664                        |editor, _, window, cx| {
 1665                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1666                        },
 1667                    ));
 1668                };
 1669
 1670                project_subscriptions.push(cx.subscribe_in(
 1671                    &project.read(cx).breakpoint_store(),
 1672                    window,
 1673                    |editor, _, event, window, cx| match event {
 1674                        BreakpointStoreEvent::ClearDebugLines => {
 1675                            editor.clear_row_highlights::<ActiveDebugLine>();
 1676                            editor.refresh_inline_values(cx);
 1677                        }
 1678                        BreakpointStoreEvent::SetDebugLine => {
 1679                            if editor.go_to_active_debug_line(window, cx) {
 1680                                cx.stop_propagation();
 1681                            }
 1682
 1683                            editor.refresh_inline_values(cx);
 1684                        }
 1685                        _ => {}
 1686                    },
 1687                ));
 1688            }
 1689        }
 1690
 1691        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1692
 1693        let inlay_hint_settings =
 1694            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1695        let focus_handle = cx.focus_handle();
 1696        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1697            .detach();
 1698        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1699            .detach();
 1700        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1701            .detach();
 1702        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1703            .detach();
 1704
 1705        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1706            Some(false)
 1707        } else {
 1708            None
 1709        };
 1710
 1711        let breakpoint_store = match (&mode, project.as_ref()) {
 1712            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1713            _ => None,
 1714        };
 1715
 1716        let mut code_action_providers = Vec::new();
 1717        let mut load_uncommitted_diff = None;
 1718        if let Some(project) = project.clone() {
 1719            load_uncommitted_diff = Some(
 1720                update_uncommitted_diff_for_buffer(
 1721                    cx.entity(),
 1722                    &project,
 1723                    buffer.read(cx).all_buffers(),
 1724                    buffer.clone(),
 1725                    cx,
 1726                )
 1727                .shared(),
 1728            );
 1729            code_action_providers.push(Rc::new(project) as Rc<_>);
 1730        }
 1731
 1732        let mut this = Self {
 1733            focus_handle,
 1734            show_cursor_when_unfocused: false,
 1735            last_focused_descendant: None,
 1736            buffer: buffer.clone(),
 1737            display_map: display_map.clone(),
 1738            selections,
 1739            scroll_manager: ScrollManager::new(cx),
 1740            columnar_selection_tail: None,
 1741            add_selections_state: None,
 1742            select_next_state: None,
 1743            select_prev_state: None,
 1744            selection_history: SelectionHistory::default(),
 1745            autoclose_regions: Vec::new(),
 1746            snippet_stack: InvalidationStack::default(),
 1747            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1748            ime_transaction: None,
 1749            active_diagnostics: ActiveDiagnostic::None,
 1750            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1751            inline_diagnostics_update: Task::ready(()),
 1752            inline_diagnostics: Vec::new(),
 1753            soft_wrap_mode_override,
 1754            diagnostics_max_severity,
 1755            hard_wrap: None,
 1756            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1757            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1758            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1759            project,
 1760            blink_manager: blink_manager.clone(),
 1761            show_local_selections: true,
 1762            show_scrollbars: full_mode,
 1763            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1764            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1765            show_gutter: mode.is_full(),
 1766            show_line_numbers: None,
 1767            use_relative_line_numbers: None,
 1768            disable_expand_excerpt_buttons: false,
 1769            show_git_diff_gutter: None,
 1770            show_code_actions: None,
 1771            show_runnables: None,
 1772            show_breakpoints: None,
 1773            show_wrap_guides: None,
 1774            show_indent_guides,
 1775            placeholder_text: None,
 1776            highlight_order: 0,
 1777            highlighted_rows: HashMap::default(),
 1778            background_highlights: TreeMap::default(),
 1779            gutter_highlights: TreeMap::default(),
 1780            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1781            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1782            nav_history: None,
 1783            context_menu: RefCell::new(None),
 1784            context_menu_options: None,
 1785            mouse_context_menu: None,
 1786            completion_tasks: Vec::new(),
 1787            inline_blame_popover: None,
 1788            signature_help_state: SignatureHelpState::default(),
 1789            auto_signature_help: None,
 1790            find_all_references_task_sources: Vec::new(),
 1791            next_completion_id: 0,
 1792            next_inlay_id: 0,
 1793            code_action_providers,
 1794            available_code_actions: None,
 1795            code_actions_task: None,
 1796            quick_selection_highlight_task: None,
 1797            debounced_selection_highlight_task: None,
 1798            document_highlights_task: None,
 1799            linked_editing_range_task: None,
 1800            pending_rename: None,
 1801            searchable: true,
 1802            cursor_shape: EditorSettings::get_global(cx)
 1803                .cursor_shape
 1804                .unwrap_or_default(),
 1805            current_line_highlight: None,
 1806            autoindent_mode: Some(AutoindentMode::EachLine),
 1807            collapse_matches: false,
 1808            workspace: None,
 1809            input_enabled: true,
 1810            use_modal_editing: mode.is_full(),
 1811            read_only: mode.is_minimap(),
 1812            use_autoclose: true,
 1813            use_auto_surround: true,
 1814            auto_replace_emoji_shortcode: false,
 1815            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1816            leader_id: None,
 1817            remote_id: None,
 1818            hover_state: HoverState::default(),
 1819            pending_mouse_down: None,
 1820            hovered_link_state: None,
 1821            edit_prediction_provider: None,
 1822            active_inline_completion: None,
 1823            stale_inline_completion_in_menu: None,
 1824            edit_prediction_preview: EditPredictionPreview::Inactive {
 1825                released_too_fast: false,
 1826            },
 1827            inline_diagnostics_enabled: mode.is_full(),
 1828            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1829            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1830
 1831            gutter_hovered: false,
 1832            pixel_position_of_newest_cursor: None,
 1833            last_bounds: None,
 1834            last_position_map: None,
 1835            expect_bounds_change: None,
 1836            gutter_dimensions: GutterDimensions::default(),
 1837            style: None,
 1838            show_cursor_names: false,
 1839            hovered_cursors: HashMap::default(),
 1840            next_editor_action_id: EditorActionId::default(),
 1841            editor_actions: Rc::default(),
 1842            inline_completions_hidden_for_vim_mode: false,
 1843            show_inline_completions_override: None,
 1844            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1845            edit_prediction_settings: EditPredictionSettings::Disabled,
 1846            edit_prediction_indent_conflict: false,
 1847            edit_prediction_requires_modifier_in_indent_conflict: true,
 1848            custom_context_menu: None,
 1849            show_git_blame_gutter: false,
 1850            show_git_blame_inline: false,
 1851            show_selection_menu: None,
 1852            show_git_blame_inline_delay_task: None,
 1853            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1854            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1855            serialize_dirty_buffers: !mode.is_minimap()
 1856                && ProjectSettings::get_global(cx)
 1857                    .session
 1858                    .restore_unsaved_buffers,
 1859            blame: None,
 1860            blame_subscription: None,
 1861            tasks: BTreeMap::default(),
 1862
 1863            breakpoint_store,
 1864            gutter_breakpoint_indicator: (None, None),
 1865            _subscriptions: vec![
 1866                cx.observe(&buffer, Self::on_buffer_changed),
 1867                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1868                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1869                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1870                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1871                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1872                cx.observe_window_activation(window, |editor, window, cx| {
 1873                    let active = window.is_window_active();
 1874                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1875                        if active {
 1876                            blink_manager.enable(cx);
 1877                        } else {
 1878                            blink_manager.disable(cx);
 1879                        }
 1880                    });
 1881                }),
 1882            ],
 1883            tasks_update_task: None,
 1884            linked_edit_ranges: Default::default(),
 1885            in_project_search: false,
 1886            previous_search_ranges: None,
 1887            breadcrumb_header: None,
 1888            focused_block: None,
 1889            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1890            addons: HashMap::default(),
 1891            registered_buffers: HashMap::default(),
 1892            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1893            selection_mark_mode: false,
 1894            toggle_fold_multiple_buffers: Task::ready(()),
 1895            serialize_selections: Task::ready(()),
 1896            serialize_folds: Task::ready(()),
 1897            text_style_refinement: None,
 1898            load_diff_task: load_uncommitted_diff,
 1899            temporary_diff_override: false,
 1900            mouse_cursor_hidden: false,
 1901            minimap: None,
 1902            hide_mouse_mode: EditorSettings::get_global(cx)
 1903                .hide_mouse
 1904                .unwrap_or_default(),
 1905            change_list: ChangeList::new(),
 1906            mode,
 1907        };
 1908        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1909            this._subscriptions
 1910                .push(cx.observe(breakpoints, |_, _, cx| {
 1911                    cx.notify();
 1912                }));
 1913        }
 1914        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1915        this._subscriptions.extend(project_subscriptions);
 1916
 1917        this._subscriptions.push(cx.subscribe_in(
 1918            &cx.entity(),
 1919            window,
 1920            |editor, _, e: &EditorEvent, window, cx| match e {
 1921                EditorEvent::ScrollPositionChanged { local, .. } => {
 1922                    if *local {
 1923                        let new_anchor = editor.scroll_manager.anchor();
 1924                        let snapshot = editor.snapshot(window, cx);
 1925                        editor.update_restoration_data(cx, move |data| {
 1926                            data.scroll_position = (
 1927                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1928                                new_anchor.offset,
 1929                            );
 1930                        });
 1931                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1932                        editor.inline_blame_popover.take();
 1933                    }
 1934                }
 1935                EditorEvent::Edited { .. } => {
 1936                    if !vim_enabled(cx) {
 1937                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1938                        let pop_state = editor
 1939                            .change_list
 1940                            .last()
 1941                            .map(|previous| {
 1942                                previous.len() == selections.len()
 1943                                    && previous.iter().enumerate().all(|(ix, p)| {
 1944                                        p.to_display_point(&map).row()
 1945                                            == selections[ix].head().row()
 1946                                    })
 1947                            })
 1948                            .unwrap_or(false);
 1949                        let new_positions = selections
 1950                            .into_iter()
 1951                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1952                            .collect();
 1953                        editor
 1954                            .change_list
 1955                            .push_to_change_list(pop_state, new_positions);
 1956                    }
 1957                }
 1958                _ => (),
 1959            },
 1960        ));
 1961
 1962        if let Some(dap_store) = this
 1963            .project
 1964            .as_ref()
 1965            .map(|project| project.read(cx).dap_store())
 1966        {
 1967            let weak_editor = cx.weak_entity();
 1968
 1969            this._subscriptions
 1970                .push(
 1971                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1972                        let session_entity = cx.entity();
 1973                        weak_editor
 1974                            .update(cx, |editor, cx| {
 1975                                editor._subscriptions.push(
 1976                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1977                                );
 1978                            })
 1979                            .ok();
 1980                    }),
 1981                );
 1982
 1983            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1984                this._subscriptions
 1985                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1986            }
 1987        }
 1988
 1989        this.end_selection(window, cx);
 1990        this.scroll_manager.show_scrollbars(window, cx);
 1991        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1992
 1993        if full_mode {
 1994            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1995            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1996
 1997            if this.git_blame_inline_enabled {
 1998                this.start_git_blame_inline(false, window, cx);
 1999            }
 2000
 2001            this.go_to_active_debug_line(window, cx);
 2002
 2003            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2004                if let Some(project) = this.project.as_ref() {
 2005                    let handle = project.update(cx, |project, cx| {
 2006                        project.register_buffer_with_language_servers(&buffer, cx)
 2007                    });
 2008                    this.registered_buffers
 2009                        .insert(buffer.read(cx).remote_id(), handle);
 2010                }
 2011            }
 2012
 2013            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2014        }
 2015
 2016        this.report_editor_event("Editor Opened", None, cx);
 2017        this
 2018    }
 2019
 2020    pub fn deploy_mouse_context_menu(
 2021        &mut self,
 2022        position: gpui::Point<Pixels>,
 2023        context_menu: Entity<ContextMenu>,
 2024        window: &mut Window,
 2025        cx: &mut Context<Self>,
 2026    ) {
 2027        self.mouse_context_menu = Some(MouseContextMenu::new(
 2028            self,
 2029            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2030            context_menu,
 2031            window,
 2032            cx,
 2033        ));
 2034    }
 2035
 2036    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2037        self.mouse_context_menu
 2038            .as_ref()
 2039            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2040    }
 2041
 2042    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2043        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2044    }
 2045
 2046    fn key_context_internal(
 2047        &self,
 2048        has_active_edit_prediction: bool,
 2049        window: &Window,
 2050        cx: &App,
 2051    ) -> KeyContext {
 2052        let mut key_context = KeyContext::new_with_defaults();
 2053        key_context.add("Editor");
 2054        let mode = match self.mode {
 2055            EditorMode::SingleLine { .. } => "single_line",
 2056            EditorMode::AutoHeight { .. } => "auto_height",
 2057            EditorMode::Minimap { .. } => "minimap",
 2058            EditorMode::Full { .. } => "full",
 2059        };
 2060
 2061        if EditorSettings::jupyter_enabled(cx) {
 2062            key_context.add("jupyter");
 2063        }
 2064
 2065        key_context.set("mode", mode);
 2066        if self.pending_rename.is_some() {
 2067            key_context.add("renaming");
 2068        }
 2069
 2070        match self.context_menu.borrow().as_ref() {
 2071            Some(CodeContextMenu::Completions(_)) => {
 2072                key_context.add("menu");
 2073                key_context.add("showing_completions");
 2074            }
 2075            Some(CodeContextMenu::CodeActions(_)) => {
 2076                key_context.add("menu");
 2077                key_context.add("showing_code_actions")
 2078            }
 2079            None => {}
 2080        }
 2081
 2082        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2083        if !self.focus_handle(cx).contains_focused(window, cx)
 2084            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2085        {
 2086            for addon in self.addons.values() {
 2087                addon.extend_key_context(&mut key_context, cx)
 2088            }
 2089        }
 2090
 2091        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2092            if let Some(extension) = singleton_buffer
 2093                .read(cx)
 2094                .file()
 2095                .and_then(|file| file.path().extension()?.to_str())
 2096            {
 2097                key_context.set("extension", extension.to_string());
 2098            }
 2099        } else {
 2100            key_context.add("multibuffer");
 2101        }
 2102
 2103        if has_active_edit_prediction {
 2104            if self.edit_prediction_in_conflict() {
 2105                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2106            } else {
 2107                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2108                key_context.add("copilot_suggestion");
 2109            }
 2110        }
 2111
 2112        if self.selection_mark_mode {
 2113            key_context.add("selection_mode");
 2114        }
 2115
 2116        key_context
 2117    }
 2118
 2119    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2120        self.mouse_cursor_hidden = match origin {
 2121            HideMouseCursorOrigin::TypingAction => {
 2122                matches!(
 2123                    self.hide_mouse_mode,
 2124                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2125                )
 2126            }
 2127            HideMouseCursorOrigin::MovementAction => {
 2128                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2129            }
 2130        };
 2131    }
 2132
 2133    pub fn edit_prediction_in_conflict(&self) -> bool {
 2134        if !self.show_edit_predictions_in_menu() {
 2135            return false;
 2136        }
 2137
 2138        let showing_completions = self
 2139            .context_menu
 2140            .borrow()
 2141            .as_ref()
 2142            .map_or(false, |context| {
 2143                matches!(context, CodeContextMenu::Completions(_))
 2144            });
 2145
 2146        showing_completions
 2147            || self.edit_prediction_requires_modifier()
 2148            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2149            // bindings to insert tab characters.
 2150            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2151    }
 2152
 2153    pub fn accept_edit_prediction_keybind(
 2154        &self,
 2155        window: &Window,
 2156        cx: &App,
 2157    ) -> AcceptEditPredictionBinding {
 2158        let key_context = self.key_context_internal(true, window, cx);
 2159        let in_conflict = self.edit_prediction_in_conflict();
 2160
 2161        AcceptEditPredictionBinding(
 2162            window
 2163                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2164                .into_iter()
 2165                .filter(|binding| {
 2166                    !in_conflict
 2167                        || binding
 2168                            .keystrokes()
 2169                            .first()
 2170                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2171                })
 2172                .rev()
 2173                .min_by_key(|binding| {
 2174                    binding
 2175                        .keystrokes()
 2176                        .first()
 2177                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2178                }),
 2179        )
 2180    }
 2181
 2182    pub fn new_file(
 2183        workspace: &mut Workspace,
 2184        _: &workspace::NewFile,
 2185        window: &mut Window,
 2186        cx: &mut Context<Workspace>,
 2187    ) {
 2188        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2189            "Failed to create buffer",
 2190            window,
 2191            cx,
 2192            |e, _, _| match e.error_code() {
 2193                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2194                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2195                e.error_tag("required").unwrap_or("the latest version")
 2196            )),
 2197                _ => None,
 2198            },
 2199        );
 2200    }
 2201
 2202    pub fn new_in_workspace(
 2203        workspace: &mut Workspace,
 2204        window: &mut Window,
 2205        cx: &mut Context<Workspace>,
 2206    ) -> Task<Result<Entity<Editor>>> {
 2207        let project = workspace.project().clone();
 2208        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2209
 2210        cx.spawn_in(window, async move |workspace, cx| {
 2211            let buffer = create.await?;
 2212            workspace.update_in(cx, |workspace, window, cx| {
 2213                let editor =
 2214                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2215                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2216                editor
 2217            })
 2218        })
 2219    }
 2220
 2221    fn new_file_vertical(
 2222        workspace: &mut Workspace,
 2223        _: &workspace::NewFileSplitVertical,
 2224        window: &mut Window,
 2225        cx: &mut Context<Workspace>,
 2226    ) {
 2227        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2228    }
 2229
 2230    fn new_file_horizontal(
 2231        workspace: &mut Workspace,
 2232        _: &workspace::NewFileSplitHorizontal,
 2233        window: &mut Window,
 2234        cx: &mut Context<Workspace>,
 2235    ) {
 2236        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2237    }
 2238
 2239    fn new_file_in_direction(
 2240        workspace: &mut Workspace,
 2241        direction: SplitDirection,
 2242        window: &mut Window,
 2243        cx: &mut Context<Workspace>,
 2244    ) {
 2245        let project = workspace.project().clone();
 2246        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2247
 2248        cx.spawn_in(window, async move |workspace, cx| {
 2249            let buffer = create.await?;
 2250            workspace.update_in(cx, move |workspace, window, cx| {
 2251                workspace.split_item(
 2252                    direction,
 2253                    Box::new(
 2254                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2255                    ),
 2256                    window,
 2257                    cx,
 2258                )
 2259            })?;
 2260            anyhow::Ok(())
 2261        })
 2262        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2263            match e.error_code() {
 2264                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2265                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2266                e.error_tag("required").unwrap_or("the latest version")
 2267            )),
 2268                _ => None,
 2269            }
 2270        });
 2271    }
 2272
 2273    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2274        self.leader_id
 2275    }
 2276
 2277    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2278        &self.buffer
 2279    }
 2280
 2281    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2282        self.workspace.as_ref()?.0.upgrade()
 2283    }
 2284
 2285    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2286        self.buffer().read(cx).title(cx)
 2287    }
 2288
 2289    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2290        let git_blame_gutter_max_author_length = self
 2291            .render_git_blame_gutter(cx)
 2292            .then(|| {
 2293                if let Some(blame) = self.blame.as_ref() {
 2294                    let max_author_length =
 2295                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2296                    Some(max_author_length)
 2297                } else {
 2298                    None
 2299                }
 2300            })
 2301            .flatten();
 2302
 2303        EditorSnapshot {
 2304            mode: self.mode.clone(),
 2305            show_gutter: self.show_gutter,
 2306            show_line_numbers: self.show_line_numbers,
 2307            show_git_diff_gutter: self.show_git_diff_gutter,
 2308            show_runnables: self.show_runnables,
 2309            show_breakpoints: self.show_breakpoints,
 2310            git_blame_gutter_max_author_length,
 2311            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2312            scroll_anchor: self.scroll_manager.anchor(),
 2313            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2314            placeholder_text: self.placeholder_text.clone(),
 2315            is_focused: self.focus_handle.is_focused(window),
 2316            current_line_highlight: self
 2317                .current_line_highlight
 2318                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2319            gutter_hovered: self.gutter_hovered,
 2320        }
 2321    }
 2322
 2323    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2324        self.buffer.read(cx).language_at(point, cx)
 2325    }
 2326
 2327    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2328        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2329    }
 2330
 2331    pub fn active_excerpt(
 2332        &self,
 2333        cx: &App,
 2334    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2335        self.buffer
 2336            .read(cx)
 2337            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2338    }
 2339
 2340    pub fn mode(&self) -> &EditorMode {
 2341        &self.mode
 2342    }
 2343
 2344    pub fn set_mode(&mut self, mode: EditorMode) {
 2345        self.mode = mode;
 2346    }
 2347
 2348    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2349        self.collaboration_hub.as_deref()
 2350    }
 2351
 2352    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2353        self.collaboration_hub = Some(hub);
 2354    }
 2355
 2356    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2357        self.in_project_search = in_project_search;
 2358    }
 2359
 2360    pub fn set_custom_context_menu(
 2361        &mut self,
 2362        f: impl 'static
 2363        + Fn(
 2364            &mut Self,
 2365            DisplayPoint,
 2366            &mut Window,
 2367            &mut Context<Self>,
 2368        ) -> Option<Entity<ui::ContextMenu>>,
 2369    ) {
 2370        self.custom_context_menu = Some(Box::new(f))
 2371    }
 2372
 2373    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2374        self.completion_provider = provider;
 2375    }
 2376
 2377    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2378        self.semantics_provider.clone()
 2379    }
 2380
 2381    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2382        self.semantics_provider = provider;
 2383    }
 2384
 2385    pub fn set_edit_prediction_provider<T>(
 2386        &mut self,
 2387        provider: Option<Entity<T>>,
 2388        window: &mut Window,
 2389        cx: &mut Context<Self>,
 2390    ) where
 2391        T: EditPredictionProvider,
 2392    {
 2393        self.edit_prediction_provider =
 2394            provider.map(|provider| RegisteredInlineCompletionProvider {
 2395                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2396                    if this.focus_handle.is_focused(window) {
 2397                        this.update_visible_inline_completion(window, cx);
 2398                    }
 2399                }),
 2400                provider: Arc::new(provider),
 2401            });
 2402        self.update_edit_prediction_settings(cx);
 2403        self.refresh_inline_completion(false, false, window, cx);
 2404    }
 2405
 2406    pub fn placeholder_text(&self) -> Option<&str> {
 2407        self.placeholder_text.as_deref()
 2408    }
 2409
 2410    pub fn set_placeholder_text(
 2411        &mut self,
 2412        placeholder_text: impl Into<Arc<str>>,
 2413        cx: &mut Context<Self>,
 2414    ) {
 2415        let placeholder_text = Some(placeholder_text.into());
 2416        if self.placeholder_text != placeholder_text {
 2417            self.placeholder_text = placeholder_text;
 2418            cx.notify();
 2419        }
 2420    }
 2421
 2422    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2423        self.cursor_shape = cursor_shape;
 2424
 2425        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2426        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2427
 2428        cx.notify();
 2429    }
 2430
 2431    pub fn set_current_line_highlight(
 2432        &mut self,
 2433        current_line_highlight: Option<CurrentLineHighlight>,
 2434    ) {
 2435        self.current_line_highlight = current_line_highlight;
 2436    }
 2437
 2438    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2439        self.collapse_matches = collapse_matches;
 2440    }
 2441
 2442    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2443        let buffers = self.buffer.read(cx).all_buffers();
 2444        let Some(project) = self.project.as_ref() else {
 2445            return;
 2446        };
 2447        project.update(cx, |project, cx| {
 2448            for buffer in buffers {
 2449                self.registered_buffers
 2450                    .entry(buffer.read(cx).remote_id())
 2451                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2452            }
 2453        })
 2454    }
 2455
 2456    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2457        if self.collapse_matches {
 2458            return range.start..range.start;
 2459        }
 2460        range.clone()
 2461    }
 2462
 2463    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2464        if self.display_map.read(cx).clip_at_line_ends != clip {
 2465            self.display_map
 2466                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2467        }
 2468    }
 2469
 2470    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2471        self.input_enabled = input_enabled;
 2472    }
 2473
 2474    pub fn set_inline_completions_hidden_for_vim_mode(
 2475        &mut self,
 2476        hidden: bool,
 2477        window: &mut Window,
 2478        cx: &mut Context<Self>,
 2479    ) {
 2480        if hidden != self.inline_completions_hidden_for_vim_mode {
 2481            self.inline_completions_hidden_for_vim_mode = hidden;
 2482            if hidden {
 2483                self.update_visible_inline_completion(window, cx);
 2484            } else {
 2485                self.refresh_inline_completion(true, false, window, cx);
 2486            }
 2487        }
 2488    }
 2489
 2490    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2491        self.menu_inline_completions_policy = value;
 2492    }
 2493
 2494    pub fn set_autoindent(&mut self, autoindent: bool) {
 2495        if autoindent {
 2496            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2497        } else {
 2498            self.autoindent_mode = None;
 2499        }
 2500    }
 2501
 2502    pub fn read_only(&self, cx: &App) -> bool {
 2503        self.read_only || self.buffer.read(cx).read_only()
 2504    }
 2505
 2506    pub fn set_read_only(&mut self, read_only: bool) {
 2507        self.read_only = read_only;
 2508    }
 2509
 2510    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2511        self.use_autoclose = autoclose;
 2512    }
 2513
 2514    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2515        self.use_auto_surround = auto_surround;
 2516    }
 2517
 2518    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2519        self.auto_replace_emoji_shortcode = auto_replace;
 2520    }
 2521
 2522    pub fn toggle_edit_predictions(
 2523        &mut self,
 2524        _: &ToggleEditPrediction,
 2525        window: &mut Window,
 2526        cx: &mut Context<Self>,
 2527    ) {
 2528        if self.show_inline_completions_override.is_some() {
 2529            self.set_show_edit_predictions(None, window, cx);
 2530        } else {
 2531            let show_edit_predictions = !self.edit_predictions_enabled();
 2532            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2533        }
 2534    }
 2535
 2536    pub fn set_show_edit_predictions(
 2537        &mut self,
 2538        show_edit_predictions: Option<bool>,
 2539        window: &mut Window,
 2540        cx: &mut Context<Self>,
 2541    ) {
 2542        self.show_inline_completions_override = show_edit_predictions;
 2543        self.update_edit_prediction_settings(cx);
 2544
 2545        if let Some(false) = show_edit_predictions {
 2546            self.discard_inline_completion(false, cx);
 2547        } else {
 2548            self.refresh_inline_completion(false, true, window, cx);
 2549        }
 2550    }
 2551
 2552    fn inline_completions_disabled_in_scope(
 2553        &self,
 2554        buffer: &Entity<Buffer>,
 2555        buffer_position: language::Anchor,
 2556        cx: &App,
 2557    ) -> bool {
 2558        let snapshot = buffer.read(cx).snapshot();
 2559        let settings = snapshot.settings_at(buffer_position, cx);
 2560
 2561        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2562            return false;
 2563        };
 2564
 2565        scope.override_name().map_or(false, |scope_name| {
 2566            settings
 2567                .edit_predictions_disabled_in
 2568                .iter()
 2569                .any(|s| s == scope_name)
 2570        })
 2571    }
 2572
 2573    pub fn set_use_modal_editing(&mut self, to: bool) {
 2574        self.use_modal_editing = to;
 2575    }
 2576
 2577    pub fn use_modal_editing(&self) -> bool {
 2578        self.use_modal_editing
 2579    }
 2580
 2581    fn selections_did_change(
 2582        &mut self,
 2583        local: bool,
 2584        old_cursor_position: &Anchor,
 2585        show_completions: bool,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        window.invalidate_character_coordinates();
 2590
 2591        // Copy selections to primary selection buffer
 2592        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2593        if local {
 2594            let selections = self.selections.all::<usize>(cx);
 2595            let buffer_handle = self.buffer.read(cx).read(cx);
 2596
 2597            let mut text = String::new();
 2598            for (index, selection) in selections.iter().enumerate() {
 2599                let text_for_selection = buffer_handle
 2600                    .text_for_range(selection.start..selection.end)
 2601                    .collect::<String>();
 2602
 2603                text.push_str(&text_for_selection);
 2604                if index != selections.len() - 1 {
 2605                    text.push('\n');
 2606                }
 2607            }
 2608
 2609            if !text.is_empty() {
 2610                cx.write_to_primary(ClipboardItem::new_string(text));
 2611            }
 2612        }
 2613
 2614        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2615            self.buffer.update(cx, |buffer, cx| {
 2616                buffer.set_active_selections(
 2617                    &self.selections.disjoint_anchors(),
 2618                    self.selections.line_mode,
 2619                    self.cursor_shape,
 2620                    cx,
 2621                )
 2622            });
 2623        }
 2624        let display_map = self
 2625            .display_map
 2626            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2627        let buffer = &display_map.buffer_snapshot;
 2628        self.add_selections_state = None;
 2629        self.select_next_state = None;
 2630        self.select_prev_state = None;
 2631        self.select_syntax_node_history.try_clear();
 2632        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2633        self.snippet_stack
 2634            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2635        self.take_rename(false, window, cx);
 2636
 2637        let new_cursor_position = self.selections.newest_anchor().head();
 2638
 2639        self.push_to_nav_history(
 2640            *old_cursor_position,
 2641            Some(new_cursor_position.to_point(buffer)),
 2642            false,
 2643            cx,
 2644        );
 2645
 2646        if local {
 2647            let new_cursor_position = self.selections.newest_anchor().head();
 2648            let mut context_menu = self.context_menu.borrow_mut();
 2649            let completion_menu = match context_menu.as_ref() {
 2650                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2651                _ => {
 2652                    *context_menu = None;
 2653                    None
 2654                }
 2655            };
 2656            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2657                if !self.registered_buffers.contains_key(&buffer_id) {
 2658                    if let Some(project) = self.project.as_ref() {
 2659                        project.update(cx, |project, cx| {
 2660                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2661                                return;
 2662                            };
 2663                            self.registered_buffers.insert(
 2664                                buffer_id,
 2665                                project.register_buffer_with_language_servers(&buffer, cx),
 2666                            );
 2667                        })
 2668                    }
 2669                }
 2670            }
 2671
 2672            if let Some(completion_menu) = completion_menu {
 2673                let cursor_position = new_cursor_position.to_offset(buffer);
 2674                let (word_range, kind) =
 2675                    buffer.surrounding_word(completion_menu.initial_position, true);
 2676                if kind == Some(CharKind::Word)
 2677                    && word_range.to_inclusive().contains(&cursor_position)
 2678                {
 2679                    let mut completion_menu = completion_menu.clone();
 2680                    drop(context_menu);
 2681
 2682                    let query = Self::completion_query(buffer, cursor_position);
 2683                    cx.spawn(async move |this, cx| {
 2684                        completion_menu
 2685                            .filter(query.as_deref(), cx.background_executor().clone())
 2686                            .await;
 2687
 2688                        this.update(cx, |this, cx| {
 2689                            let mut context_menu = this.context_menu.borrow_mut();
 2690                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2691                            else {
 2692                                return;
 2693                            };
 2694
 2695                            if menu.id > completion_menu.id {
 2696                                return;
 2697                            }
 2698
 2699                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2700                            drop(context_menu);
 2701                            cx.notify();
 2702                        })
 2703                    })
 2704                    .detach();
 2705
 2706                    if show_completions {
 2707                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2708                    }
 2709                } else {
 2710                    drop(context_menu);
 2711                    self.hide_context_menu(window, cx);
 2712                }
 2713            } else {
 2714                drop(context_menu);
 2715            }
 2716
 2717            hide_hover(self, cx);
 2718
 2719            if old_cursor_position.to_display_point(&display_map).row()
 2720                != new_cursor_position.to_display_point(&display_map).row()
 2721            {
 2722                self.available_code_actions.take();
 2723            }
 2724            self.refresh_code_actions(window, cx);
 2725            self.refresh_document_highlights(cx);
 2726            self.refresh_selected_text_highlights(false, window, cx);
 2727            refresh_matching_bracket_highlights(self, window, cx);
 2728            self.update_visible_inline_completion(window, cx);
 2729            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2730            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2731            self.inline_blame_popover.take();
 2732            if self.git_blame_inline_enabled {
 2733                self.start_inline_blame_timer(window, cx);
 2734            }
 2735        }
 2736
 2737        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2738        cx.emit(EditorEvent::SelectionsChanged { local });
 2739
 2740        let selections = &self.selections.disjoint;
 2741        if selections.len() == 1 {
 2742            cx.emit(SearchEvent::ActiveMatchChanged)
 2743        }
 2744        if local {
 2745            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2746                let inmemory_selections = selections
 2747                    .iter()
 2748                    .map(|s| {
 2749                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2750                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2751                    })
 2752                    .collect();
 2753                self.update_restoration_data(cx, |data| {
 2754                    data.selections = inmemory_selections;
 2755                });
 2756
 2757                if WorkspaceSettings::get(None, cx).restore_on_startup
 2758                    != RestoreOnStartupBehavior::None
 2759                {
 2760                    if let Some(workspace_id) =
 2761                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2762                    {
 2763                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2764                        let selections = selections.clone();
 2765                        let background_executor = cx.background_executor().clone();
 2766                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2767                        self.serialize_selections = cx.background_spawn(async move {
 2768                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2769                    let db_selections = selections
 2770                        .iter()
 2771                        .map(|selection| {
 2772                            (
 2773                                selection.start.to_offset(&snapshot),
 2774                                selection.end.to_offset(&snapshot),
 2775                            )
 2776                        })
 2777                        .collect();
 2778
 2779                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2780                        .await
 2781                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2782                        .log_err();
 2783                });
 2784                    }
 2785                }
 2786            }
 2787        }
 2788
 2789        cx.notify();
 2790    }
 2791
 2792    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2793        use text::ToOffset as _;
 2794        use text::ToPoint as _;
 2795
 2796        if self.mode.is_minimap()
 2797            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2798        {
 2799            return;
 2800        }
 2801
 2802        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2803            return;
 2804        };
 2805
 2806        let snapshot = singleton.read(cx).snapshot();
 2807        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2808            let display_snapshot = display_map.snapshot(cx);
 2809
 2810            display_snapshot
 2811                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2812                .map(|fold| {
 2813                    fold.range.start.text_anchor.to_point(&snapshot)
 2814                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2815                })
 2816                .collect()
 2817        });
 2818        self.update_restoration_data(cx, |data| {
 2819            data.folds = inmemory_folds;
 2820        });
 2821
 2822        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2823            return;
 2824        };
 2825        let background_executor = cx.background_executor().clone();
 2826        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2827        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2828            display_map
 2829                .snapshot(cx)
 2830                .folds_in_range(0..snapshot.len())
 2831                .map(|fold| {
 2832                    (
 2833                        fold.range.start.text_anchor.to_offset(&snapshot),
 2834                        fold.range.end.text_anchor.to_offset(&snapshot),
 2835                    )
 2836                })
 2837                .collect()
 2838        });
 2839        self.serialize_folds = cx.background_spawn(async move {
 2840            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2841            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2842                .await
 2843                .with_context(|| {
 2844                    format!(
 2845                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2846                    )
 2847                })
 2848                .log_err();
 2849        });
 2850    }
 2851
 2852    pub fn sync_selections(
 2853        &mut self,
 2854        other: Entity<Editor>,
 2855        cx: &mut Context<Self>,
 2856    ) -> gpui::Subscription {
 2857        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2858        self.selections.change_with(cx, |selections| {
 2859            selections.select_anchors(other_selections);
 2860        });
 2861
 2862        let other_subscription =
 2863            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2864                EditorEvent::SelectionsChanged { local: true } => {
 2865                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2866                    if other_selections.is_empty() {
 2867                        return;
 2868                    }
 2869                    this.selections.change_with(cx, |selections| {
 2870                        selections.select_anchors(other_selections);
 2871                    });
 2872                }
 2873                _ => {}
 2874            });
 2875
 2876        let this_subscription =
 2877            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2878                EditorEvent::SelectionsChanged { local: true } => {
 2879                    let these_selections = this.selections.disjoint.to_vec();
 2880                    if these_selections.is_empty() {
 2881                        return;
 2882                    }
 2883                    other.update(cx, |other_editor, cx| {
 2884                        other_editor.selections.change_with(cx, |selections| {
 2885                            selections.select_anchors(these_selections);
 2886                        })
 2887                    });
 2888                }
 2889                _ => {}
 2890            });
 2891
 2892        Subscription::join(other_subscription, this_subscription)
 2893    }
 2894
 2895    pub fn change_selections<R>(
 2896        &mut self,
 2897        autoscroll: Option<Autoscroll>,
 2898        window: &mut Window,
 2899        cx: &mut Context<Self>,
 2900        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2901    ) -> R {
 2902        self.change_selections_inner(autoscroll, true, window, cx, change)
 2903    }
 2904
 2905    fn change_selections_inner<R>(
 2906        &mut self,
 2907        autoscroll: Option<Autoscroll>,
 2908        request_completions: bool,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2912    ) -> R {
 2913        let old_cursor_position = self.selections.newest_anchor().head();
 2914        self.push_to_selection_history();
 2915
 2916        let (changed, result) = self.selections.change_with(cx, change);
 2917
 2918        if changed {
 2919            if let Some(autoscroll) = autoscroll {
 2920                self.request_autoscroll(autoscroll, cx);
 2921            }
 2922            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2923
 2924            if self.should_open_signature_help_automatically(
 2925                &old_cursor_position,
 2926                self.signature_help_state.backspace_pressed(),
 2927                cx,
 2928            ) {
 2929                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2930            }
 2931            self.signature_help_state.set_backspace_pressed(false);
 2932        }
 2933
 2934        result
 2935    }
 2936
 2937    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2938    where
 2939        I: IntoIterator<Item = (Range<S>, T)>,
 2940        S: ToOffset,
 2941        T: Into<Arc<str>>,
 2942    {
 2943        if self.read_only(cx) {
 2944            return;
 2945        }
 2946
 2947        self.buffer
 2948            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2949    }
 2950
 2951    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2952    where
 2953        I: IntoIterator<Item = (Range<S>, T)>,
 2954        S: ToOffset,
 2955        T: Into<Arc<str>>,
 2956    {
 2957        if self.read_only(cx) {
 2958            return;
 2959        }
 2960
 2961        self.buffer.update(cx, |buffer, cx| {
 2962            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2963        });
 2964    }
 2965
 2966    pub fn edit_with_block_indent<I, S, T>(
 2967        &mut self,
 2968        edits: I,
 2969        original_indent_columns: Vec<Option<u32>>,
 2970        cx: &mut Context<Self>,
 2971    ) where
 2972        I: IntoIterator<Item = (Range<S>, T)>,
 2973        S: ToOffset,
 2974        T: Into<Arc<str>>,
 2975    {
 2976        if self.read_only(cx) {
 2977            return;
 2978        }
 2979
 2980        self.buffer.update(cx, |buffer, cx| {
 2981            buffer.edit(
 2982                edits,
 2983                Some(AutoindentMode::Block {
 2984                    original_indent_columns,
 2985                }),
 2986                cx,
 2987            )
 2988        });
 2989    }
 2990
 2991    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2992        self.hide_context_menu(window, cx);
 2993
 2994        match phase {
 2995            SelectPhase::Begin {
 2996                position,
 2997                add,
 2998                click_count,
 2999            } => self.begin_selection(position, add, click_count, window, cx),
 3000            SelectPhase::BeginColumnar {
 3001                position,
 3002                goal_column,
 3003                reset,
 3004            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3005            SelectPhase::Extend {
 3006                position,
 3007                click_count,
 3008            } => self.extend_selection(position, click_count, window, cx),
 3009            SelectPhase::Update {
 3010                position,
 3011                goal_column,
 3012                scroll_delta,
 3013            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3014            SelectPhase::End => self.end_selection(window, cx),
 3015        }
 3016    }
 3017
 3018    fn extend_selection(
 3019        &mut self,
 3020        position: DisplayPoint,
 3021        click_count: usize,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024    ) {
 3025        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3026        let tail = self.selections.newest::<usize>(cx).tail();
 3027        self.begin_selection(position, false, click_count, window, cx);
 3028
 3029        let position = position.to_offset(&display_map, Bias::Left);
 3030        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3031
 3032        let mut pending_selection = self
 3033            .selections
 3034            .pending_anchor()
 3035            .expect("extend_selection not called with pending selection");
 3036        if position >= tail {
 3037            pending_selection.start = tail_anchor;
 3038        } else {
 3039            pending_selection.end = tail_anchor;
 3040            pending_selection.reversed = true;
 3041        }
 3042
 3043        let mut pending_mode = self.selections.pending_mode().unwrap();
 3044        match &mut pending_mode {
 3045            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3046            _ => {}
 3047        }
 3048
 3049        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3050
 3051        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3052            s.set_pending(pending_selection, pending_mode)
 3053        });
 3054    }
 3055
 3056    fn begin_selection(
 3057        &mut self,
 3058        position: DisplayPoint,
 3059        add: bool,
 3060        click_count: usize,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063    ) {
 3064        if !self.focus_handle.is_focused(window) {
 3065            self.last_focused_descendant = None;
 3066            window.focus(&self.focus_handle);
 3067        }
 3068
 3069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3070        let buffer = &display_map.buffer_snapshot;
 3071        let position = display_map.clip_point(position, Bias::Left);
 3072
 3073        let start;
 3074        let end;
 3075        let mode;
 3076        let mut auto_scroll;
 3077        match click_count {
 3078            1 => {
 3079                start = buffer.anchor_before(position.to_point(&display_map));
 3080                end = start;
 3081                mode = SelectMode::Character;
 3082                auto_scroll = true;
 3083            }
 3084            2 => {
 3085                let range = movement::surrounding_word(&display_map, position);
 3086                start = buffer.anchor_before(range.start.to_point(&display_map));
 3087                end = buffer.anchor_before(range.end.to_point(&display_map));
 3088                mode = SelectMode::Word(start..end);
 3089                auto_scroll = true;
 3090            }
 3091            3 => {
 3092                let position = display_map
 3093                    .clip_point(position, Bias::Left)
 3094                    .to_point(&display_map);
 3095                let line_start = display_map.prev_line_boundary(position).0;
 3096                let next_line_start = buffer.clip_point(
 3097                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3098                    Bias::Left,
 3099                );
 3100                start = buffer.anchor_before(line_start);
 3101                end = buffer.anchor_before(next_line_start);
 3102                mode = SelectMode::Line(start..end);
 3103                auto_scroll = true;
 3104            }
 3105            _ => {
 3106                start = buffer.anchor_before(0);
 3107                end = buffer.anchor_before(buffer.len());
 3108                mode = SelectMode::All;
 3109                auto_scroll = false;
 3110            }
 3111        }
 3112        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3113
 3114        let point_to_delete: Option<usize> = {
 3115            let selected_points: Vec<Selection<Point>> =
 3116                self.selections.disjoint_in_range(start..end, cx);
 3117
 3118            if !add || click_count > 1 {
 3119                None
 3120            } else if !selected_points.is_empty() {
 3121                Some(selected_points[0].id)
 3122            } else {
 3123                let clicked_point_already_selected =
 3124                    self.selections.disjoint.iter().find(|selection| {
 3125                        selection.start.to_point(buffer) == start.to_point(buffer)
 3126                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3127                    });
 3128
 3129                clicked_point_already_selected.map(|selection| selection.id)
 3130            }
 3131        };
 3132
 3133        let selections_count = self.selections.count();
 3134
 3135        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3136            if let Some(point_to_delete) = point_to_delete {
 3137                s.delete(point_to_delete);
 3138
 3139                if selections_count == 1 {
 3140                    s.set_pending_anchor_range(start..end, mode);
 3141                }
 3142            } else {
 3143                if !add {
 3144                    s.clear_disjoint();
 3145                }
 3146
 3147                s.set_pending_anchor_range(start..end, mode);
 3148            }
 3149        });
 3150    }
 3151
 3152    fn begin_columnar_selection(
 3153        &mut self,
 3154        position: DisplayPoint,
 3155        goal_column: u32,
 3156        reset: bool,
 3157        window: &mut Window,
 3158        cx: &mut Context<Self>,
 3159    ) {
 3160        if !self.focus_handle.is_focused(window) {
 3161            self.last_focused_descendant = None;
 3162            window.focus(&self.focus_handle);
 3163        }
 3164
 3165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3166
 3167        if reset {
 3168            let pointer_position = display_map
 3169                .buffer_snapshot
 3170                .anchor_before(position.to_point(&display_map));
 3171
 3172            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3173                s.clear_disjoint();
 3174                s.set_pending_anchor_range(
 3175                    pointer_position..pointer_position,
 3176                    SelectMode::Character,
 3177                );
 3178            });
 3179        }
 3180
 3181        let tail = self.selections.newest::<Point>(cx).tail();
 3182        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3183
 3184        if !reset {
 3185            self.select_columns(
 3186                tail.to_display_point(&display_map),
 3187                position,
 3188                goal_column,
 3189                &display_map,
 3190                window,
 3191                cx,
 3192            );
 3193        }
 3194    }
 3195
 3196    fn update_selection(
 3197        &mut self,
 3198        position: DisplayPoint,
 3199        goal_column: u32,
 3200        scroll_delta: gpui::Point<f32>,
 3201        window: &mut Window,
 3202        cx: &mut Context<Self>,
 3203    ) {
 3204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3205
 3206        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3207            let tail = tail.to_display_point(&display_map);
 3208            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3209        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3210            let buffer = self.buffer.read(cx).snapshot(cx);
 3211            let head;
 3212            let tail;
 3213            let mode = self.selections.pending_mode().unwrap();
 3214            match &mode {
 3215                SelectMode::Character => {
 3216                    head = position.to_point(&display_map);
 3217                    tail = pending.tail().to_point(&buffer);
 3218                }
 3219                SelectMode::Word(original_range) => {
 3220                    let original_display_range = original_range.start.to_display_point(&display_map)
 3221                        ..original_range.end.to_display_point(&display_map);
 3222                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3223                        ..original_display_range.end.to_point(&display_map);
 3224                    if movement::is_inside_word(&display_map, position)
 3225                        || original_display_range.contains(&position)
 3226                    {
 3227                        let word_range = movement::surrounding_word(&display_map, position);
 3228                        if word_range.start < original_display_range.start {
 3229                            head = word_range.start.to_point(&display_map);
 3230                        } else {
 3231                            head = word_range.end.to_point(&display_map);
 3232                        }
 3233                    } else {
 3234                        head = position.to_point(&display_map);
 3235                    }
 3236
 3237                    if head <= original_buffer_range.start {
 3238                        tail = original_buffer_range.end;
 3239                    } else {
 3240                        tail = original_buffer_range.start;
 3241                    }
 3242                }
 3243                SelectMode::Line(original_range) => {
 3244                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3245
 3246                    let position = display_map
 3247                        .clip_point(position, Bias::Left)
 3248                        .to_point(&display_map);
 3249                    let line_start = display_map.prev_line_boundary(position).0;
 3250                    let next_line_start = buffer.clip_point(
 3251                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3252                        Bias::Left,
 3253                    );
 3254
 3255                    if line_start < original_range.start {
 3256                        head = line_start
 3257                    } else {
 3258                        head = next_line_start
 3259                    }
 3260
 3261                    if head <= original_range.start {
 3262                        tail = original_range.end;
 3263                    } else {
 3264                        tail = original_range.start;
 3265                    }
 3266                }
 3267                SelectMode::All => {
 3268                    return;
 3269                }
 3270            };
 3271
 3272            if head < tail {
 3273                pending.start = buffer.anchor_before(head);
 3274                pending.end = buffer.anchor_before(tail);
 3275                pending.reversed = true;
 3276            } else {
 3277                pending.start = buffer.anchor_before(tail);
 3278                pending.end = buffer.anchor_before(head);
 3279                pending.reversed = false;
 3280            }
 3281
 3282            self.change_selections(None, window, cx, |s| {
 3283                s.set_pending(pending, mode);
 3284            });
 3285        } else {
 3286            log::error!("update_selection dispatched with no pending selection");
 3287            return;
 3288        }
 3289
 3290        self.apply_scroll_delta(scroll_delta, window, cx);
 3291        cx.notify();
 3292    }
 3293
 3294    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3295        self.columnar_selection_tail.take();
 3296        if self.selections.pending_anchor().is_some() {
 3297            let selections = self.selections.all::<usize>(cx);
 3298            self.change_selections(None, window, cx, |s| {
 3299                s.select(selections);
 3300                s.clear_pending();
 3301            });
 3302        }
 3303    }
 3304
 3305    fn select_columns(
 3306        &mut self,
 3307        tail: DisplayPoint,
 3308        head: DisplayPoint,
 3309        goal_column: u32,
 3310        display_map: &DisplaySnapshot,
 3311        window: &mut Window,
 3312        cx: &mut Context<Self>,
 3313    ) {
 3314        let start_row = cmp::min(tail.row(), head.row());
 3315        let end_row = cmp::max(tail.row(), head.row());
 3316        let start_column = cmp::min(tail.column(), goal_column);
 3317        let end_column = cmp::max(tail.column(), goal_column);
 3318        let reversed = start_column < tail.column();
 3319
 3320        let selection_ranges = (start_row.0..=end_row.0)
 3321            .map(DisplayRow)
 3322            .filter_map(|row| {
 3323                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3324                    let start = display_map
 3325                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3326                        .to_point(display_map);
 3327                    let end = display_map
 3328                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3329                        .to_point(display_map);
 3330                    if reversed {
 3331                        Some(end..start)
 3332                    } else {
 3333                        Some(start..end)
 3334                    }
 3335                } else {
 3336                    None
 3337                }
 3338            })
 3339            .collect::<Vec<_>>();
 3340
 3341        self.change_selections(None, window, cx, |s| {
 3342            s.select_ranges(selection_ranges);
 3343        });
 3344        cx.notify();
 3345    }
 3346
 3347    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3348        self.selections
 3349            .all_adjusted(cx)
 3350            .iter()
 3351            .any(|selection| !selection.is_empty())
 3352    }
 3353
 3354    pub fn has_pending_nonempty_selection(&self) -> bool {
 3355        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3356            Some(Selection { start, end, .. }) => start != end,
 3357            None => false,
 3358        };
 3359
 3360        pending_nonempty_selection
 3361            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3362    }
 3363
 3364    pub fn has_pending_selection(&self) -> bool {
 3365        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3366    }
 3367
 3368    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3369        self.selection_mark_mode = false;
 3370
 3371        if self.clear_expanded_diff_hunks(cx) {
 3372            cx.notify();
 3373            return;
 3374        }
 3375        if self.dismiss_menus_and_popups(true, window, cx) {
 3376            return;
 3377        }
 3378
 3379        if self.mode.is_full()
 3380            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3381        {
 3382            return;
 3383        }
 3384
 3385        cx.propagate();
 3386    }
 3387
 3388    pub fn dismiss_menus_and_popups(
 3389        &mut self,
 3390        is_user_requested: bool,
 3391        window: &mut Window,
 3392        cx: &mut Context<Self>,
 3393    ) -> bool {
 3394        if self.take_rename(false, window, cx).is_some() {
 3395            return true;
 3396        }
 3397
 3398        if hide_hover(self, cx) {
 3399            return true;
 3400        }
 3401
 3402        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3403            return true;
 3404        }
 3405
 3406        if self.hide_context_menu(window, cx).is_some() {
 3407            return true;
 3408        }
 3409
 3410        if self.mouse_context_menu.take().is_some() {
 3411            return true;
 3412        }
 3413
 3414        if is_user_requested && self.discard_inline_completion(true, cx) {
 3415            return true;
 3416        }
 3417
 3418        if self.snippet_stack.pop().is_some() {
 3419            return true;
 3420        }
 3421
 3422        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3423            self.dismiss_diagnostics(cx);
 3424            return true;
 3425        }
 3426
 3427        false
 3428    }
 3429
 3430    fn linked_editing_ranges_for(
 3431        &self,
 3432        selection: Range<text::Anchor>,
 3433        cx: &App,
 3434    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3435        if self.linked_edit_ranges.is_empty() {
 3436            return None;
 3437        }
 3438        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3439            selection.end.buffer_id.and_then(|end_buffer_id| {
 3440                if selection.start.buffer_id != Some(end_buffer_id) {
 3441                    return None;
 3442                }
 3443                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3444                let snapshot = buffer.read(cx).snapshot();
 3445                self.linked_edit_ranges
 3446                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3447                    .map(|ranges| (ranges, snapshot, buffer))
 3448            })?;
 3449        use text::ToOffset as TO;
 3450        // find offset from the start of current range to current cursor position
 3451        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3452
 3453        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3454        let start_difference = start_offset - start_byte_offset;
 3455        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3456        let end_difference = end_offset - start_byte_offset;
 3457        // Current range has associated linked ranges.
 3458        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3459        for range in linked_ranges.iter() {
 3460            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3461            let end_offset = start_offset + end_difference;
 3462            let start_offset = start_offset + start_difference;
 3463            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3464                continue;
 3465            }
 3466            if self.selections.disjoint_anchor_ranges().any(|s| {
 3467                if s.start.buffer_id != selection.start.buffer_id
 3468                    || s.end.buffer_id != selection.end.buffer_id
 3469                {
 3470                    return false;
 3471                }
 3472                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3473                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3474            }) {
 3475                continue;
 3476            }
 3477            let start = buffer_snapshot.anchor_after(start_offset);
 3478            let end = buffer_snapshot.anchor_after(end_offset);
 3479            linked_edits
 3480                .entry(buffer.clone())
 3481                .or_default()
 3482                .push(start..end);
 3483        }
 3484        Some(linked_edits)
 3485    }
 3486
 3487    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3488        let text: Arc<str> = text.into();
 3489
 3490        if self.read_only(cx) {
 3491            return;
 3492        }
 3493
 3494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3495
 3496        let selections = self.selections.all_adjusted(cx);
 3497        let mut bracket_inserted = false;
 3498        let mut edits = Vec::new();
 3499        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3500        let mut new_selections = Vec::with_capacity(selections.len());
 3501        let mut new_autoclose_regions = Vec::new();
 3502        let snapshot = self.buffer.read(cx).read(cx);
 3503        let mut clear_linked_edit_ranges = false;
 3504
 3505        for (selection, autoclose_region) in
 3506            self.selections_with_autoclose_regions(selections, &snapshot)
 3507        {
 3508            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3509                // Determine if the inserted text matches the opening or closing
 3510                // bracket of any of this language's bracket pairs.
 3511                let mut bracket_pair = None;
 3512                let mut is_bracket_pair_start = false;
 3513                let mut is_bracket_pair_end = false;
 3514                if !text.is_empty() {
 3515                    let mut bracket_pair_matching_end = None;
 3516                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3517                    //  and they are removing the character that triggered IME popup.
 3518                    for (pair, enabled) in scope.brackets() {
 3519                        if !pair.close && !pair.surround {
 3520                            continue;
 3521                        }
 3522
 3523                        if enabled && pair.start.ends_with(text.as_ref()) {
 3524                            let prefix_len = pair.start.len() - text.len();
 3525                            let preceding_text_matches_prefix = prefix_len == 0
 3526                                || (selection.start.column >= (prefix_len as u32)
 3527                                    && snapshot.contains_str_at(
 3528                                        Point::new(
 3529                                            selection.start.row,
 3530                                            selection.start.column - (prefix_len as u32),
 3531                                        ),
 3532                                        &pair.start[..prefix_len],
 3533                                    ));
 3534                            if preceding_text_matches_prefix {
 3535                                bracket_pair = Some(pair.clone());
 3536                                is_bracket_pair_start = true;
 3537                                break;
 3538                            }
 3539                        }
 3540                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3541                        {
 3542                            // take first bracket pair matching end, but don't break in case a later bracket
 3543                            // pair matches start
 3544                            bracket_pair_matching_end = Some(pair.clone());
 3545                        }
 3546                    }
 3547                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3548                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3549                        is_bracket_pair_end = true;
 3550                    }
 3551                }
 3552
 3553                if let Some(bracket_pair) = bracket_pair {
 3554                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3555                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3556                    let auto_surround =
 3557                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3558                    if selection.is_empty() {
 3559                        if is_bracket_pair_start {
 3560                            // If the inserted text is a suffix of an opening bracket and the
 3561                            // selection is preceded by the rest of the opening bracket, then
 3562                            // insert the closing bracket.
 3563                            let following_text_allows_autoclose = snapshot
 3564                                .chars_at(selection.start)
 3565                                .next()
 3566                                .map_or(true, |c| scope.should_autoclose_before(c));
 3567
 3568                            let preceding_text_allows_autoclose = selection.start.column == 0
 3569                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3570                                    true,
 3571                                    |c| {
 3572                                        bracket_pair.start != bracket_pair.end
 3573                                            || !snapshot
 3574                                                .char_classifier_at(selection.start)
 3575                                                .is_word(c)
 3576                                    },
 3577                                );
 3578
 3579                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3580                                && bracket_pair.start.len() == 1
 3581                            {
 3582                                let target = bracket_pair.start.chars().next().unwrap();
 3583                                let current_line_count = snapshot
 3584                                    .reversed_chars_at(selection.start)
 3585                                    .take_while(|&c| c != '\n')
 3586                                    .filter(|&c| c == target)
 3587                                    .count();
 3588                                current_line_count % 2 == 1
 3589                            } else {
 3590                                false
 3591                            };
 3592
 3593                            if autoclose
 3594                                && bracket_pair.close
 3595                                && following_text_allows_autoclose
 3596                                && preceding_text_allows_autoclose
 3597                                && !is_closing_quote
 3598                            {
 3599                                let anchor = snapshot.anchor_before(selection.end);
 3600                                new_selections.push((selection.map(|_| anchor), text.len()));
 3601                                new_autoclose_regions.push((
 3602                                    anchor,
 3603                                    text.len(),
 3604                                    selection.id,
 3605                                    bracket_pair.clone(),
 3606                                ));
 3607                                edits.push((
 3608                                    selection.range(),
 3609                                    format!("{}{}", text, bracket_pair.end).into(),
 3610                                ));
 3611                                bracket_inserted = true;
 3612                                continue;
 3613                            }
 3614                        }
 3615
 3616                        if let Some(region) = autoclose_region {
 3617                            // If the selection is followed by an auto-inserted closing bracket,
 3618                            // then don't insert that closing bracket again; just move the selection
 3619                            // past the closing bracket.
 3620                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3621                                && text.as_ref() == region.pair.end.as_str();
 3622                            if should_skip {
 3623                                let anchor = snapshot.anchor_after(selection.end);
 3624                                new_selections
 3625                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3626                                continue;
 3627                            }
 3628                        }
 3629
 3630                        let always_treat_brackets_as_autoclosed = snapshot
 3631                            .language_settings_at(selection.start, cx)
 3632                            .always_treat_brackets_as_autoclosed;
 3633                        if always_treat_brackets_as_autoclosed
 3634                            && is_bracket_pair_end
 3635                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3636                        {
 3637                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3638                            // and the inserted text is a closing bracket and the selection is followed
 3639                            // by the closing bracket then move the selection past the closing bracket.
 3640                            let anchor = snapshot.anchor_after(selection.end);
 3641                            new_selections.push((selection.map(|_| anchor), text.len()));
 3642                            continue;
 3643                        }
 3644                    }
 3645                    // If an opening bracket is 1 character long and is typed while
 3646                    // text is selected, then surround that text with the bracket pair.
 3647                    else if auto_surround
 3648                        && bracket_pair.surround
 3649                        && is_bracket_pair_start
 3650                        && bracket_pair.start.chars().count() == 1
 3651                    {
 3652                        edits.push((selection.start..selection.start, text.clone()));
 3653                        edits.push((
 3654                            selection.end..selection.end,
 3655                            bracket_pair.end.as_str().into(),
 3656                        ));
 3657                        bracket_inserted = true;
 3658                        new_selections.push((
 3659                            Selection {
 3660                                id: selection.id,
 3661                                start: snapshot.anchor_after(selection.start),
 3662                                end: snapshot.anchor_before(selection.end),
 3663                                reversed: selection.reversed,
 3664                                goal: selection.goal,
 3665                            },
 3666                            0,
 3667                        ));
 3668                        continue;
 3669                    }
 3670                }
 3671            }
 3672
 3673            if self.auto_replace_emoji_shortcode
 3674                && selection.is_empty()
 3675                && text.as_ref().ends_with(':')
 3676            {
 3677                if let Some(possible_emoji_short_code) =
 3678                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3679                {
 3680                    if !possible_emoji_short_code.is_empty() {
 3681                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3682                            let emoji_shortcode_start = Point::new(
 3683                                selection.start.row,
 3684                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3685                            );
 3686
 3687                            // Remove shortcode from buffer
 3688                            edits.push((
 3689                                emoji_shortcode_start..selection.start,
 3690                                "".to_string().into(),
 3691                            ));
 3692                            new_selections.push((
 3693                                Selection {
 3694                                    id: selection.id,
 3695                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3696                                    end: snapshot.anchor_before(selection.start),
 3697                                    reversed: selection.reversed,
 3698                                    goal: selection.goal,
 3699                                },
 3700                                0,
 3701                            ));
 3702
 3703                            // Insert emoji
 3704                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3705                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3706                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3707
 3708                            continue;
 3709                        }
 3710                    }
 3711                }
 3712            }
 3713
 3714            // If not handling any auto-close operation, then just replace the selected
 3715            // text with the given input and move the selection to the end of the
 3716            // newly inserted text.
 3717            let anchor = snapshot.anchor_after(selection.end);
 3718            if !self.linked_edit_ranges.is_empty() {
 3719                let start_anchor = snapshot.anchor_before(selection.start);
 3720
 3721                let is_word_char = text.chars().next().map_or(true, |char| {
 3722                    let classifier = snapshot
 3723                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3724                        .ignore_punctuation(true);
 3725                    classifier.is_word(char)
 3726                });
 3727
 3728                if is_word_char {
 3729                    if let Some(ranges) = self
 3730                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3731                    {
 3732                        for (buffer, edits) in ranges {
 3733                            linked_edits
 3734                                .entry(buffer.clone())
 3735                                .or_default()
 3736                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3737                        }
 3738                    }
 3739                } else {
 3740                    clear_linked_edit_ranges = true;
 3741                }
 3742            }
 3743
 3744            new_selections.push((selection.map(|_| anchor), 0));
 3745            edits.push((selection.start..selection.end, text.clone()));
 3746        }
 3747
 3748        drop(snapshot);
 3749
 3750        self.transact(window, cx, |this, window, cx| {
 3751            if clear_linked_edit_ranges {
 3752                this.linked_edit_ranges.clear();
 3753            }
 3754            let initial_buffer_versions =
 3755                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3756
 3757            this.buffer.update(cx, |buffer, cx| {
 3758                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3759            });
 3760            for (buffer, edits) in linked_edits {
 3761                buffer.update(cx, |buffer, cx| {
 3762                    let snapshot = buffer.snapshot();
 3763                    let edits = edits
 3764                        .into_iter()
 3765                        .map(|(range, text)| {
 3766                            use text::ToPoint as TP;
 3767                            let end_point = TP::to_point(&range.end, &snapshot);
 3768                            let start_point = TP::to_point(&range.start, &snapshot);
 3769                            (start_point..end_point, text)
 3770                        })
 3771                        .sorted_by_key(|(range, _)| range.start);
 3772                    buffer.edit(edits, None, cx);
 3773                })
 3774            }
 3775            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3776            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3777            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3778            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3779                .zip(new_selection_deltas)
 3780                .map(|(selection, delta)| Selection {
 3781                    id: selection.id,
 3782                    start: selection.start + delta,
 3783                    end: selection.end + delta,
 3784                    reversed: selection.reversed,
 3785                    goal: SelectionGoal::None,
 3786                })
 3787                .collect::<Vec<_>>();
 3788
 3789            let mut i = 0;
 3790            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3791                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3792                let start = map.buffer_snapshot.anchor_before(position);
 3793                let end = map.buffer_snapshot.anchor_after(position);
 3794                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3795                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3796                        Ordering::Less => i += 1,
 3797                        Ordering::Greater => break,
 3798                        Ordering::Equal => {
 3799                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3800                                Ordering::Less => i += 1,
 3801                                Ordering::Equal => break,
 3802                                Ordering::Greater => break,
 3803                            }
 3804                        }
 3805                    }
 3806                }
 3807                this.autoclose_regions.insert(
 3808                    i,
 3809                    AutocloseRegion {
 3810                        selection_id,
 3811                        range: start..end,
 3812                        pair,
 3813                    },
 3814                );
 3815            }
 3816
 3817            let had_active_inline_completion = this.has_active_inline_completion();
 3818            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3819                s.select(new_selections)
 3820            });
 3821
 3822            if !bracket_inserted {
 3823                if let Some(on_type_format_task) =
 3824                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3825                {
 3826                    on_type_format_task.detach_and_log_err(cx);
 3827                }
 3828            }
 3829
 3830            let editor_settings = EditorSettings::get_global(cx);
 3831            if bracket_inserted
 3832                && (editor_settings.auto_signature_help
 3833                    || editor_settings.show_signature_help_after_edits)
 3834            {
 3835                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3836            }
 3837
 3838            let trigger_in_words =
 3839                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3840            if this.hard_wrap.is_some() {
 3841                let latest: Range<Point> = this.selections.newest(cx).range();
 3842                if latest.is_empty()
 3843                    && this
 3844                        .buffer()
 3845                        .read(cx)
 3846                        .snapshot(cx)
 3847                        .line_len(MultiBufferRow(latest.start.row))
 3848                        == latest.start.column
 3849                {
 3850                    this.rewrap_impl(
 3851                        RewrapOptions {
 3852                            override_language_settings: true,
 3853                            preserve_existing_whitespace: true,
 3854                        },
 3855                        cx,
 3856                    )
 3857                }
 3858            }
 3859            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3860            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3861            this.refresh_inline_completion(true, false, window, cx);
 3862            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3863        });
 3864    }
 3865
 3866    fn find_possible_emoji_shortcode_at_position(
 3867        snapshot: &MultiBufferSnapshot,
 3868        position: Point,
 3869    ) -> Option<String> {
 3870        let mut chars = Vec::new();
 3871        let mut found_colon = false;
 3872        for char in snapshot.reversed_chars_at(position).take(100) {
 3873            // Found a possible emoji shortcode in the middle of the buffer
 3874            if found_colon {
 3875                if char.is_whitespace() {
 3876                    chars.reverse();
 3877                    return Some(chars.iter().collect());
 3878                }
 3879                // If the previous character is not a whitespace, we are in the middle of a word
 3880                // and we only want to complete the shortcode if the word is made up of other emojis
 3881                let mut containing_word = String::new();
 3882                for ch in snapshot
 3883                    .reversed_chars_at(position)
 3884                    .skip(chars.len() + 1)
 3885                    .take(100)
 3886                {
 3887                    if ch.is_whitespace() {
 3888                        break;
 3889                    }
 3890                    containing_word.push(ch);
 3891                }
 3892                let containing_word = containing_word.chars().rev().collect::<String>();
 3893                if util::word_consists_of_emojis(containing_word.as_str()) {
 3894                    chars.reverse();
 3895                    return Some(chars.iter().collect());
 3896                }
 3897            }
 3898
 3899            if char.is_whitespace() || !char.is_ascii() {
 3900                return None;
 3901            }
 3902            if char == ':' {
 3903                found_colon = true;
 3904            } else {
 3905                chars.push(char);
 3906            }
 3907        }
 3908        // Found a possible emoji shortcode at the beginning of the buffer
 3909        chars.reverse();
 3910        Some(chars.iter().collect())
 3911    }
 3912
 3913    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3915        self.transact(window, cx, |this, window, cx| {
 3916            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3917                let selections = this.selections.all::<usize>(cx);
 3918                let multi_buffer = this.buffer.read(cx);
 3919                let buffer = multi_buffer.snapshot(cx);
 3920                selections
 3921                    .iter()
 3922                    .map(|selection| {
 3923                        let start_point = selection.start.to_point(&buffer);
 3924                        let mut existing_indent =
 3925                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3926                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3927                        let start = selection.start;
 3928                        let end = selection.end;
 3929                        let selection_is_empty = start == end;
 3930                        let language_scope = buffer.language_scope_at(start);
 3931                        let (
 3932                            comment_delimiter,
 3933                            doc_delimiter,
 3934                            insert_extra_newline,
 3935                            indent_on_newline,
 3936                            indent_on_extra_newline,
 3937                        ) = if let Some(language) = &language_scope {
 3938                            let mut insert_extra_newline =
 3939                                insert_extra_newline_brackets(&buffer, start..end, language)
 3940                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3941
 3942                            // Comment extension on newline is allowed only for cursor selections
 3943                            let comment_delimiter = maybe!({
 3944                                if !selection_is_empty {
 3945                                    return None;
 3946                                }
 3947
 3948                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3949                                    return None;
 3950                                }
 3951
 3952                                let delimiters = language.line_comment_prefixes();
 3953                                let max_len_of_delimiter =
 3954                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3955                                let (snapshot, range) =
 3956                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3957
 3958                                let num_of_whitespaces = snapshot
 3959                                    .chars_for_range(range.clone())
 3960                                    .take_while(|c| c.is_whitespace())
 3961                                    .count();
 3962                                let comment_candidate = snapshot
 3963                                    .chars_for_range(range)
 3964                                    .skip(num_of_whitespaces)
 3965                                    .take(max_len_of_delimiter)
 3966                                    .collect::<String>();
 3967                                let (delimiter, trimmed_len) =
 3968                                    delimiters.iter().find_map(|delimiter| {
 3969                                        let trimmed = delimiter.trim_end();
 3970                                        if comment_candidate.starts_with(trimmed) {
 3971                                            Some((delimiter, trimmed.len()))
 3972                                        } else {
 3973                                            None
 3974                                        }
 3975                                    })?;
 3976                                let cursor_is_placed_after_comment_marker =
 3977                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3978                                if cursor_is_placed_after_comment_marker {
 3979                                    Some(delimiter.clone())
 3980                                } else {
 3981                                    None
 3982                                }
 3983                            });
 3984
 3985                            let mut indent_on_newline = IndentSize::spaces(0);
 3986                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3987
 3988                            let doc_delimiter = maybe!({
 3989                                if !selection_is_empty {
 3990                                    return None;
 3991                                }
 3992
 3993                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3994                                    return None;
 3995                                }
 3996
 3997                                let DocumentationConfig {
 3998                                    start: start_tag,
 3999                                    end: end_tag,
 4000                                    prefix: delimiter,
 4001                                    tab_size: len,
 4002                                } = language.documentation()?;
 4003
 4004                                let (snapshot, range) =
 4005                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4006
 4007                                let num_of_whitespaces = snapshot
 4008                                    .chars_for_range(range.clone())
 4009                                    .take_while(|c| c.is_whitespace())
 4010                                    .count();
 4011
 4012                                let cursor_is_after_start_tag = {
 4013                                    let start_tag_len = start_tag.len();
 4014                                    let start_tag_line = snapshot
 4015                                        .chars_for_range(range.clone())
 4016                                        .skip(num_of_whitespaces)
 4017                                        .take(start_tag_len)
 4018                                        .collect::<String>();
 4019                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4020                                        num_of_whitespaces + start_tag_len
 4021                                            <= start_point.column as usize
 4022                                    } else {
 4023                                        false
 4024                                    }
 4025                                };
 4026
 4027                                let cursor_is_after_delimiter = {
 4028                                    let delimiter_trim = delimiter.trim_end();
 4029                                    let delimiter_line = snapshot
 4030                                        .chars_for_range(range.clone())
 4031                                        .skip(num_of_whitespaces)
 4032                                        .take(delimiter_trim.len())
 4033                                        .collect::<String>();
 4034                                    if delimiter_line.starts_with(delimiter_trim) {
 4035                                        num_of_whitespaces + delimiter_trim.len()
 4036                                            <= start_point.column as usize
 4037                                    } else {
 4038                                        false
 4039                                    }
 4040                                };
 4041
 4042                                let cursor_is_before_end_tag_if_exists = {
 4043                                    let num_of_whitespaces_rev = snapshot
 4044                                        .reversed_chars_for_range(range.clone())
 4045                                        .take_while(|c| c.is_whitespace())
 4046                                        .count();
 4047                                    let mut line_iter = snapshot
 4048                                        .reversed_chars_for_range(range)
 4049                                        .skip(num_of_whitespaces_rev);
 4050                                    let end_tag_exists = end_tag
 4051                                        .chars()
 4052                                        .rev()
 4053                                        .all(|char| line_iter.next() == Some(char));
 4054                                    if end_tag_exists {
 4055                                        let max_point = snapshot.line_len(start_point.row) as usize;
 4056                                        let ordering = (num_of_whitespaces_rev
 4057                                            + end_tag.len()
 4058                                            + start_point.column as usize)
 4059                                            .cmp(&max_point);
 4060                                        let cursor_is_before_end_tag =
 4061                                            ordering != Ordering::Greater;
 4062                                        if cursor_is_after_start_tag {
 4063                                            if cursor_is_before_end_tag {
 4064                                                insert_extra_newline = true;
 4065                                            }
 4066                                            let cursor_is_at_start_of_end_tag =
 4067                                                ordering == Ordering::Equal;
 4068                                            if cursor_is_at_start_of_end_tag {
 4069                                                indent_on_extra_newline.len = (*len).into();
 4070                                            }
 4071                                        }
 4072                                        cursor_is_before_end_tag
 4073                                    } else {
 4074                                        true
 4075                                    }
 4076                                };
 4077
 4078                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4079                                    && cursor_is_before_end_tag_if_exists
 4080                                {
 4081                                    if cursor_is_after_start_tag {
 4082                                        indent_on_newline.len = (*len).into();
 4083                                    }
 4084                                    Some(delimiter.clone())
 4085                                } else {
 4086                                    None
 4087                                }
 4088                            });
 4089
 4090                            (
 4091                                comment_delimiter,
 4092                                doc_delimiter,
 4093                                insert_extra_newline,
 4094                                indent_on_newline,
 4095                                indent_on_extra_newline,
 4096                            )
 4097                        } else {
 4098                            (
 4099                                None,
 4100                                None,
 4101                                false,
 4102                                IndentSize::default(),
 4103                                IndentSize::default(),
 4104                            )
 4105                        };
 4106
 4107                        let prevent_auto_indent = doc_delimiter.is_some();
 4108                        let delimiter = comment_delimiter.or(doc_delimiter);
 4109
 4110                        let capacity_for_delimiter =
 4111                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4112                        let mut new_text = String::with_capacity(
 4113                            1 + capacity_for_delimiter
 4114                                + existing_indent.len as usize
 4115                                + indent_on_newline.len as usize
 4116                                + indent_on_extra_newline.len as usize,
 4117                        );
 4118                        new_text.push('\n');
 4119                        new_text.extend(existing_indent.chars());
 4120                        new_text.extend(indent_on_newline.chars());
 4121
 4122                        if let Some(delimiter) = &delimiter {
 4123                            new_text.push_str(delimiter);
 4124                        }
 4125
 4126                        if insert_extra_newline {
 4127                            new_text.push('\n');
 4128                            new_text.extend(existing_indent.chars());
 4129                            new_text.extend(indent_on_extra_newline.chars());
 4130                        }
 4131
 4132                        let anchor = buffer.anchor_after(end);
 4133                        let new_selection = selection.map(|_| anchor);
 4134                        (
 4135                            ((start..end, new_text), prevent_auto_indent),
 4136                            (insert_extra_newline, new_selection),
 4137                        )
 4138                    })
 4139                    .unzip()
 4140            };
 4141
 4142            let mut auto_indent_edits = Vec::new();
 4143            let mut edits = Vec::new();
 4144            for (edit, prevent_auto_indent) in edits_with_flags {
 4145                if prevent_auto_indent {
 4146                    edits.push(edit);
 4147                } else {
 4148                    auto_indent_edits.push(edit);
 4149                }
 4150            }
 4151            if !edits.is_empty() {
 4152                this.edit(edits, cx);
 4153            }
 4154            if !auto_indent_edits.is_empty() {
 4155                this.edit_with_autoindent(auto_indent_edits, cx);
 4156            }
 4157
 4158            let buffer = this.buffer.read(cx).snapshot(cx);
 4159            let new_selections = selection_info
 4160                .into_iter()
 4161                .map(|(extra_newline_inserted, new_selection)| {
 4162                    let mut cursor = new_selection.end.to_point(&buffer);
 4163                    if extra_newline_inserted {
 4164                        cursor.row -= 1;
 4165                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4166                    }
 4167                    new_selection.map(|_| cursor)
 4168                })
 4169                .collect();
 4170
 4171            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4172                s.select(new_selections)
 4173            });
 4174            this.refresh_inline_completion(true, false, window, cx);
 4175        });
 4176    }
 4177
 4178    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4179        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4180
 4181        let buffer = self.buffer.read(cx);
 4182        let snapshot = buffer.snapshot(cx);
 4183
 4184        let mut edits = Vec::new();
 4185        let mut rows = Vec::new();
 4186
 4187        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4188            let cursor = selection.head();
 4189            let row = cursor.row;
 4190
 4191            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4192
 4193            let newline = "\n".to_string();
 4194            edits.push((start_of_line..start_of_line, newline));
 4195
 4196            rows.push(row + rows_inserted as u32);
 4197        }
 4198
 4199        self.transact(window, cx, |editor, window, cx| {
 4200            editor.edit(edits, cx);
 4201
 4202            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4203                let mut index = 0;
 4204                s.move_cursors_with(|map, _, _| {
 4205                    let row = rows[index];
 4206                    index += 1;
 4207
 4208                    let point = Point::new(row, 0);
 4209                    let boundary = map.next_line_boundary(point).1;
 4210                    let clipped = map.clip_point(boundary, Bias::Left);
 4211
 4212                    (clipped, SelectionGoal::None)
 4213                });
 4214            });
 4215
 4216            let mut indent_edits = Vec::new();
 4217            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4218            for row in rows {
 4219                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4220                for (row, indent) in indents {
 4221                    if indent.len == 0 {
 4222                        continue;
 4223                    }
 4224
 4225                    let text = match indent.kind {
 4226                        IndentKind::Space => " ".repeat(indent.len as usize),
 4227                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4228                    };
 4229                    let point = Point::new(row.0, 0);
 4230                    indent_edits.push((point..point, text));
 4231                }
 4232            }
 4233            editor.edit(indent_edits, cx);
 4234        });
 4235    }
 4236
 4237    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4238        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4239
 4240        let buffer = self.buffer.read(cx);
 4241        let snapshot = buffer.snapshot(cx);
 4242
 4243        let mut edits = Vec::new();
 4244        let mut rows = Vec::new();
 4245        let mut rows_inserted = 0;
 4246
 4247        for selection in self.selections.all_adjusted(cx) {
 4248            let cursor = selection.head();
 4249            let row = cursor.row;
 4250
 4251            let point = Point::new(row + 1, 0);
 4252            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4253
 4254            let newline = "\n".to_string();
 4255            edits.push((start_of_line..start_of_line, newline));
 4256
 4257            rows_inserted += 1;
 4258            rows.push(row + rows_inserted);
 4259        }
 4260
 4261        self.transact(window, cx, |editor, window, cx| {
 4262            editor.edit(edits, cx);
 4263
 4264            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4265                let mut index = 0;
 4266                s.move_cursors_with(|map, _, _| {
 4267                    let row = rows[index];
 4268                    index += 1;
 4269
 4270                    let point = Point::new(row, 0);
 4271                    let boundary = map.next_line_boundary(point).1;
 4272                    let clipped = map.clip_point(boundary, Bias::Left);
 4273
 4274                    (clipped, SelectionGoal::None)
 4275                });
 4276            });
 4277
 4278            let mut indent_edits = Vec::new();
 4279            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4280            for row in rows {
 4281                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4282                for (row, indent) in indents {
 4283                    if indent.len == 0 {
 4284                        continue;
 4285                    }
 4286
 4287                    let text = match indent.kind {
 4288                        IndentKind::Space => " ".repeat(indent.len as usize),
 4289                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4290                    };
 4291                    let point = Point::new(row.0, 0);
 4292                    indent_edits.push((point..point, text));
 4293                }
 4294            }
 4295            editor.edit(indent_edits, cx);
 4296        });
 4297    }
 4298
 4299    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4300        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4301            original_indent_columns: Vec::new(),
 4302        });
 4303        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4304    }
 4305
 4306    fn insert_with_autoindent_mode(
 4307        &mut self,
 4308        text: &str,
 4309        autoindent_mode: Option<AutoindentMode>,
 4310        window: &mut Window,
 4311        cx: &mut Context<Self>,
 4312    ) {
 4313        if self.read_only(cx) {
 4314            return;
 4315        }
 4316
 4317        let text: Arc<str> = text.into();
 4318        self.transact(window, cx, |this, window, cx| {
 4319            let old_selections = this.selections.all_adjusted(cx);
 4320            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4321                let anchors = {
 4322                    let snapshot = buffer.read(cx);
 4323                    old_selections
 4324                        .iter()
 4325                        .map(|s| {
 4326                            let anchor = snapshot.anchor_after(s.head());
 4327                            s.map(|_| anchor)
 4328                        })
 4329                        .collect::<Vec<_>>()
 4330                };
 4331                buffer.edit(
 4332                    old_selections
 4333                        .iter()
 4334                        .map(|s| (s.start..s.end, text.clone())),
 4335                    autoindent_mode,
 4336                    cx,
 4337                );
 4338                anchors
 4339            });
 4340
 4341            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4342                s.select_anchors(selection_anchors);
 4343            });
 4344
 4345            cx.notify();
 4346        });
 4347    }
 4348
 4349    fn trigger_completion_on_input(
 4350        &mut self,
 4351        text: &str,
 4352        trigger_in_words: bool,
 4353        window: &mut Window,
 4354        cx: &mut Context<Self>,
 4355    ) {
 4356        let ignore_completion_provider = self
 4357            .context_menu
 4358            .borrow()
 4359            .as_ref()
 4360            .map(|menu| match menu {
 4361                CodeContextMenu::Completions(completions_menu) => {
 4362                    completions_menu.ignore_completion_provider
 4363                }
 4364                CodeContextMenu::CodeActions(_) => false,
 4365            })
 4366            .unwrap_or(false);
 4367
 4368        if ignore_completion_provider {
 4369            self.show_word_completions(&ShowWordCompletions, window, cx);
 4370        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4371            self.show_completions(
 4372                &ShowCompletions {
 4373                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4374                },
 4375                window,
 4376                cx,
 4377            );
 4378        } else {
 4379            self.hide_context_menu(window, cx);
 4380        }
 4381    }
 4382
 4383    fn is_completion_trigger(
 4384        &self,
 4385        text: &str,
 4386        trigger_in_words: bool,
 4387        cx: &mut Context<Self>,
 4388    ) -> bool {
 4389        let position = self.selections.newest_anchor().head();
 4390        let multibuffer = self.buffer.read(cx);
 4391        let Some(buffer) = position
 4392            .buffer_id
 4393            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4394        else {
 4395            return false;
 4396        };
 4397
 4398        if let Some(completion_provider) = &self.completion_provider {
 4399            completion_provider.is_completion_trigger(
 4400                &buffer,
 4401                position.text_anchor,
 4402                text,
 4403                trigger_in_words,
 4404                cx,
 4405            )
 4406        } else {
 4407            false
 4408        }
 4409    }
 4410
 4411    /// If any empty selections is touching the start of its innermost containing autoclose
 4412    /// region, expand it to select the brackets.
 4413    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4414        let selections = self.selections.all::<usize>(cx);
 4415        let buffer = self.buffer.read(cx).read(cx);
 4416        let new_selections = self
 4417            .selections_with_autoclose_regions(selections, &buffer)
 4418            .map(|(mut selection, region)| {
 4419                if !selection.is_empty() {
 4420                    return selection;
 4421                }
 4422
 4423                if let Some(region) = region {
 4424                    let mut range = region.range.to_offset(&buffer);
 4425                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4426                        range.start -= region.pair.start.len();
 4427                        if buffer.contains_str_at(range.start, &region.pair.start)
 4428                            && buffer.contains_str_at(range.end, &region.pair.end)
 4429                        {
 4430                            range.end += region.pair.end.len();
 4431                            selection.start = range.start;
 4432                            selection.end = range.end;
 4433
 4434                            return selection;
 4435                        }
 4436                    }
 4437                }
 4438
 4439                let always_treat_brackets_as_autoclosed = buffer
 4440                    .language_settings_at(selection.start, cx)
 4441                    .always_treat_brackets_as_autoclosed;
 4442
 4443                if !always_treat_brackets_as_autoclosed {
 4444                    return selection;
 4445                }
 4446
 4447                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4448                    for (pair, enabled) in scope.brackets() {
 4449                        if !enabled || !pair.close {
 4450                            continue;
 4451                        }
 4452
 4453                        if buffer.contains_str_at(selection.start, &pair.end) {
 4454                            let pair_start_len = pair.start.len();
 4455                            if buffer.contains_str_at(
 4456                                selection.start.saturating_sub(pair_start_len),
 4457                                &pair.start,
 4458                            ) {
 4459                                selection.start -= pair_start_len;
 4460                                selection.end += pair.end.len();
 4461
 4462                                return selection;
 4463                            }
 4464                        }
 4465                    }
 4466                }
 4467
 4468                selection
 4469            })
 4470            .collect();
 4471
 4472        drop(buffer);
 4473        self.change_selections(None, window, cx, |selections| {
 4474            selections.select(new_selections)
 4475        });
 4476    }
 4477
 4478    /// Iterate the given selections, and for each one, find the smallest surrounding
 4479    /// autoclose region. This uses the ordering of the selections and the autoclose
 4480    /// regions to avoid repeated comparisons.
 4481    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4482        &'a self,
 4483        selections: impl IntoIterator<Item = Selection<D>>,
 4484        buffer: &'a MultiBufferSnapshot,
 4485    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4486        let mut i = 0;
 4487        let mut regions = self.autoclose_regions.as_slice();
 4488        selections.into_iter().map(move |selection| {
 4489            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4490
 4491            let mut enclosing = None;
 4492            while let Some(pair_state) = regions.get(i) {
 4493                if pair_state.range.end.to_offset(buffer) < range.start {
 4494                    regions = &regions[i + 1..];
 4495                    i = 0;
 4496                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4497                    break;
 4498                } else {
 4499                    if pair_state.selection_id == selection.id {
 4500                        enclosing = Some(pair_state);
 4501                    }
 4502                    i += 1;
 4503                }
 4504            }
 4505
 4506            (selection, enclosing)
 4507        })
 4508    }
 4509
 4510    /// Remove any autoclose regions that no longer contain their selection.
 4511    fn invalidate_autoclose_regions(
 4512        &mut self,
 4513        mut selections: &[Selection<Anchor>],
 4514        buffer: &MultiBufferSnapshot,
 4515    ) {
 4516        self.autoclose_regions.retain(|state| {
 4517            let mut i = 0;
 4518            while let Some(selection) = selections.get(i) {
 4519                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4520                    selections = &selections[1..];
 4521                    continue;
 4522                }
 4523                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4524                    break;
 4525                }
 4526                if selection.id == state.selection_id {
 4527                    return true;
 4528                } else {
 4529                    i += 1;
 4530                }
 4531            }
 4532            false
 4533        });
 4534    }
 4535
 4536    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4537        let offset = position.to_offset(buffer);
 4538        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4539        if offset > word_range.start && kind == Some(CharKind::Word) {
 4540            Some(
 4541                buffer
 4542                    .text_for_range(word_range.start..offset)
 4543                    .collect::<String>(),
 4544            )
 4545        } else {
 4546            None
 4547        }
 4548    }
 4549
 4550    pub fn toggle_inline_values(
 4551        &mut self,
 4552        _: &ToggleInlineValues,
 4553        _: &mut Window,
 4554        cx: &mut Context<Self>,
 4555    ) {
 4556        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4557
 4558        self.refresh_inline_values(cx);
 4559    }
 4560
 4561    pub fn toggle_inlay_hints(
 4562        &mut self,
 4563        _: &ToggleInlayHints,
 4564        _: &mut Window,
 4565        cx: &mut Context<Self>,
 4566    ) {
 4567        self.refresh_inlay_hints(
 4568            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4569            cx,
 4570        );
 4571    }
 4572
 4573    pub fn inlay_hints_enabled(&self) -> bool {
 4574        self.inlay_hint_cache.enabled
 4575    }
 4576
 4577    pub fn inline_values_enabled(&self) -> bool {
 4578        self.inline_value_cache.enabled
 4579    }
 4580
 4581    #[cfg(any(test, feature = "test-support"))]
 4582    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4583        self.display_map
 4584            .read(cx)
 4585            .current_inlays()
 4586            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4587            .cloned()
 4588            .collect()
 4589    }
 4590
 4591    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4592        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4593            return;
 4594        }
 4595
 4596        let reason_description = reason.description();
 4597        let ignore_debounce = matches!(
 4598            reason,
 4599            InlayHintRefreshReason::SettingsChange(_)
 4600                | InlayHintRefreshReason::Toggle(_)
 4601                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4602                | InlayHintRefreshReason::ModifiersChanged(_)
 4603        );
 4604        let (invalidate_cache, required_languages) = match reason {
 4605            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4606                match self.inlay_hint_cache.modifiers_override(enabled) {
 4607                    Some(enabled) => {
 4608                        if enabled {
 4609                            (InvalidationStrategy::RefreshRequested, None)
 4610                        } else {
 4611                            self.splice_inlays(
 4612                                &self
 4613                                    .visible_inlay_hints(cx)
 4614                                    .iter()
 4615                                    .map(|inlay| inlay.id)
 4616                                    .collect::<Vec<InlayId>>(),
 4617                                Vec::new(),
 4618                                cx,
 4619                            );
 4620                            return;
 4621                        }
 4622                    }
 4623                    None => return,
 4624                }
 4625            }
 4626            InlayHintRefreshReason::Toggle(enabled) => {
 4627                if self.inlay_hint_cache.toggle(enabled) {
 4628                    if enabled {
 4629                        (InvalidationStrategy::RefreshRequested, None)
 4630                    } else {
 4631                        self.splice_inlays(
 4632                            &self
 4633                                .visible_inlay_hints(cx)
 4634                                .iter()
 4635                                .map(|inlay| inlay.id)
 4636                                .collect::<Vec<InlayId>>(),
 4637                            Vec::new(),
 4638                            cx,
 4639                        );
 4640                        return;
 4641                    }
 4642                } else {
 4643                    return;
 4644                }
 4645            }
 4646            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4647                match self.inlay_hint_cache.update_settings(
 4648                    &self.buffer,
 4649                    new_settings,
 4650                    self.visible_inlay_hints(cx),
 4651                    cx,
 4652                ) {
 4653                    ControlFlow::Break(Some(InlaySplice {
 4654                        to_remove,
 4655                        to_insert,
 4656                    })) => {
 4657                        self.splice_inlays(&to_remove, to_insert, cx);
 4658                        return;
 4659                    }
 4660                    ControlFlow::Break(None) => return,
 4661                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4662                }
 4663            }
 4664            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4665                if let Some(InlaySplice {
 4666                    to_remove,
 4667                    to_insert,
 4668                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4669                {
 4670                    self.splice_inlays(&to_remove, to_insert, cx);
 4671                }
 4672                self.display_map.update(cx, |display_map, _| {
 4673                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4674                });
 4675                return;
 4676            }
 4677            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4678            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4679                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4680            }
 4681            InlayHintRefreshReason::RefreshRequested => {
 4682                (InvalidationStrategy::RefreshRequested, None)
 4683            }
 4684        };
 4685
 4686        if let Some(InlaySplice {
 4687            to_remove,
 4688            to_insert,
 4689        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4690            reason_description,
 4691            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4692            invalidate_cache,
 4693            ignore_debounce,
 4694            cx,
 4695        ) {
 4696            self.splice_inlays(&to_remove, to_insert, cx);
 4697        }
 4698    }
 4699
 4700    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4701        self.display_map
 4702            .read(cx)
 4703            .current_inlays()
 4704            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4705            .cloned()
 4706            .collect()
 4707    }
 4708
 4709    pub fn excerpts_for_inlay_hints_query(
 4710        &self,
 4711        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4712        cx: &mut Context<Editor>,
 4713    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4714        let Some(project) = self.project.as_ref() else {
 4715            return HashMap::default();
 4716        };
 4717        let project = project.read(cx);
 4718        let multi_buffer = self.buffer().read(cx);
 4719        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4720        let multi_buffer_visible_start = self
 4721            .scroll_manager
 4722            .anchor()
 4723            .anchor
 4724            .to_point(&multi_buffer_snapshot);
 4725        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4726            multi_buffer_visible_start
 4727                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4728            Bias::Left,
 4729        );
 4730        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4731        multi_buffer_snapshot
 4732            .range_to_buffer_ranges(multi_buffer_visible_range)
 4733            .into_iter()
 4734            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4735            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4736                let buffer_file = project::File::from_dyn(buffer.file())?;
 4737                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4738                let worktree_entry = buffer_worktree
 4739                    .read(cx)
 4740                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4741                if worktree_entry.is_ignored {
 4742                    return None;
 4743                }
 4744
 4745                let language = buffer.language()?;
 4746                if let Some(restrict_to_languages) = restrict_to_languages {
 4747                    if !restrict_to_languages.contains(language) {
 4748                        return None;
 4749                    }
 4750                }
 4751                Some((
 4752                    excerpt_id,
 4753                    (
 4754                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4755                        buffer.version().clone(),
 4756                        excerpt_visible_range,
 4757                    ),
 4758                ))
 4759            })
 4760            .collect()
 4761    }
 4762
 4763    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4764        TextLayoutDetails {
 4765            text_system: window.text_system().clone(),
 4766            editor_style: self.style.clone().unwrap(),
 4767            rem_size: window.rem_size(),
 4768            scroll_anchor: self.scroll_manager.anchor(),
 4769            visible_rows: self.visible_line_count(),
 4770            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4771        }
 4772    }
 4773
 4774    pub fn splice_inlays(
 4775        &self,
 4776        to_remove: &[InlayId],
 4777        to_insert: Vec<Inlay>,
 4778        cx: &mut Context<Self>,
 4779    ) {
 4780        self.display_map.update(cx, |display_map, cx| {
 4781            display_map.splice_inlays(to_remove, to_insert, cx)
 4782        });
 4783        cx.notify();
 4784    }
 4785
 4786    fn trigger_on_type_formatting(
 4787        &self,
 4788        input: String,
 4789        window: &mut Window,
 4790        cx: &mut Context<Self>,
 4791    ) -> Option<Task<Result<()>>> {
 4792        if input.len() != 1 {
 4793            return None;
 4794        }
 4795
 4796        let project = self.project.as_ref()?;
 4797        let position = self.selections.newest_anchor().head();
 4798        let (buffer, buffer_position) = self
 4799            .buffer
 4800            .read(cx)
 4801            .text_anchor_for_position(position, cx)?;
 4802
 4803        let settings = language_settings::language_settings(
 4804            buffer
 4805                .read(cx)
 4806                .language_at(buffer_position)
 4807                .map(|l| l.name()),
 4808            buffer.read(cx).file(),
 4809            cx,
 4810        );
 4811        if !settings.use_on_type_format {
 4812            return None;
 4813        }
 4814
 4815        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4816        // hence we do LSP request & edit on host side only — add formats to host's history.
 4817        let push_to_lsp_host_history = true;
 4818        // If this is not the host, append its history with new edits.
 4819        let push_to_client_history = project.read(cx).is_via_collab();
 4820
 4821        let on_type_formatting = project.update(cx, |project, cx| {
 4822            project.on_type_format(
 4823                buffer.clone(),
 4824                buffer_position,
 4825                input,
 4826                push_to_lsp_host_history,
 4827                cx,
 4828            )
 4829        });
 4830        Some(cx.spawn_in(window, async move |editor, cx| {
 4831            if let Some(transaction) = on_type_formatting.await? {
 4832                if push_to_client_history {
 4833                    buffer
 4834                        .update(cx, |buffer, _| {
 4835                            buffer.push_transaction(transaction, Instant::now());
 4836                            buffer.finalize_last_transaction();
 4837                        })
 4838                        .ok();
 4839                }
 4840                editor.update(cx, |editor, cx| {
 4841                    editor.refresh_document_highlights(cx);
 4842                })?;
 4843            }
 4844            Ok(())
 4845        }))
 4846    }
 4847
 4848    pub fn show_word_completions(
 4849        &mut self,
 4850        _: &ShowWordCompletions,
 4851        window: &mut Window,
 4852        cx: &mut Context<Self>,
 4853    ) {
 4854        self.open_completions_menu(true, None, window, cx);
 4855    }
 4856
 4857    pub fn show_completions(
 4858        &mut self,
 4859        options: &ShowCompletions,
 4860        window: &mut Window,
 4861        cx: &mut Context<Self>,
 4862    ) {
 4863        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4864    }
 4865
 4866    fn open_completions_menu(
 4867        &mut self,
 4868        ignore_completion_provider: bool,
 4869        trigger: Option<&str>,
 4870        window: &mut Window,
 4871        cx: &mut Context<Self>,
 4872    ) {
 4873        if self.pending_rename.is_some() {
 4874            return;
 4875        }
 4876        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4877            return;
 4878        }
 4879
 4880        let position = self.selections.newest_anchor().head();
 4881        if position.diff_base_anchor.is_some() {
 4882            return;
 4883        }
 4884        let (buffer, buffer_position) =
 4885            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4886                output
 4887            } else {
 4888                return;
 4889            };
 4890        let buffer_snapshot = buffer.read(cx).snapshot();
 4891        let show_completion_documentation = buffer_snapshot
 4892            .settings_at(buffer_position, cx)
 4893            .show_completion_documentation;
 4894
 4895        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4896
 4897        let trigger_kind = match trigger {
 4898            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4899                CompletionTriggerKind::TRIGGER_CHARACTER
 4900            }
 4901            _ => CompletionTriggerKind::INVOKED,
 4902        };
 4903        let completion_context = CompletionContext {
 4904            trigger_character: trigger.and_then(|trigger| {
 4905                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4906                    Some(String::from(trigger))
 4907                } else {
 4908                    None
 4909                }
 4910            }),
 4911            trigger_kind,
 4912        };
 4913
 4914        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4915        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4916            let word_to_exclude = buffer_snapshot
 4917                .text_for_range(old_range.clone())
 4918                .collect::<String>();
 4919            (
 4920                buffer_snapshot.anchor_before(old_range.start)
 4921                    ..buffer_snapshot.anchor_after(old_range.end),
 4922                Some(word_to_exclude),
 4923            )
 4924        } else {
 4925            (buffer_position..buffer_position, None)
 4926        };
 4927
 4928        let completion_settings = language_settings(
 4929            buffer_snapshot
 4930                .language_at(buffer_position)
 4931                .map(|language| language.name()),
 4932            buffer_snapshot.file(),
 4933            cx,
 4934        )
 4935        .completions;
 4936
 4937        // The document can be large, so stay in reasonable bounds when searching for words,
 4938        // otherwise completion pop-up might be slow to appear.
 4939        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4940        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4941        let min_word_search = buffer_snapshot.clip_point(
 4942            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4943            Bias::Left,
 4944        );
 4945        let max_word_search = buffer_snapshot.clip_point(
 4946            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4947            Bias::Right,
 4948        );
 4949        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4950            ..buffer_snapshot.point_to_offset(max_word_search);
 4951
 4952        let provider = self
 4953            .completion_provider
 4954            .as_ref()
 4955            .filter(|_| !ignore_completion_provider);
 4956        let skip_digits = query
 4957            .as_ref()
 4958            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4959
 4960        let (mut words, provided_completions) = match provider {
 4961            Some(provider) => {
 4962                let completions = provider.completions(
 4963                    position.excerpt_id,
 4964                    &buffer,
 4965                    buffer_position,
 4966                    completion_context,
 4967                    window,
 4968                    cx,
 4969                );
 4970
 4971                let words = match completion_settings.words {
 4972                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4973                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4974                        .background_spawn(async move {
 4975                            buffer_snapshot.words_in_range(WordsQuery {
 4976                                fuzzy_contents: None,
 4977                                range: word_search_range,
 4978                                skip_digits,
 4979                            })
 4980                        }),
 4981                };
 4982
 4983                (words, completions)
 4984            }
 4985            None => (
 4986                cx.background_spawn(async move {
 4987                    buffer_snapshot.words_in_range(WordsQuery {
 4988                        fuzzy_contents: None,
 4989                        range: word_search_range,
 4990                        skip_digits,
 4991                    })
 4992                }),
 4993                Task::ready(Ok(None)),
 4994            ),
 4995        };
 4996
 4997        let sort_completions = provider
 4998            .as_ref()
 4999            .map_or(false, |provider| provider.sort_completions());
 5000
 5001        let filter_completions = provider
 5002            .as_ref()
 5003            .map_or(true, |provider| provider.filter_completions());
 5004
 5005        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5006
 5007        let id = post_inc(&mut self.next_completion_id);
 5008        let task = cx.spawn_in(window, async move |editor, cx| {
 5009            async move {
 5010                editor.update(cx, |this, _| {
 5011                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5012                })?;
 5013
 5014                let mut completions = Vec::new();
 5015                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5016                    completions.extend(provided_completions);
 5017                    if completion_settings.words == WordsCompletionMode::Fallback {
 5018                        words = Task::ready(BTreeMap::default());
 5019                    }
 5020                }
 5021
 5022                let mut words = words.await;
 5023                if let Some(word_to_exclude) = &word_to_exclude {
 5024                    words.remove(word_to_exclude);
 5025                }
 5026                for lsp_completion in &completions {
 5027                    words.remove(&lsp_completion.new_text);
 5028                }
 5029                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5030                    replace_range: old_range.clone(),
 5031                    new_text: word.clone(),
 5032                    label: CodeLabel::plain(word, None),
 5033                    icon_path: None,
 5034                    documentation: None,
 5035                    source: CompletionSource::BufferWord {
 5036                        word_range,
 5037                        resolved: false,
 5038                    },
 5039                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5040                    confirm: None,
 5041                }));
 5042
 5043                let menu = if completions.is_empty() {
 5044                    None
 5045                } else {
 5046                    let mut menu = CompletionsMenu::new(
 5047                        id,
 5048                        sort_completions,
 5049                        show_completion_documentation,
 5050                        ignore_completion_provider,
 5051                        position,
 5052                        buffer.clone(),
 5053                        completions.into(),
 5054                        snippet_sort_order,
 5055                    );
 5056
 5057                    menu.filter(
 5058                        if filter_completions {
 5059                            query.as_deref()
 5060                        } else {
 5061                            None
 5062                        },
 5063                        cx.background_executor().clone(),
 5064                    )
 5065                    .await;
 5066
 5067                    menu.visible().then_some(menu)
 5068                };
 5069
 5070                editor.update_in(cx, |editor, window, cx| {
 5071                    match editor.context_menu.borrow().as_ref() {
 5072                        None => {}
 5073                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5074                            if prev_menu.id > id {
 5075                                return;
 5076                            }
 5077                        }
 5078                        _ => return,
 5079                    }
 5080
 5081                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5082                        let mut menu = menu.unwrap();
 5083                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5084                        crate::hover_popover::hide_hover(editor, cx);
 5085                        *editor.context_menu.borrow_mut() =
 5086                            Some(CodeContextMenu::Completions(menu));
 5087
 5088                        if editor.show_edit_predictions_in_menu() {
 5089                            editor.update_visible_inline_completion(window, cx);
 5090                        } else {
 5091                            editor.discard_inline_completion(false, cx);
 5092                        }
 5093
 5094                        cx.notify();
 5095                    } else if editor.completion_tasks.len() <= 1 {
 5096                        // If there are no more completion tasks and the last menu was
 5097                        // empty, we should hide it.
 5098                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5099                        // If it was already hidden and we don't show inline
 5100                        // completions in the menu, we should also show the
 5101                        // inline-completion when available.
 5102                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5103                            editor.update_visible_inline_completion(window, cx);
 5104                        }
 5105                    }
 5106                })?;
 5107
 5108                anyhow::Ok(())
 5109            }
 5110            .log_err()
 5111            .await
 5112        });
 5113
 5114        self.completion_tasks.push((id, task));
 5115    }
 5116
 5117    #[cfg(feature = "test-support")]
 5118    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5119        let menu = self.context_menu.borrow();
 5120        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5121            let completions = menu.completions.borrow();
 5122            Some(completions.to_vec())
 5123        } else {
 5124            None
 5125        }
 5126    }
 5127
 5128    pub fn confirm_completion(
 5129        &mut self,
 5130        action: &ConfirmCompletion,
 5131        window: &mut Window,
 5132        cx: &mut Context<Self>,
 5133    ) -> Option<Task<Result<()>>> {
 5134        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5135        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5136    }
 5137
 5138    pub fn confirm_completion_insert(
 5139        &mut self,
 5140        _: &ConfirmCompletionInsert,
 5141        window: &mut Window,
 5142        cx: &mut Context<Self>,
 5143    ) -> Option<Task<Result<()>>> {
 5144        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5145        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5146    }
 5147
 5148    pub fn confirm_completion_replace(
 5149        &mut self,
 5150        _: &ConfirmCompletionReplace,
 5151        window: &mut Window,
 5152        cx: &mut Context<Self>,
 5153    ) -> Option<Task<Result<()>>> {
 5154        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5155        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5156    }
 5157
 5158    pub fn compose_completion(
 5159        &mut self,
 5160        action: &ComposeCompletion,
 5161        window: &mut Window,
 5162        cx: &mut Context<Self>,
 5163    ) -> Option<Task<Result<()>>> {
 5164        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5165        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5166    }
 5167
 5168    fn do_completion(
 5169        &mut self,
 5170        item_ix: Option<usize>,
 5171        intent: CompletionIntent,
 5172        window: &mut Window,
 5173        cx: &mut Context<Editor>,
 5174    ) -> Option<Task<Result<()>>> {
 5175        use language::ToOffset as _;
 5176
 5177        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5178        else {
 5179            return None;
 5180        };
 5181
 5182        let candidate_id = {
 5183            let entries = completions_menu.entries.borrow();
 5184            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5185            if self.show_edit_predictions_in_menu() {
 5186                self.discard_inline_completion(true, cx);
 5187            }
 5188            mat.candidate_id
 5189        };
 5190
 5191        let buffer_handle = completions_menu.buffer;
 5192        let completion = completions_menu
 5193            .completions
 5194            .borrow()
 5195            .get(candidate_id)?
 5196            .clone();
 5197        cx.stop_propagation();
 5198
 5199        let snapshot = self.buffer.read(cx).snapshot(cx);
 5200        let newest_anchor = self.selections.newest_anchor();
 5201
 5202        let snippet;
 5203        let new_text;
 5204        if completion.is_snippet() {
 5205            let mut snippet_source = completion.new_text.clone();
 5206            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5207                if scope.prefers_label_for_snippet_in_completion() {
 5208                    if let Some(label) = completion.label() {
 5209                        if matches!(
 5210                            completion.kind(),
 5211                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5212                        ) {
 5213                            snippet_source = label;
 5214                        }
 5215                    }
 5216                }
 5217            }
 5218            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5219            new_text = snippet.as_ref().unwrap().text.clone();
 5220        } else {
 5221            snippet = None;
 5222            new_text = completion.new_text.clone();
 5223        };
 5224
 5225        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5226        let buffer = buffer_handle.read(cx);
 5227        let replace_range_multibuffer = {
 5228            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5229            let multibuffer_anchor = snapshot
 5230                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5231                .unwrap()
 5232                ..snapshot
 5233                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5234                    .unwrap();
 5235            multibuffer_anchor.start.to_offset(&snapshot)
 5236                ..multibuffer_anchor.end.to_offset(&snapshot)
 5237        };
 5238        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5239            return None;
 5240        }
 5241
 5242        let old_text = buffer
 5243            .text_for_range(replace_range.clone())
 5244            .collect::<String>();
 5245        let lookbehind = newest_anchor
 5246            .start
 5247            .text_anchor
 5248            .to_offset(buffer)
 5249            .saturating_sub(replace_range.start);
 5250        let lookahead = replace_range
 5251            .end
 5252            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5253        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5254        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5255
 5256        let selections = self.selections.all::<usize>(cx);
 5257        let mut ranges = Vec::new();
 5258        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5259
 5260        for selection in &selections {
 5261            let range = if selection.id == newest_anchor.id {
 5262                replace_range_multibuffer.clone()
 5263            } else {
 5264                let mut range = selection.range();
 5265
 5266                // if prefix is present, don't duplicate it
 5267                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5268                    range.start = range.start.saturating_sub(lookbehind);
 5269
 5270                    // if suffix is also present, mimic the newest cursor and replace it
 5271                    if selection.id != newest_anchor.id
 5272                        && snapshot.contains_str_at(range.end, suffix)
 5273                    {
 5274                        range.end += lookahead;
 5275                    }
 5276                }
 5277                range
 5278            };
 5279
 5280            ranges.push(range.clone());
 5281
 5282            if !self.linked_edit_ranges.is_empty() {
 5283                let start_anchor = snapshot.anchor_before(range.start);
 5284                let end_anchor = snapshot.anchor_after(range.end);
 5285                if let Some(ranges) = self
 5286                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5287                {
 5288                    for (buffer, edits) in ranges {
 5289                        linked_edits
 5290                            .entry(buffer.clone())
 5291                            .or_default()
 5292                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5293                    }
 5294                }
 5295            }
 5296        }
 5297
 5298        cx.emit(EditorEvent::InputHandled {
 5299            utf16_range_to_replace: None,
 5300            text: new_text.clone().into(),
 5301        });
 5302
 5303        self.transact(window, cx, |this, window, cx| {
 5304            if let Some(mut snippet) = snippet {
 5305                snippet.text = new_text.to_string();
 5306                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5307            } else {
 5308                this.buffer.update(cx, |buffer, cx| {
 5309                    let auto_indent = match completion.insert_text_mode {
 5310                        Some(InsertTextMode::AS_IS) => None,
 5311                        _ => this.autoindent_mode.clone(),
 5312                    };
 5313                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5314                    buffer.edit(edits, auto_indent, cx);
 5315                });
 5316            }
 5317            for (buffer, edits) in linked_edits {
 5318                buffer.update(cx, |buffer, cx| {
 5319                    let snapshot = buffer.snapshot();
 5320                    let edits = edits
 5321                        .into_iter()
 5322                        .map(|(range, text)| {
 5323                            use text::ToPoint as TP;
 5324                            let end_point = TP::to_point(&range.end, &snapshot);
 5325                            let start_point = TP::to_point(&range.start, &snapshot);
 5326                            (start_point..end_point, text)
 5327                        })
 5328                        .sorted_by_key(|(range, _)| range.start);
 5329                    buffer.edit(edits, None, cx);
 5330                })
 5331            }
 5332
 5333            this.refresh_inline_completion(true, false, window, cx);
 5334        });
 5335
 5336        let show_new_completions_on_confirm = completion
 5337            .confirm
 5338            .as_ref()
 5339            .map_or(false, |confirm| confirm(intent, window, cx));
 5340        if show_new_completions_on_confirm {
 5341            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5342        }
 5343
 5344        let provider = self.completion_provider.as_ref()?;
 5345        drop(completion);
 5346        let apply_edits = provider.apply_additional_edits_for_completion(
 5347            buffer_handle,
 5348            completions_menu.completions.clone(),
 5349            candidate_id,
 5350            true,
 5351            cx,
 5352        );
 5353
 5354        let editor_settings = EditorSettings::get_global(cx);
 5355        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5356            // After the code completion is finished, users often want to know what signatures are needed.
 5357            // so we should automatically call signature_help
 5358            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5359        }
 5360
 5361        Some(cx.foreground_executor().spawn(async move {
 5362            apply_edits.await?;
 5363            Ok(())
 5364        }))
 5365    }
 5366
 5367    pub fn toggle_code_actions(
 5368        &mut self,
 5369        action: &ToggleCodeActions,
 5370        window: &mut Window,
 5371        cx: &mut Context<Self>,
 5372    ) {
 5373        let quick_launch = action.quick_launch;
 5374        let mut context_menu = self.context_menu.borrow_mut();
 5375        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5376            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5377                // Toggle if we're selecting the same one
 5378                *context_menu = None;
 5379                cx.notify();
 5380                return;
 5381            } else {
 5382                // Otherwise, clear it and start a new one
 5383                *context_menu = None;
 5384                cx.notify();
 5385            }
 5386        }
 5387        drop(context_menu);
 5388        let snapshot = self.snapshot(window, cx);
 5389        let deployed_from_indicator = action.deployed_from_indicator;
 5390        let mut task = self.code_actions_task.take();
 5391        let action = action.clone();
 5392        cx.spawn_in(window, async move |editor, cx| {
 5393            while let Some(prev_task) = task {
 5394                prev_task.await.log_err();
 5395                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5396            }
 5397
 5398            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5399                if editor.focus_handle.is_focused(window) {
 5400                    let multibuffer_point = action
 5401                        .deployed_from_indicator
 5402                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5403                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5404                    let (buffer, buffer_row) = snapshot
 5405                        .buffer_snapshot
 5406                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5407                        .and_then(|(buffer_snapshot, range)| {
 5408                            editor
 5409                                .buffer
 5410                                .read(cx)
 5411                                .buffer(buffer_snapshot.remote_id())
 5412                                .map(|buffer| (buffer, range.start.row))
 5413                        })?;
 5414                    let (_, code_actions) = editor
 5415                        .available_code_actions
 5416                        .clone()
 5417                        .and_then(|(location, code_actions)| {
 5418                            let snapshot = location.buffer.read(cx).snapshot();
 5419                            let point_range = location.range.to_point(&snapshot);
 5420                            let point_range = point_range.start.row..=point_range.end.row;
 5421                            if point_range.contains(&buffer_row) {
 5422                                Some((location, code_actions))
 5423                            } else {
 5424                                None
 5425                            }
 5426                        })
 5427                        .unzip();
 5428                    let buffer_id = buffer.read(cx).remote_id();
 5429                    let tasks = editor
 5430                        .tasks
 5431                        .get(&(buffer_id, buffer_row))
 5432                        .map(|t| Arc::new(t.to_owned()));
 5433                    if tasks.is_none() && code_actions.is_none() {
 5434                        return None;
 5435                    }
 5436
 5437                    editor.completion_tasks.clear();
 5438                    editor.discard_inline_completion(false, cx);
 5439                    let task_context =
 5440                        tasks
 5441                            .as_ref()
 5442                            .zip(editor.project.clone())
 5443                            .map(|(tasks, project)| {
 5444                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5445                            });
 5446
 5447                    Some(cx.spawn_in(window, async move |editor, cx| {
 5448                        let task_context = match task_context {
 5449                            Some(task_context) => task_context.await,
 5450                            None => None,
 5451                        };
 5452                        let resolved_tasks =
 5453                            tasks
 5454                                .zip(task_context.clone())
 5455                                .map(|(tasks, task_context)| ResolvedTasks {
 5456                                    templates: tasks.resolve(&task_context).collect(),
 5457                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5458                                        multibuffer_point.row,
 5459                                        tasks.column,
 5460                                    )),
 5461                                });
 5462                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5463                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5464                                maybe!({
 5465                                    let project = editor.project.as_ref()?;
 5466                                    let dap_store = project.read(cx).dap_store();
 5467                                    let mut scenarios = vec![];
 5468                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5469                                    let buffer = buffer.read(cx);
 5470                                    let language = buffer.language()?;
 5471                                    let file = buffer.file();
 5472                                    let debug_adapter =
 5473                                        language_settings(language.name().into(), file, cx)
 5474                                            .debuggers
 5475                                            .first()
 5476                                            .map(SharedString::from)
 5477                                            .or_else(|| {
 5478                                                language
 5479                                                    .config()
 5480                                                    .debuggers
 5481                                                    .first()
 5482                                                    .map(SharedString::from)
 5483                                            })?;
 5484
 5485                                    dap_store.update(cx, |dap_store, cx| {
 5486                                        for (_, task) in &resolved_tasks.templates {
 5487                                            if let Some(scenario) = dap_store
 5488                                                .debug_scenario_for_build_task(
 5489                                                    task.original_task().clone(),
 5490                                                    debug_adapter.clone().into(),
 5491                                                    task.display_label().to_owned().into(),
 5492                                                    cx,
 5493                                                )
 5494                                            {
 5495                                                scenarios.push(scenario);
 5496                                            }
 5497                                        }
 5498                                    });
 5499                                    Some(scenarios)
 5500                                })
 5501                                .unwrap_or_default()
 5502                            } else {
 5503                                vec![]
 5504                            }
 5505                        })?;
 5506                        let spawn_straight_away = quick_launch
 5507                            && resolved_tasks
 5508                                .as_ref()
 5509                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5510                            && code_actions
 5511                                .as_ref()
 5512                                .map_or(true, |actions| actions.is_empty())
 5513                            && debug_scenarios.is_empty();
 5514                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5515                            crate::hover_popover::hide_hover(editor, cx);
 5516                            *editor.context_menu.borrow_mut() =
 5517                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5518                                    buffer,
 5519                                    actions: CodeActionContents::new(
 5520                                        resolved_tasks,
 5521                                        code_actions,
 5522                                        debug_scenarios,
 5523                                        task_context.unwrap_or_default(),
 5524                                    ),
 5525                                    selected_item: Default::default(),
 5526                                    scroll_handle: UniformListScrollHandle::default(),
 5527                                    deployed_from_indicator,
 5528                                }));
 5529                            if spawn_straight_away {
 5530                                if let Some(task) = editor.confirm_code_action(
 5531                                    &ConfirmCodeAction { item_ix: Some(0) },
 5532                                    window,
 5533                                    cx,
 5534                                ) {
 5535                                    cx.notify();
 5536                                    return task;
 5537                                }
 5538                            }
 5539                            cx.notify();
 5540                            Task::ready(Ok(()))
 5541                        }) {
 5542                            task.await
 5543                        } else {
 5544                            Ok(())
 5545                        }
 5546                    }))
 5547                } else {
 5548                    Some(Task::ready(Ok(())))
 5549                }
 5550            })?;
 5551            if let Some(task) = spawned_test_task {
 5552                task.await?;
 5553            }
 5554
 5555            anyhow::Ok(())
 5556        })
 5557        .detach_and_log_err(cx);
 5558    }
 5559
 5560    pub fn confirm_code_action(
 5561        &mut self,
 5562        action: &ConfirmCodeAction,
 5563        window: &mut Window,
 5564        cx: &mut Context<Self>,
 5565    ) -> Option<Task<Result<()>>> {
 5566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5567
 5568        let actions_menu =
 5569            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5570                menu
 5571            } else {
 5572                return None;
 5573            };
 5574
 5575        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5576        let action = actions_menu.actions.get(action_ix)?;
 5577        let title = action.label();
 5578        let buffer = actions_menu.buffer;
 5579        let workspace = self.workspace()?;
 5580
 5581        match action {
 5582            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5583                workspace.update(cx, |workspace, cx| {
 5584                    workspace.schedule_resolved_task(
 5585                        task_source_kind,
 5586                        resolved_task,
 5587                        false,
 5588                        window,
 5589                        cx,
 5590                    );
 5591
 5592                    Some(Task::ready(Ok(())))
 5593                })
 5594            }
 5595            CodeActionsItem::CodeAction {
 5596                excerpt_id,
 5597                action,
 5598                provider,
 5599            } => {
 5600                let apply_code_action =
 5601                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5602                let workspace = workspace.downgrade();
 5603                Some(cx.spawn_in(window, async move |editor, cx| {
 5604                    let project_transaction = apply_code_action.await?;
 5605                    Self::open_project_transaction(
 5606                        &editor,
 5607                        workspace,
 5608                        project_transaction,
 5609                        title,
 5610                        cx,
 5611                    )
 5612                    .await
 5613                }))
 5614            }
 5615            CodeActionsItem::DebugScenario(scenario) => {
 5616                let context = actions_menu.actions.context.clone();
 5617
 5618                workspace.update(cx, |workspace, cx| {
 5619                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5620                });
 5621                Some(Task::ready(Ok(())))
 5622            }
 5623        }
 5624    }
 5625
 5626    pub async fn open_project_transaction(
 5627        this: &WeakEntity<Editor>,
 5628        workspace: WeakEntity<Workspace>,
 5629        transaction: ProjectTransaction,
 5630        title: String,
 5631        cx: &mut AsyncWindowContext,
 5632    ) -> Result<()> {
 5633        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5634        cx.update(|_, cx| {
 5635            entries.sort_unstable_by_key(|(buffer, _)| {
 5636                buffer.read(cx).file().map(|f| f.path().clone())
 5637            });
 5638        })?;
 5639
 5640        // If the project transaction's edits are all contained within this editor, then
 5641        // avoid opening a new editor to display them.
 5642
 5643        if let Some((buffer, transaction)) = entries.first() {
 5644            if entries.len() == 1 {
 5645                let excerpt = this.update(cx, |editor, cx| {
 5646                    editor
 5647                        .buffer()
 5648                        .read(cx)
 5649                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5650                })?;
 5651                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5652                    if excerpted_buffer == *buffer {
 5653                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5654                            let excerpt_range = excerpt_range.to_offset(buffer);
 5655                            buffer
 5656                                .edited_ranges_for_transaction::<usize>(transaction)
 5657                                .all(|range| {
 5658                                    excerpt_range.start <= range.start
 5659                                        && excerpt_range.end >= range.end
 5660                                })
 5661                        })?;
 5662
 5663                        if all_edits_within_excerpt {
 5664                            return Ok(());
 5665                        }
 5666                    }
 5667                }
 5668            }
 5669        } else {
 5670            return Ok(());
 5671        }
 5672
 5673        let mut ranges_to_highlight = Vec::new();
 5674        let excerpt_buffer = cx.new(|cx| {
 5675            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5676            for (buffer_handle, transaction) in &entries {
 5677                let edited_ranges = buffer_handle
 5678                    .read(cx)
 5679                    .edited_ranges_for_transaction::<Point>(transaction)
 5680                    .collect::<Vec<_>>();
 5681                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5682                    PathKey::for_buffer(buffer_handle, cx),
 5683                    buffer_handle.clone(),
 5684                    edited_ranges,
 5685                    DEFAULT_MULTIBUFFER_CONTEXT,
 5686                    cx,
 5687                );
 5688
 5689                ranges_to_highlight.extend(ranges);
 5690            }
 5691            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5692            multibuffer
 5693        })?;
 5694
 5695        workspace.update_in(cx, |workspace, window, cx| {
 5696            let project = workspace.project().clone();
 5697            let editor =
 5698                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5699            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5700            editor.update(cx, |editor, cx| {
 5701                editor.highlight_background::<Self>(
 5702                    &ranges_to_highlight,
 5703                    |theme| theme.editor_highlighted_line_background,
 5704                    cx,
 5705                );
 5706            });
 5707        })?;
 5708
 5709        Ok(())
 5710    }
 5711
 5712    pub fn clear_code_action_providers(&mut self) {
 5713        self.code_action_providers.clear();
 5714        self.available_code_actions.take();
 5715    }
 5716
 5717    pub fn add_code_action_provider(
 5718        &mut self,
 5719        provider: Rc<dyn CodeActionProvider>,
 5720        window: &mut Window,
 5721        cx: &mut Context<Self>,
 5722    ) {
 5723        if self
 5724            .code_action_providers
 5725            .iter()
 5726            .any(|existing_provider| existing_provider.id() == provider.id())
 5727        {
 5728            return;
 5729        }
 5730
 5731        self.code_action_providers.push(provider);
 5732        self.refresh_code_actions(window, cx);
 5733    }
 5734
 5735    pub fn remove_code_action_provider(
 5736        &mut self,
 5737        id: Arc<str>,
 5738        window: &mut Window,
 5739        cx: &mut Context<Self>,
 5740    ) {
 5741        self.code_action_providers
 5742            .retain(|provider| provider.id() != id);
 5743        self.refresh_code_actions(window, cx);
 5744    }
 5745
 5746    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5747        let newest_selection = self.selections.newest_anchor().clone();
 5748        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5749        let buffer = self.buffer.read(cx);
 5750        if newest_selection.head().diff_base_anchor.is_some() {
 5751            return None;
 5752        }
 5753        let (start_buffer, start) =
 5754            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5755        let (end_buffer, end) =
 5756            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5757        if start_buffer != end_buffer {
 5758            return None;
 5759        }
 5760
 5761        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5762            cx.background_executor()
 5763                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5764                .await;
 5765
 5766            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5767                let providers = this.code_action_providers.clone();
 5768                let tasks = this
 5769                    .code_action_providers
 5770                    .iter()
 5771                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5772                    .collect::<Vec<_>>();
 5773                (providers, tasks)
 5774            })?;
 5775
 5776            let mut actions = Vec::new();
 5777            for (provider, provider_actions) in
 5778                providers.into_iter().zip(future::join_all(tasks).await)
 5779            {
 5780                if let Some(provider_actions) = provider_actions.log_err() {
 5781                    actions.extend(provider_actions.into_iter().map(|action| {
 5782                        AvailableCodeAction {
 5783                            excerpt_id: newest_selection.start.excerpt_id,
 5784                            action,
 5785                            provider: provider.clone(),
 5786                        }
 5787                    }));
 5788                }
 5789            }
 5790
 5791            this.update(cx, |this, cx| {
 5792                this.available_code_actions = if actions.is_empty() {
 5793                    None
 5794                } else {
 5795                    Some((
 5796                        Location {
 5797                            buffer: start_buffer,
 5798                            range: start..end,
 5799                        },
 5800                        actions.into(),
 5801                    ))
 5802                };
 5803                cx.notify();
 5804            })
 5805        }));
 5806        None
 5807    }
 5808
 5809    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5810        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5811            self.show_git_blame_inline = false;
 5812
 5813            self.show_git_blame_inline_delay_task =
 5814                Some(cx.spawn_in(window, async move |this, cx| {
 5815                    cx.background_executor().timer(delay).await;
 5816
 5817                    this.update(cx, |this, cx| {
 5818                        this.show_git_blame_inline = true;
 5819                        cx.notify();
 5820                    })
 5821                    .log_err();
 5822                }));
 5823        }
 5824    }
 5825
 5826    fn show_blame_popover(
 5827        &mut self,
 5828        blame_entry: &BlameEntry,
 5829        position: gpui::Point<Pixels>,
 5830        cx: &mut Context<Self>,
 5831    ) {
 5832        if let Some(state) = &mut self.inline_blame_popover {
 5833            state.hide_task.take();
 5834            cx.notify();
 5835        } else {
 5836            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5837            let show_task = cx.spawn(async move |editor, cx| {
 5838                cx.background_executor()
 5839                    .timer(std::time::Duration::from_millis(delay))
 5840                    .await;
 5841                editor
 5842                    .update(cx, |editor, cx| {
 5843                        if let Some(state) = &mut editor.inline_blame_popover {
 5844                            state.show_task = None;
 5845                            cx.notify();
 5846                        }
 5847                    })
 5848                    .ok();
 5849            });
 5850            let Some(blame) = self.blame.as_ref() else {
 5851                return;
 5852            };
 5853            let blame = blame.read(cx);
 5854            let details = blame.details_for_entry(&blame_entry);
 5855            let markdown = cx.new(|cx| {
 5856                Markdown::new(
 5857                    details
 5858                        .as_ref()
 5859                        .map(|message| message.message.clone())
 5860                        .unwrap_or_default(),
 5861                    None,
 5862                    None,
 5863                    cx,
 5864                )
 5865            });
 5866            self.inline_blame_popover = Some(InlineBlamePopover {
 5867                position,
 5868                show_task: Some(show_task),
 5869                hide_task: None,
 5870                popover_bounds: None,
 5871                popover_state: InlineBlamePopoverState {
 5872                    scroll_handle: ScrollHandle::new(),
 5873                    commit_message: details,
 5874                    markdown,
 5875                },
 5876            });
 5877        }
 5878    }
 5879
 5880    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5881        if let Some(state) = &mut self.inline_blame_popover {
 5882            if state.show_task.is_some() {
 5883                self.inline_blame_popover.take();
 5884                cx.notify();
 5885            } else {
 5886                let hide_task = cx.spawn(async move |editor, cx| {
 5887                    cx.background_executor()
 5888                        .timer(std::time::Duration::from_millis(100))
 5889                        .await;
 5890                    editor
 5891                        .update(cx, |editor, cx| {
 5892                            editor.inline_blame_popover.take();
 5893                            cx.notify();
 5894                        })
 5895                        .ok();
 5896                });
 5897                state.hide_task = Some(hide_task);
 5898            }
 5899        }
 5900    }
 5901
 5902    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5903        if self.pending_rename.is_some() {
 5904            return None;
 5905        }
 5906
 5907        let provider = self.semantics_provider.clone()?;
 5908        let buffer = self.buffer.read(cx);
 5909        let newest_selection = self.selections.newest_anchor().clone();
 5910        let cursor_position = newest_selection.head();
 5911        let (cursor_buffer, cursor_buffer_position) =
 5912            buffer.text_anchor_for_position(cursor_position, cx)?;
 5913        let (tail_buffer, tail_buffer_position) =
 5914            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5915        if cursor_buffer != tail_buffer {
 5916            return None;
 5917        }
 5918
 5919        let snapshot = cursor_buffer.read(cx).snapshot();
 5920        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5921        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5922        if start_word_range != end_word_range {
 5923            self.document_highlights_task.take();
 5924            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5925            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5926            return None;
 5927        }
 5928
 5929        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5930        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5931            cx.background_executor()
 5932                .timer(Duration::from_millis(debounce))
 5933                .await;
 5934
 5935            let highlights = if let Some(highlights) = cx
 5936                .update(|cx| {
 5937                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5938                })
 5939                .ok()
 5940                .flatten()
 5941            {
 5942                highlights.await.log_err()
 5943            } else {
 5944                None
 5945            };
 5946
 5947            if let Some(highlights) = highlights {
 5948                this.update(cx, |this, cx| {
 5949                    if this.pending_rename.is_some() {
 5950                        return;
 5951                    }
 5952
 5953                    let buffer_id = cursor_position.buffer_id;
 5954                    let buffer = this.buffer.read(cx);
 5955                    if !buffer
 5956                        .text_anchor_for_position(cursor_position, cx)
 5957                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5958                    {
 5959                        return;
 5960                    }
 5961
 5962                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5963                    let mut write_ranges = Vec::new();
 5964                    let mut read_ranges = Vec::new();
 5965                    for highlight in highlights {
 5966                        for (excerpt_id, excerpt_range) in
 5967                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5968                        {
 5969                            let start = highlight
 5970                                .range
 5971                                .start
 5972                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5973                            let end = highlight
 5974                                .range
 5975                                .end
 5976                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5977                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5978                                continue;
 5979                            }
 5980
 5981                            let range = Anchor {
 5982                                buffer_id,
 5983                                excerpt_id,
 5984                                text_anchor: start,
 5985                                diff_base_anchor: None,
 5986                            }..Anchor {
 5987                                buffer_id,
 5988                                excerpt_id,
 5989                                text_anchor: end,
 5990                                diff_base_anchor: None,
 5991                            };
 5992                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5993                                write_ranges.push(range);
 5994                            } else {
 5995                                read_ranges.push(range);
 5996                            }
 5997                        }
 5998                    }
 5999
 6000                    this.highlight_background::<DocumentHighlightRead>(
 6001                        &read_ranges,
 6002                        |theme| theme.editor_document_highlight_read_background,
 6003                        cx,
 6004                    );
 6005                    this.highlight_background::<DocumentHighlightWrite>(
 6006                        &write_ranges,
 6007                        |theme| theme.editor_document_highlight_write_background,
 6008                        cx,
 6009                    );
 6010                    cx.notify();
 6011                })
 6012                .log_err();
 6013            }
 6014        }));
 6015        None
 6016    }
 6017
 6018    fn prepare_highlight_query_from_selection(
 6019        &mut self,
 6020        cx: &mut Context<Editor>,
 6021    ) -> Option<(String, Range<Anchor>)> {
 6022        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6023            return None;
 6024        }
 6025        if !EditorSettings::get_global(cx).selection_highlight {
 6026            return None;
 6027        }
 6028        if self.selections.count() != 1 || self.selections.line_mode {
 6029            return None;
 6030        }
 6031        let selection = self.selections.newest::<Point>(cx);
 6032        if selection.is_empty() || selection.start.row != selection.end.row {
 6033            return None;
 6034        }
 6035        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6036        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6037        let query = multi_buffer_snapshot
 6038            .text_for_range(selection_anchor_range.clone())
 6039            .collect::<String>();
 6040        if query.trim().is_empty() {
 6041            return None;
 6042        }
 6043        Some((query, selection_anchor_range))
 6044    }
 6045
 6046    fn update_selection_occurrence_highlights(
 6047        &mut self,
 6048        query_text: String,
 6049        query_range: Range<Anchor>,
 6050        multi_buffer_range_to_query: Range<Point>,
 6051        use_debounce: bool,
 6052        window: &mut Window,
 6053        cx: &mut Context<Editor>,
 6054    ) -> Task<()> {
 6055        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6056        cx.spawn_in(window, async move |editor, cx| {
 6057            if use_debounce {
 6058                cx.background_executor()
 6059                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6060                    .await;
 6061            }
 6062            let match_task = cx.background_spawn(async move {
 6063                let buffer_ranges = multi_buffer_snapshot
 6064                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6065                    .into_iter()
 6066                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6067                let mut match_ranges = Vec::new();
 6068                let Ok(regex) = project::search::SearchQuery::text(
 6069                    query_text.clone(),
 6070                    false,
 6071                    false,
 6072                    false,
 6073                    Default::default(),
 6074                    Default::default(),
 6075                    false,
 6076                    None,
 6077                ) else {
 6078                    return Vec::default();
 6079                };
 6080                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6081                    match_ranges.extend(
 6082                        regex
 6083                            .search(&buffer_snapshot, Some(search_range.clone()))
 6084                            .await
 6085                            .into_iter()
 6086                            .filter_map(|match_range| {
 6087                                let match_start = buffer_snapshot
 6088                                    .anchor_after(search_range.start + match_range.start);
 6089                                let match_end = buffer_snapshot
 6090                                    .anchor_before(search_range.start + match_range.end);
 6091                                let match_anchor_range = Anchor::range_in_buffer(
 6092                                    excerpt_id,
 6093                                    buffer_snapshot.remote_id(),
 6094                                    match_start..match_end,
 6095                                );
 6096                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6097                            }),
 6098                    );
 6099                }
 6100                match_ranges
 6101            });
 6102            let match_ranges = match_task.await;
 6103            editor
 6104                .update_in(cx, |editor, _, cx| {
 6105                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6106                    if !match_ranges.is_empty() {
 6107                        editor.highlight_background::<SelectedTextHighlight>(
 6108                            &match_ranges,
 6109                            |theme| theme.editor_document_highlight_bracket_background,
 6110                            cx,
 6111                        )
 6112                    }
 6113                })
 6114                .log_err();
 6115        })
 6116    }
 6117
 6118    fn refresh_selected_text_highlights(
 6119        &mut self,
 6120        on_buffer_edit: bool,
 6121        window: &mut Window,
 6122        cx: &mut Context<Editor>,
 6123    ) {
 6124        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6125        else {
 6126            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6127            self.quick_selection_highlight_task.take();
 6128            self.debounced_selection_highlight_task.take();
 6129            return;
 6130        };
 6131        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6132        if on_buffer_edit
 6133            || self
 6134                .quick_selection_highlight_task
 6135                .as_ref()
 6136                .map_or(true, |(prev_anchor_range, _)| {
 6137                    prev_anchor_range != &query_range
 6138                })
 6139        {
 6140            let multi_buffer_visible_start = self
 6141                .scroll_manager
 6142                .anchor()
 6143                .anchor
 6144                .to_point(&multi_buffer_snapshot);
 6145            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6146                multi_buffer_visible_start
 6147                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6148                Bias::Left,
 6149            );
 6150            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6151            self.quick_selection_highlight_task = Some((
 6152                query_range.clone(),
 6153                self.update_selection_occurrence_highlights(
 6154                    query_text.clone(),
 6155                    query_range.clone(),
 6156                    multi_buffer_visible_range,
 6157                    false,
 6158                    window,
 6159                    cx,
 6160                ),
 6161            ));
 6162        }
 6163        if on_buffer_edit
 6164            || self
 6165                .debounced_selection_highlight_task
 6166                .as_ref()
 6167                .map_or(true, |(prev_anchor_range, _)| {
 6168                    prev_anchor_range != &query_range
 6169                })
 6170        {
 6171            let multi_buffer_start = multi_buffer_snapshot
 6172                .anchor_before(0)
 6173                .to_point(&multi_buffer_snapshot);
 6174            let multi_buffer_end = multi_buffer_snapshot
 6175                .anchor_after(multi_buffer_snapshot.len())
 6176                .to_point(&multi_buffer_snapshot);
 6177            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6178            self.debounced_selection_highlight_task = Some((
 6179                query_range.clone(),
 6180                self.update_selection_occurrence_highlights(
 6181                    query_text,
 6182                    query_range,
 6183                    multi_buffer_full_range,
 6184                    true,
 6185                    window,
 6186                    cx,
 6187                ),
 6188            ));
 6189        }
 6190    }
 6191
 6192    pub fn refresh_inline_completion(
 6193        &mut self,
 6194        debounce: bool,
 6195        user_requested: bool,
 6196        window: &mut Window,
 6197        cx: &mut Context<Self>,
 6198    ) -> Option<()> {
 6199        let provider = self.edit_prediction_provider()?;
 6200        let cursor = self.selections.newest_anchor().head();
 6201        let (buffer, cursor_buffer_position) =
 6202            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6203
 6204        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6205            self.discard_inline_completion(false, cx);
 6206            return None;
 6207        }
 6208
 6209        if !user_requested
 6210            && (!self.should_show_edit_predictions()
 6211                || !self.is_focused(window)
 6212                || buffer.read(cx).is_empty())
 6213        {
 6214            self.discard_inline_completion(false, cx);
 6215            return None;
 6216        }
 6217
 6218        self.update_visible_inline_completion(window, cx);
 6219        provider.refresh(
 6220            self.project.clone(),
 6221            buffer,
 6222            cursor_buffer_position,
 6223            debounce,
 6224            cx,
 6225        );
 6226        Some(())
 6227    }
 6228
 6229    fn show_edit_predictions_in_menu(&self) -> bool {
 6230        match self.edit_prediction_settings {
 6231            EditPredictionSettings::Disabled => false,
 6232            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6233        }
 6234    }
 6235
 6236    pub fn edit_predictions_enabled(&self) -> bool {
 6237        match self.edit_prediction_settings {
 6238            EditPredictionSettings::Disabled => false,
 6239            EditPredictionSettings::Enabled { .. } => true,
 6240        }
 6241    }
 6242
 6243    fn edit_prediction_requires_modifier(&self) -> bool {
 6244        match self.edit_prediction_settings {
 6245            EditPredictionSettings::Disabled => false,
 6246            EditPredictionSettings::Enabled {
 6247                preview_requires_modifier,
 6248                ..
 6249            } => preview_requires_modifier,
 6250        }
 6251    }
 6252
 6253    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6254        if self.edit_prediction_provider.is_none() {
 6255            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6256        } else {
 6257            let selection = self.selections.newest_anchor();
 6258            let cursor = selection.head();
 6259
 6260            if let Some((buffer, cursor_buffer_position)) =
 6261                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6262            {
 6263                self.edit_prediction_settings =
 6264                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6265            }
 6266        }
 6267    }
 6268
 6269    fn edit_prediction_settings_at_position(
 6270        &self,
 6271        buffer: &Entity<Buffer>,
 6272        buffer_position: language::Anchor,
 6273        cx: &App,
 6274    ) -> EditPredictionSettings {
 6275        if !self.mode.is_full()
 6276            || !self.show_inline_completions_override.unwrap_or(true)
 6277            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6278        {
 6279            return EditPredictionSettings::Disabled;
 6280        }
 6281
 6282        let buffer = buffer.read(cx);
 6283
 6284        let file = buffer.file();
 6285
 6286        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6287            return EditPredictionSettings::Disabled;
 6288        };
 6289
 6290        let by_provider = matches!(
 6291            self.menu_inline_completions_policy,
 6292            MenuInlineCompletionsPolicy::ByProvider
 6293        );
 6294
 6295        let show_in_menu = by_provider
 6296            && self
 6297                .edit_prediction_provider
 6298                .as_ref()
 6299                .map_or(false, |provider| {
 6300                    provider.provider.show_completions_in_menu()
 6301                });
 6302
 6303        let preview_requires_modifier =
 6304            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6305
 6306        EditPredictionSettings::Enabled {
 6307            show_in_menu,
 6308            preview_requires_modifier,
 6309        }
 6310    }
 6311
 6312    fn should_show_edit_predictions(&self) -> bool {
 6313        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6314    }
 6315
 6316    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6317        matches!(
 6318            self.edit_prediction_preview,
 6319            EditPredictionPreview::Active { .. }
 6320        )
 6321    }
 6322
 6323    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6324        let cursor = self.selections.newest_anchor().head();
 6325        if let Some((buffer, cursor_position)) =
 6326            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6327        {
 6328            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6329        } else {
 6330            false
 6331        }
 6332    }
 6333
 6334    pub fn supports_minimap(&self, cx: &App) -> bool {
 6335        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6336    }
 6337
 6338    fn edit_predictions_enabled_in_buffer(
 6339        &self,
 6340        buffer: &Entity<Buffer>,
 6341        buffer_position: language::Anchor,
 6342        cx: &App,
 6343    ) -> bool {
 6344        maybe!({
 6345            if self.read_only(cx) {
 6346                return Some(false);
 6347            }
 6348            let provider = self.edit_prediction_provider()?;
 6349            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6350                return Some(false);
 6351            }
 6352            let buffer = buffer.read(cx);
 6353            let Some(file) = buffer.file() else {
 6354                return Some(true);
 6355            };
 6356            let settings = all_language_settings(Some(file), cx);
 6357            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6358        })
 6359        .unwrap_or(false)
 6360    }
 6361
 6362    fn cycle_inline_completion(
 6363        &mut self,
 6364        direction: Direction,
 6365        window: &mut Window,
 6366        cx: &mut Context<Self>,
 6367    ) -> Option<()> {
 6368        let provider = self.edit_prediction_provider()?;
 6369        let cursor = self.selections.newest_anchor().head();
 6370        let (buffer, cursor_buffer_position) =
 6371            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6372        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6373            return None;
 6374        }
 6375
 6376        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6377        self.update_visible_inline_completion(window, cx);
 6378
 6379        Some(())
 6380    }
 6381
 6382    pub fn show_inline_completion(
 6383        &mut self,
 6384        _: &ShowEditPrediction,
 6385        window: &mut Window,
 6386        cx: &mut Context<Self>,
 6387    ) {
 6388        if !self.has_active_inline_completion() {
 6389            self.refresh_inline_completion(false, true, window, cx);
 6390            return;
 6391        }
 6392
 6393        self.update_visible_inline_completion(window, cx);
 6394    }
 6395
 6396    pub fn display_cursor_names(
 6397        &mut self,
 6398        _: &DisplayCursorNames,
 6399        window: &mut Window,
 6400        cx: &mut Context<Self>,
 6401    ) {
 6402        self.show_cursor_names(window, cx);
 6403    }
 6404
 6405    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6406        self.show_cursor_names = true;
 6407        cx.notify();
 6408        cx.spawn_in(window, async move |this, cx| {
 6409            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6410            this.update(cx, |this, cx| {
 6411                this.show_cursor_names = false;
 6412                cx.notify()
 6413            })
 6414            .ok()
 6415        })
 6416        .detach();
 6417    }
 6418
 6419    pub fn next_edit_prediction(
 6420        &mut self,
 6421        _: &NextEditPrediction,
 6422        window: &mut Window,
 6423        cx: &mut Context<Self>,
 6424    ) {
 6425        if self.has_active_inline_completion() {
 6426            self.cycle_inline_completion(Direction::Next, window, cx);
 6427        } else {
 6428            let is_copilot_disabled = self
 6429                .refresh_inline_completion(false, true, window, cx)
 6430                .is_none();
 6431            if is_copilot_disabled {
 6432                cx.propagate();
 6433            }
 6434        }
 6435    }
 6436
 6437    pub fn previous_edit_prediction(
 6438        &mut self,
 6439        _: &PreviousEditPrediction,
 6440        window: &mut Window,
 6441        cx: &mut Context<Self>,
 6442    ) {
 6443        if self.has_active_inline_completion() {
 6444            self.cycle_inline_completion(Direction::Prev, window, cx);
 6445        } else {
 6446            let is_copilot_disabled = self
 6447                .refresh_inline_completion(false, true, window, cx)
 6448                .is_none();
 6449            if is_copilot_disabled {
 6450                cx.propagate();
 6451            }
 6452        }
 6453    }
 6454
 6455    pub fn accept_edit_prediction(
 6456        &mut self,
 6457        _: &AcceptEditPrediction,
 6458        window: &mut Window,
 6459        cx: &mut Context<Self>,
 6460    ) {
 6461        if self.show_edit_predictions_in_menu() {
 6462            self.hide_context_menu(window, cx);
 6463        }
 6464
 6465        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6466            return;
 6467        };
 6468
 6469        self.report_inline_completion_event(
 6470            active_inline_completion.completion_id.clone(),
 6471            true,
 6472            cx,
 6473        );
 6474
 6475        match &active_inline_completion.completion {
 6476            InlineCompletion::Move { target, .. } => {
 6477                let target = *target;
 6478
 6479                if let Some(position_map) = &self.last_position_map {
 6480                    if position_map
 6481                        .visible_row_range
 6482                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6483                        || !self.edit_prediction_requires_modifier()
 6484                    {
 6485                        self.unfold_ranges(&[target..target], true, false, cx);
 6486                        // Note that this is also done in vim's handler of the Tab action.
 6487                        self.change_selections(
 6488                            Some(Autoscroll::newest()),
 6489                            window,
 6490                            cx,
 6491                            |selections| {
 6492                                selections.select_anchor_ranges([target..target]);
 6493                            },
 6494                        );
 6495                        self.clear_row_highlights::<EditPredictionPreview>();
 6496
 6497                        self.edit_prediction_preview
 6498                            .set_previous_scroll_position(None);
 6499                    } else {
 6500                        self.edit_prediction_preview
 6501                            .set_previous_scroll_position(Some(
 6502                                position_map.snapshot.scroll_anchor,
 6503                            ));
 6504
 6505                        self.highlight_rows::<EditPredictionPreview>(
 6506                            target..target,
 6507                            cx.theme().colors().editor_highlighted_line_background,
 6508                            RowHighlightOptions {
 6509                                autoscroll: true,
 6510                                ..Default::default()
 6511                            },
 6512                            cx,
 6513                        );
 6514                        self.request_autoscroll(Autoscroll::fit(), cx);
 6515                    }
 6516                }
 6517            }
 6518            InlineCompletion::Edit { edits, .. } => {
 6519                if let Some(provider) = self.edit_prediction_provider() {
 6520                    provider.accept(cx);
 6521                }
 6522
 6523                let snapshot = self.buffer.read(cx).snapshot(cx);
 6524                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6525
 6526                self.buffer.update(cx, |buffer, cx| {
 6527                    buffer.edit(edits.iter().cloned(), None, cx)
 6528                });
 6529
 6530                self.change_selections(None, window, cx, |s| {
 6531                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6532                });
 6533
 6534                self.update_visible_inline_completion(window, cx);
 6535                if self.active_inline_completion.is_none() {
 6536                    self.refresh_inline_completion(true, true, window, cx);
 6537                }
 6538
 6539                cx.notify();
 6540            }
 6541        }
 6542
 6543        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6544    }
 6545
 6546    pub fn accept_partial_inline_completion(
 6547        &mut self,
 6548        _: &AcceptPartialEditPrediction,
 6549        window: &mut Window,
 6550        cx: &mut Context<Self>,
 6551    ) {
 6552        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6553            return;
 6554        };
 6555        if self.selections.count() != 1 {
 6556            return;
 6557        }
 6558
 6559        self.report_inline_completion_event(
 6560            active_inline_completion.completion_id.clone(),
 6561            true,
 6562            cx,
 6563        );
 6564
 6565        match &active_inline_completion.completion {
 6566            InlineCompletion::Move { target, .. } => {
 6567                let target = *target;
 6568                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6569                    selections.select_anchor_ranges([target..target]);
 6570                });
 6571            }
 6572            InlineCompletion::Edit { edits, .. } => {
 6573                // Find an insertion that starts at the cursor position.
 6574                let snapshot = self.buffer.read(cx).snapshot(cx);
 6575                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6576                let insertion = edits.iter().find_map(|(range, text)| {
 6577                    let range = range.to_offset(&snapshot);
 6578                    if range.is_empty() && range.start == cursor_offset {
 6579                        Some(text)
 6580                    } else {
 6581                        None
 6582                    }
 6583                });
 6584
 6585                if let Some(text) = insertion {
 6586                    let mut partial_completion = text
 6587                        .chars()
 6588                        .by_ref()
 6589                        .take_while(|c| c.is_alphabetic())
 6590                        .collect::<String>();
 6591                    if partial_completion.is_empty() {
 6592                        partial_completion = text
 6593                            .chars()
 6594                            .by_ref()
 6595                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6596                            .collect::<String>();
 6597                    }
 6598
 6599                    cx.emit(EditorEvent::InputHandled {
 6600                        utf16_range_to_replace: None,
 6601                        text: partial_completion.clone().into(),
 6602                    });
 6603
 6604                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6605
 6606                    self.refresh_inline_completion(true, true, window, cx);
 6607                    cx.notify();
 6608                } else {
 6609                    self.accept_edit_prediction(&Default::default(), window, cx);
 6610                }
 6611            }
 6612        }
 6613    }
 6614
 6615    fn discard_inline_completion(
 6616        &mut self,
 6617        should_report_inline_completion_event: bool,
 6618        cx: &mut Context<Self>,
 6619    ) -> bool {
 6620        if should_report_inline_completion_event {
 6621            let completion_id = self
 6622                .active_inline_completion
 6623                .as_ref()
 6624                .and_then(|active_completion| active_completion.completion_id.clone());
 6625
 6626            self.report_inline_completion_event(completion_id, false, cx);
 6627        }
 6628
 6629        if let Some(provider) = self.edit_prediction_provider() {
 6630            provider.discard(cx);
 6631        }
 6632
 6633        self.take_active_inline_completion(cx)
 6634    }
 6635
 6636    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6637        let Some(provider) = self.edit_prediction_provider() else {
 6638            return;
 6639        };
 6640
 6641        let Some((_, buffer, _)) = self
 6642            .buffer
 6643            .read(cx)
 6644            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6645        else {
 6646            return;
 6647        };
 6648
 6649        let extension = buffer
 6650            .read(cx)
 6651            .file()
 6652            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6653
 6654        let event_type = match accepted {
 6655            true => "Edit Prediction Accepted",
 6656            false => "Edit Prediction Discarded",
 6657        };
 6658        telemetry::event!(
 6659            event_type,
 6660            provider = provider.name(),
 6661            prediction_id = id,
 6662            suggestion_accepted = accepted,
 6663            file_extension = extension,
 6664        );
 6665    }
 6666
 6667    pub fn has_active_inline_completion(&self) -> bool {
 6668        self.active_inline_completion.is_some()
 6669    }
 6670
 6671    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6672        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6673            return false;
 6674        };
 6675
 6676        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6677        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6678        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6679        true
 6680    }
 6681
 6682    /// Returns true when we're displaying the edit prediction popover below the cursor
 6683    /// like we are not previewing and the LSP autocomplete menu is visible
 6684    /// or we are in `when_holding_modifier` mode.
 6685    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6686        if self.edit_prediction_preview_is_active()
 6687            || !self.show_edit_predictions_in_menu()
 6688            || !self.edit_predictions_enabled()
 6689        {
 6690            return false;
 6691        }
 6692
 6693        if self.has_visible_completions_menu() {
 6694            return true;
 6695        }
 6696
 6697        has_completion && self.edit_prediction_requires_modifier()
 6698    }
 6699
 6700    fn handle_modifiers_changed(
 6701        &mut self,
 6702        modifiers: Modifiers,
 6703        position_map: &PositionMap,
 6704        window: &mut Window,
 6705        cx: &mut Context<Self>,
 6706    ) {
 6707        if self.show_edit_predictions_in_menu() {
 6708            self.update_edit_prediction_preview(&modifiers, window, cx);
 6709        }
 6710
 6711        self.update_selection_mode(&modifiers, position_map, window, cx);
 6712
 6713        let mouse_position = window.mouse_position();
 6714        if !position_map.text_hitbox.is_hovered(window) {
 6715            return;
 6716        }
 6717
 6718        self.update_hovered_link(
 6719            position_map.point_for_position(mouse_position),
 6720            &position_map.snapshot,
 6721            modifiers,
 6722            window,
 6723            cx,
 6724        )
 6725    }
 6726
 6727    fn update_selection_mode(
 6728        &mut self,
 6729        modifiers: &Modifiers,
 6730        position_map: &PositionMap,
 6731        window: &mut Window,
 6732        cx: &mut Context<Self>,
 6733    ) {
 6734        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6735            return;
 6736        }
 6737
 6738        let mouse_position = window.mouse_position();
 6739        let point_for_position = position_map.point_for_position(mouse_position);
 6740        let position = point_for_position.previous_valid;
 6741
 6742        self.select(
 6743            SelectPhase::BeginColumnar {
 6744                position,
 6745                reset: false,
 6746                goal_column: point_for_position.exact_unclipped.column(),
 6747            },
 6748            window,
 6749            cx,
 6750        );
 6751    }
 6752
 6753    fn update_edit_prediction_preview(
 6754        &mut self,
 6755        modifiers: &Modifiers,
 6756        window: &mut Window,
 6757        cx: &mut Context<Self>,
 6758    ) {
 6759        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6760        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6761            return;
 6762        };
 6763
 6764        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6765            if matches!(
 6766                self.edit_prediction_preview,
 6767                EditPredictionPreview::Inactive { .. }
 6768            ) {
 6769                self.edit_prediction_preview = EditPredictionPreview::Active {
 6770                    previous_scroll_position: None,
 6771                    since: Instant::now(),
 6772                };
 6773
 6774                self.update_visible_inline_completion(window, cx);
 6775                cx.notify();
 6776            }
 6777        } else if let EditPredictionPreview::Active {
 6778            previous_scroll_position,
 6779            since,
 6780        } = self.edit_prediction_preview
 6781        {
 6782            if let (Some(previous_scroll_position), Some(position_map)) =
 6783                (previous_scroll_position, self.last_position_map.as_ref())
 6784            {
 6785                self.set_scroll_position(
 6786                    previous_scroll_position
 6787                        .scroll_position(&position_map.snapshot.display_snapshot),
 6788                    window,
 6789                    cx,
 6790                );
 6791            }
 6792
 6793            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6794                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6795            };
 6796            self.clear_row_highlights::<EditPredictionPreview>();
 6797            self.update_visible_inline_completion(window, cx);
 6798            cx.notify();
 6799        }
 6800    }
 6801
 6802    fn update_visible_inline_completion(
 6803        &mut self,
 6804        _window: &mut Window,
 6805        cx: &mut Context<Self>,
 6806    ) -> Option<()> {
 6807        let selection = self.selections.newest_anchor();
 6808        let cursor = selection.head();
 6809        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6810        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6811        let excerpt_id = cursor.excerpt_id;
 6812
 6813        let show_in_menu = self.show_edit_predictions_in_menu();
 6814        let completions_menu_has_precedence = !show_in_menu
 6815            && (self.context_menu.borrow().is_some()
 6816                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6817
 6818        if completions_menu_has_precedence
 6819            || !offset_selection.is_empty()
 6820            || self
 6821                .active_inline_completion
 6822                .as_ref()
 6823                .map_or(false, |completion| {
 6824                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6825                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6826                    !invalidation_range.contains(&offset_selection.head())
 6827                })
 6828        {
 6829            self.discard_inline_completion(false, cx);
 6830            return None;
 6831        }
 6832
 6833        self.take_active_inline_completion(cx);
 6834        let Some(provider) = self.edit_prediction_provider() else {
 6835            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6836            return None;
 6837        };
 6838
 6839        let (buffer, cursor_buffer_position) =
 6840            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6841
 6842        self.edit_prediction_settings =
 6843            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6844
 6845        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6846
 6847        if self.edit_prediction_indent_conflict {
 6848            let cursor_point = cursor.to_point(&multibuffer);
 6849
 6850            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6851
 6852            if let Some((_, indent)) = indents.iter().next() {
 6853                if indent.len == cursor_point.column {
 6854                    self.edit_prediction_indent_conflict = false;
 6855                }
 6856            }
 6857        }
 6858
 6859        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6860        let edits = inline_completion
 6861            .edits
 6862            .into_iter()
 6863            .flat_map(|(range, new_text)| {
 6864                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6865                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6866                Some((start..end, new_text))
 6867            })
 6868            .collect::<Vec<_>>();
 6869        if edits.is_empty() {
 6870            return None;
 6871        }
 6872
 6873        let first_edit_start = edits.first().unwrap().0.start;
 6874        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6875        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6876
 6877        let last_edit_end = edits.last().unwrap().0.end;
 6878        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6879        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6880
 6881        let cursor_row = cursor.to_point(&multibuffer).row;
 6882
 6883        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6884
 6885        let mut inlay_ids = Vec::new();
 6886        let invalidation_row_range;
 6887        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6888            Some(cursor_row..edit_end_row)
 6889        } else if cursor_row > edit_end_row {
 6890            Some(edit_start_row..cursor_row)
 6891        } else {
 6892            None
 6893        };
 6894        let is_move =
 6895            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6896        let completion = if is_move {
 6897            invalidation_row_range =
 6898                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6899            let target = first_edit_start;
 6900            InlineCompletion::Move { target, snapshot }
 6901        } else {
 6902            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6903                && !self.inline_completions_hidden_for_vim_mode;
 6904
 6905            if show_completions_in_buffer {
 6906                if edits
 6907                    .iter()
 6908                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6909                {
 6910                    let mut inlays = Vec::new();
 6911                    for (range, new_text) in &edits {
 6912                        let inlay = Inlay::inline_completion(
 6913                            post_inc(&mut self.next_inlay_id),
 6914                            range.start,
 6915                            new_text.as_str(),
 6916                        );
 6917                        inlay_ids.push(inlay.id);
 6918                        inlays.push(inlay);
 6919                    }
 6920
 6921                    self.splice_inlays(&[], inlays, cx);
 6922                } else {
 6923                    let background_color = cx.theme().status().deleted_background;
 6924                    self.highlight_text::<InlineCompletionHighlight>(
 6925                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6926                        HighlightStyle {
 6927                            background_color: Some(background_color),
 6928                            ..Default::default()
 6929                        },
 6930                        cx,
 6931                    );
 6932                }
 6933            }
 6934
 6935            invalidation_row_range = edit_start_row..edit_end_row;
 6936
 6937            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6938                if provider.show_tab_accept_marker() {
 6939                    EditDisplayMode::TabAccept
 6940                } else {
 6941                    EditDisplayMode::Inline
 6942                }
 6943            } else {
 6944                EditDisplayMode::DiffPopover
 6945            };
 6946
 6947            InlineCompletion::Edit {
 6948                edits,
 6949                edit_preview: inline_completion.edit_preview,
 6950                display_mode,
 6951                snapshot,
 6952            }
 6953        };
 6954
 6955        let invalidation_range = multibuffer
 6956            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6957            ..multibuffer.anchor_after(Point::new(
 6958                invalidation_row_range.end,
 6959                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6960            ));
 6961
 6962        self.stale_inline_completion_in_menu = None;
 6963        self.active_inline_completion = Some(InlineCompletionState {
 6964            inlay_ids,
 6965            completion,
 6966            completion_id: inline_completion.id,
 6967            invalidation_range,
 6968        });
 6969
 6970        cx.notify();
 6971
 6972        Some(())
 6973    }
 6974
 6975    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6976        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6977    }
 6978
 6979    fn clear_tasks(&mut self) {
 6980        self.tasks.clear()
 6981    }
 6982
 6983    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6984        if self.tasks.insert(key, value).is_some() {
 6985            // This case should hopefully be rare, but just in case...
 6986            log::error!(
 6987                "multiple different run targets found on a single line, only the last target will be rendered"
 6988            )
 6989        }
 6990    }
 6991
 6992    /// Get all display points of breakpoints that will be rendered within editor
 6993    ///
 6994    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6995    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6996    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6997    fn active_breakpoints(
 6998        &self,
 6999        range: Range<DisplayRow>,
 7000        window: &mut Window,
 7001        cx: &mut Context<Self>,
 7002    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7003        let mut breakpoint_display_points = HashMap::default();
 7004
 7005        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7006            return breakpoint_display_points;
 7007        };
 7008
 7009        let snapshot = self.snapshot(window, cx);
 7010
 7011        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7012        let Some(project) = self.project.as_ref() else {
 7013            return breakpoint_display_points;
 7014        };
 7015
 7016        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7017            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7018
 7019        for (buffer_snapshot, range, excerpt_id) in
 7020            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7021        {
 7022            let Some(buffer) = project.read_with(cx, |this, cx| {
 7023                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7024            }) else {
 7025                continue;
 7026            };
 7027            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7028                &buffer,
 7029                Some(
 7030                    buffer_snapshot.anchor_before(range.start)
 7031                        ..buffer_snapshot.anchor_after(range.end),
 7032                ),
 7033                buffer_snapshot,
 7034                cx,
 7035            );
 7036            for (breakpoint, state) in breakpoints {
 7037                let multi_buffer_anchor =
 7038                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7039                let position = multi_buffer_anchor
 7040                    .to_point(&multi_buffer_snapshot)
 7041                    .to_display_point(&snapshot);
 7042
 7043                breakpoint_display_points.insert(
 7044                    position.row(),
 7045                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7046                );
 7047            }
 7048        }
 7049
 7050        breakpoint_display_points
 7051    }
 7052
 7053    fn breakpoint_context_menu(
 7054        &self,
 7055        anchor: Anchor,
 7056        window: &mut Window,
 7057        cx: &mut Context<Self>,
 7058    ) -> Entity<ui::ContextMenu> {
 7059        let weak_editor = cx.weak_entity();
 7060        let focus_handle = self.focus_handle(cx);
 7061
 7062        let row = self
 7063            .buffer
 7064            .read(cx)
 7065            .snapshot(cx)
 7066            .summary_for_anchor::<Point>(&anchor)
 7067            .row;
 7068
 7069        let breakpoint = self
 7070            .breakpoint_at_row(row, window, cx)
 7071            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7072
 7073        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7074            "Edit Log Breakpoint"
 7075        } else {
 7076            "Set Log Breakpoint"
 7077        };
 7078
 7079        let condition_breakpoint_msg = if breakpoint
 7080            .as_ref()
 7081            .is_some_and(|bp| bp.1.condition.is_some())
 7082        {
 7083            "Edit Condition Breakpoint"
 7084        } else {
 7085            "Set Condition Breakpoint"
 7086        };
 7087
 7088        let hit_condition_breakpoint_msg = if breakpoint
 7089            .as_ref()
 7090            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7091        {
 7092            "Edit Hit Condition Breakpoint"
 7093        } else {
 7094            "Set Hit Condition Breakpoint"
 7095        };
 7096
 7097        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7098            "Unset Breakpoint"
 7099        } else {
 7100            "Set Breakpoint"
 7101        };
 7102
 7103        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7104            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7105
 7106        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7107            BreakpointState::Enabled => Some("Disable"),
 7108            BreakpointState::Disabled => Some("Enable"),
 7109        });
 7110
 7111        let (anchor, breakpoint) =
 7112            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7113
 7114        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7115            menu.on_blur_subscription(Subscription::new(|| {}))
 7116                .context(focus_handle)
 7117                .when(run_to_cursor, |this| {
 7118                    let weak_editor = weak_editor.clone();
 7119                    this.entry("Run to cursor", None, move |window, cx| {
 7120                        weak_editor
 7121                            .update(cx, |editor, cx| {
 7122                                editor.change_selections(None, window, cx, |s| {
 7123                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7124                                });
 7125                            })
 7126                            .ok();
 7127
 7128                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7129                    })
 7130                    .separator()
 7131                })
 7132                .when_some(toggle_state_msg, |this, msg| {
 7133                    this.entry(msg, None, {
 7134                        let weak_editor = weak_editor.clone();
 7135                        let breakpoint = breakpoint.clone();
 7136                        move |_window, cx| {
 7137                            weak_editor
 7138                                .update(cx, |this, cx| {
 7139                                    this.edit_breakpoint_at_anchor(
 7140                                        anchor,
 7141                                        breakpoint.as_ref().clone(),
 7142                                        BreakpointEditAction::InvertState,
 7143                                        cx,
 7144                                    );
 7145                                })
 7146                                .log_err();
 7147                        }
 7148                    })
 7149                })
 7150                .entry(set_breakpoint_msg, None, {
 7151                    let weak_editor = weak_editor.clone();
 7152                    let breakpoint = breakpoint.clone();
 7153                    move |_window, cx| {
 7154                        weak_editor
 7155                            .update(cx, |this, cx| {
 7156                                this.edit_breakpoint_at_anchor(
 7157                                    anchor,
 7158                                    breakpoint.as_ref().clone(),
 7159                                    BreakpointEditAction::Toggle,
 7160                                    cx,
 7161                                );
 7162                            })
 7163                            .log_err();
 7164                    }
 7165                })
 7166                .entry(log_breakpoint_msg, None, {
 7167                    let breakpoint = breakpoint.clone();
 7168                    let weak_editor = weak_editor.clone();
 7169                    move |window, cx| {
 7170                        weak_editor
 7171                            .update(cx, |this, cx| {
 7172                                this.add_edit_breakpoint_block(
 7173                                    anchor,
 7174                                    breakpoint.as_ref(),
 7175                                    BreakpointPromptEditAction::Log,
 7176                                    window,
 7177                                    cx,
 7178                                );
 7179                            })
 7180                            .log_err();
 7181                    }
 7182                })
 7183                .entry(condition_breakpoint_msg, None, {
 7184                    let breakpoint = breakpoint.clone();
 7185                    let weak_editor = weak_editor.clone();
 7186                    move |window, cx| {
 7187                        weak_editor
 7188                            .update(cx, |this, cx| {
 7189                                this.add_edit_breakpoint_block(
 7190                                    anchor,
 7191                                    breakpoint.as_ref(),
 7192                                    BreakpointPromptEditAction::Condition,
 7193                                    window,
 7194                                    cx,
 7195                                );
 7196                            })
 7197                            .log_err();
 7198                    }
 7199                })
 7200                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7201                    weak_editor
 7202                        .update(cx, |this, cx| {
 7203                            this.add_edit_breakpoint_block(
 7204                                anchor,
 7205                                breakpoint.as_ref(),
 7206                                BreakpointPromptEditAction::HitCondition,
 7207                                window,
 7208                                cx,
 7209                            );
 7210                        })
 7211                        .log_err();
 7212                })
 7213        })
 7214    }
 7215
 7216    fn render_breakpoint(
 7217        &self,
 7218        position: Anchor,
 7219        row: DisplayRow,
 7220        breakpoint: &Breakpoint,
 7221        state: Option<BreakpointSessionState>,
 7222        cx: &mut Context<Self>,
 7223    ) -> IconButton {
 7224        let is_rejected = state.is_some_and(|s| !s.verified);
 7225        // Is it a breakpoint that shows up when hovering over gutter?
 7226        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7227            (false, false),
 7228            |PhantomBreakpointIndicator {
 7229                 is_active,
 7230                 display_row,
 7231                 collides_with_existing_breakpoint,
 7232             }| {
 7233                (
 7234                    is_active && display_row == row,
 7235                    collides_with_existing_breakpoint,
 7236                )
 7237            },
 7238        );
 7239
 7240        let (color, icon) = {
 7241            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7242                (false, false) => ui::IconName::DebugBreakpoint,
 7243                (true, false) => ui::IconName::DebugLogBreakpoint,
 7244                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7245                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7246            };
 7247
 7248            let color = if is_phantom {
 7249                Color::Hint
 7250            } else if is_rejected {
 7251                Color::Disabled
 7252            } else {
 7253                Color::Debugger
 7254            };
 7255
 7256            (color, icon)
 7257        };
 7258
 7259        let breakpoint = Arc::from(breakpoint.clone());
 7260
 7261        let alt_as_text = gpui::Keystroke {
 7262            modifiers: Modifiers::secondary_key(),
 7263            ..Default::default()
 7264        };
 7265        let primary_action_text = if breakpoint.is_disabled() {
 7266            "Enable breakpoint"
 7267        } else if is_phantom && !collides_with_existing {
 7268            "Set breakpoint"
 7269        } else {
 7270            "Unset breakpoint"
 7271        };
 7272        let focus_handle = self.focus_handle.clone();
 7273
 7274        let meta = if is_rejected {
 7275            SharedString::from("No executable code is associated with this line.")
 7276        } else if collides_with_existing && !breakpoint.is_disabled() {
 7277            SharedString::from(format!(
 7278                "{alt_as_text}-click to disable,\nright-click for more options."
 7279            ))
 7280        } else {
 7281            SharedString::from("Right-click for more options.")
 7282        };
 7283        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7284            .icon_size(IconSize::XSmall)
 7285            .size(ui::ButtonSize::None)
 7286            .when(is_rejected, |this| {
 7287                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7288            })
 7289            .icon_color(color)
 7290            .style(ButtonStyle::Transparent)
 7291            .on_click(cx.listener({
 7292                let breakpoint = breakpoint.clone();
 7293
 7294                move |editor, event: &ClickEvent, window, cx| {
 7295                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7296                        BreakpointEditAction::InvertState
 7297                    } else {
 7298                        BreakpointEditAction::Toggle
 7299                    };
 7300
 7301                    window.focus(&editor.focus_handle(cx));
 7302                    editor.edit_breakpoint_at_anchor(
 7303                        position,
 7304                        breakpoint.as_ref().clone(),
 7305                        edit_action,
 7306                        cx,
 7307                    );
 7308                }
 7309            }))
 7310            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7311                editor.set_breakpoint_context_menu(
 7312                    row,
 7313                    Some(position),
 7314                    event.down.position,
 7315                    window,
 7316                    cx,
 7317                );
 7318            }))
 7319            .tooltip(move |window, cx| {
 7320                Tooltip::with_meta_in(
 7321                    primary_action_text,
 7322                    Some(&ToggleBreakpoint),
 7323                    meta.clone(),
 7324                    &focus_handle,
 7325                    window,
 7326                    cx,
 7327                )
 7328            })
 7329    }
 7330
 7331    fn build_tasks_context(
 7332        project: &Entity<Project>,
 7333        buffer: &Entity<Buffer>,
 7334        buffer_row: u32,
 7335        tasks: &Arc<RunnableTasks>,
 7336        cx: &mut Context<Self>,
 7337    ) -> Task<Option<task::TaskContext>> {
 7338        let position = Point::new(buffer_row, tasks.column);
 7339        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7340        let location = Location {
 7341            buffer: buffer.clone(),
 7342            range: range_start..range_start,
 7343        };
 7344        // Fill in the environmental variables from the tree-sitter captures
 7345        let mut captured_task_variables = TaskVariables::default();
 7346        for (capture_name, value) in tasks.extra_variables.clone() {
 7347            captured_task_variables.insert(
 7348                task::VariableName::Custom(capture_name.into()),
 7349                value.clone(),
 7350            );
 7351        }
 7352        project.update(cx, |project, cx| {
 7353            project.task_store().update(cx, |task_store, cx| {
 7354                task_store.task_context_for_location(captured_task_variables, location, cx)
 7355            })
 7356        })
 7357    }
 7358
 7359    pub fn spawn_nearest_task(
 7360        &mut self,
 7361        action: &SpawnNearestTask,
 7362        window: &mut Window,
 7363        cx: &mut Context<Self>,
 7364    ) {
 7365        let Some((workspace, _)) = self.workspace.clone() else {
 7366            return;
 7367        };
 7368        let Some(project) = self.project.clone() else {
 7369            return;
 7370        };
 7371
 7372        // Try to find a closest, enclosing node using tree-sitter that has a
 7373        // task
 7374        let Some((buffer, buffer_row, tasks)) = self
 7375            .find_enclosing_node_task(cx)
 7376            // Or find the task that's closest in row-distance.
 7377            .or_else(|| self.find_closest_task(cx))
 7378        else {
 7379            return;
 7380        };
 7381
 7382        let reveal_strategy = action.reveal;
 7383        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7384        cx.spawn_in(window, async move |_, cx| {
 7385            let context = task_context.await?;
 7386            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7387
 7388            let resolved = &mut resolved_task.resolved;
 7389            resolved.reveal = reveal_strategy;
 7390
 7391            workspace
 7392                .update_in(cx, |workspace, window, cx| {
 7393                    workspace.schedule_resolved_task(
 7394                        task_source_kind,
 7395                        resolved_task,
 7396                        false,
 7397                        window,
 7398                        cx,
 7399                    );
 7400                })
 7401                .ok()
 7402        })
 7403        .detach();
 7404    }
 7405
 7406    fn find_closest_task(
 7407        &mut self,
 7408        cx: &mut Context<Self>,
 7409    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7410        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7411
 7412        let ((buffer_id, row), tasks) = self
 7413            .tasks
 7414            .iter()
 7415            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7416
 7417        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7418        let tasks = Arc::new(tasks.to_owned());
 7419        Some((buffer, *row, tasks))
 7420    }
 7421
 7422    fn find_enclosing_node_task(
 7423        &mut self,
 7424        cx: &mut Context<Self>,
 7425    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7426        let snapshot = self.buffer.read(cx).snapshot(cx);
 7427        let offset = self.selections.newest::<usize>(cx).head();
 7428        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7429        let buffer_id = excerpt.buffer().remote_id();
 7430
 7431        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7432        let mut cursor = layer.node().walk();
 7433
 7434        while cursor.goto_first_child_for_byte(offset).is_some() {
 7435            if cursor.node().end_byte() == offset {
 7436                cursor.goto_next_sibling();
 7437            }
 7438        }
 7439
 7440        // Ascend to the smallest ancestor that contains the range and has a task.
 7441        loop {
 7442            let node = cursor.node();
 7443            let node_range = node.byte_range();
 7444            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7445
 7446            // Check if this node contains our offset
 7447            if node_range.start <= offset && node_range.end >= offset {
 7448                // If it contains offset, check for task
 7449                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7450                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7451                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7452                }
 7453            }
 7454
 7455            if !cursor.goto_parent() {
 7456                break;
 7457            }
 7458        }
 7459        None
 7460    }
 7461
 7462    fn render_run_indicator(
 7463        &self,
 7464        _style: &EditorStyle,
 7465        is_active: bool,
 7466        row: DisplayRow,
 7467        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7468        cx: &mut Context<Self>,
 7469    ) -> IconButton {
 7470        let color = Color::Muted;
 7471        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7472
 7473        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7474            .shape(ui::IconButtonShape::Square)
 7475            .icon_size(IconSize::XSmall)
 7476            .icon_color(color)
 7477            .toggle_state(is_active)
 7478            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7479                let quick_launch = e.down.button == MouseButton::Left;
 7480                window.focus(&editor.focus_handle(cx));
 7481                editor.toggle_code_actions(
 7482                    &ToggleCodeActions {
 7483                        deployed_from_indicator: Some(row),
 7484                        quick_launch,
 7485                    },
 7486                    window,
 7487                    cx,
 7488                );
 7489            }))
 7490            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7491                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7492            }))
 7493    }
 7494
 7495    pub fn context_menu_visible(&self) -> bool {
 7496        !self.edit_prediction_preview_is_active()
 7497            && self
 7498                .context_menu
 7499                .borrow()
 7500                .as_ref()
 7501                .map_or(false, |menu| menu.visible())
 7502    }
 7503
 7504    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7505        self.context_menu
 7506            .borrow()
 7507            .as_ref()
 7508            .map(|menu| menu.origin())
 7509    }
 7510
 7511    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7512        self.context_menu_options = Some(options);
 7513    }
 7514
 7515    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7516    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7517
 7518    fn render_edit_prediction_popover(
 7519        &mut self,
 7520        text_bounds: &Bounds<Pixels>,
 7521        content_origin: gpui::Point<Pixels>,
 7522        right_margin: Pixels,
 7523        editor_snapshot: &EditorSnapshot,
 7524        visible_row_range: Range<DisplayRow>,
 7525        scroll_top: f32,
 7526        scroll_bottom: f32,
 7527        line_layouts: &[LineWithInvisibles],
 7528        line_height: Pixels,
 7529        scroll_pixel_position: gpui::Point<Pixels>,
 7530        newest_selection_head: Option<DisplayPoint>,
 7531        editor_width: Pixels,
 7532        style: &EditorStyle,
 7533        window: &mut Window,
 7534        cx: &mut App,
 7535    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7536        if self.mode().is_minimap() {
 7537            return None;
 7538        }
 7539        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7540
 7541        if self.edit_prediction_visible_in_cursor_popover(true) {
 7542            return None;
 7543        }
 7544
 7545        match &active_inline_completion.completion {
 7546            InlineCompletion::Move { target, .. } => {
 7547                let target_display_point = target.to_display_point(editor_snapshot);
 7548
 7549                if self.edit_prediction_requires_modifier() {
 7550                    if !self.edit_prediction_preview_is_active() {
 7551                        return None;
 7552                    }
 7553
 7554                    self.render_edit_prediction_modifier_jump_popover(
 7555                        text_bounds,
 7556                        content_origin,
 7557                        visible_row_range,
 7558                        line_layouts,
 7559                        line_height,
 7560                        scroll_pixel_position,
 7561                        newest_selection_head,
 7562                        target_display_point,
 7563                        window,
 7564                        cx,
 7565                    )
 7566                } else {
 7567                    self.render_edit_prediction_eager_jump_popover(
 7568                        text_bounds,
 7569                        content_origin,
 7570                        editor_snapshot,
 7571                        visible_row_range,
 7572                        scroll_top,
 7573                        scroll_bottom,
 7574                        line_height,
 7575                        scroll_pixel_position,
 7576                        target_display_point,
 7577                        editor_width,
 7578                        window,
 7579                        cx,
 7580                    )
 7581                }
 7582            }
 7583            InlineCompletion::Edit {
 7584                display_mode: EditDisplayMode::Inline,
 7585                ..
 7586            } => None,
 7587            InlineCompletion::Edit {
 7588                display_mode: EditDisplayMode::TabAccept,
 7589                edits,
 7590                ..
 7591            } => {
 7592                let range = &edits.first()?.0;
 7593                let target_display_point = range.end.to_display_point(editor_snapshot);
 7594
 7595                self.render_edit_prediction_end_of_line_popover(
 7596                    "Accept",
 7597                    editor_snapshot,
 7598                    visible_row_range,
 7599                    target_display_point,
 7600                    line_height,
 7601                    scroll_pixel_position,
 7602                    content_origin,
 7603                    editor_width,
 7604                    window,
 7605                    cx,
 7606                )
 7607            }
 7608            InlineCompletion::Edit {
 7609                edits,
 7610                edit_preview,
 7611                display_mode: EditDisplayMode::DiffPopover,
 7612                snapshot,
 7613            } => self.render_edit_prediction_diff_popover(
 7614                text_bounds,
 7615                content_origin,
 7616                right_margin,
 7617                editor_snapshot,
 7618                visible_row_range,
 7619                line_layouts,
 7620                line_height,
 7621                scroll_pixel_position,
 7622                newest_selection_head,
 7623                editor_width,
 7624                style,
 7625                edits,
 7626                edit_preview,
 7627                snapshot,
 7628                window,
 7629                cx,
 7630            ),
 7631        }
 7632    }
 7633
 7634    fn render_edit_prediction_modifier_jump_popover(
 7635        &mut self,
 7636        text_bounds: &Bounds<Pixels>,
 7637        content_origin: gpui::Point<Pixels>,
 7638        visible_row_range: Range<DisplayRow>,
 7639        line_layouts: &[LineWithInvisibles],
 7640        line_height: Pixels,
 7641        scroll_pixel_position: gpui::Point<Pixels>,
 7642        newest_selection_head: Option<DisplayPoint>,
 7643        target_display_point: DisplayPoint,
 7644        window: &mut Window,
 7645        cx: &mut App,
 7646    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7647        let scrolled_content_origin =
 7648            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7649
 7650        const SCROLL_PADDING_Y: Pixels = px(12.);
 7651
 7652        if target_display_point.row() < visible_row_range.start {
 7653            return self.render_edit_prediction_scroll_popover(
 7654                |_| SCROLL_PADDING_Y,
 7655                IconName::ArrowUp,
 7656                visible_row_range,
 7657                line_layouts,
 7658                newest_selection_head,
 7659                scrolled_content_origin,
 7660                window,
 7661                cx,
 7662            );
 7663        } else if target_display_point.row() >= visible_row_range.end {
 7664            return self.render_edit_prediction_scroll_popover(
 7665                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7666                IconName::ArrowDown,
 7667                visible_row_range,
 7668                line_layouts,
 7669                newest_selection_head,
 7670                scrolled_content_origin,
 7671                window,
 7672                cx,
 7673            );
 7674        }
 7675
 7676        const POLE_WIDTH: Pixels = px(2.);
 7677
 7678        let line_layout =
 7679            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7680        let target_column = target_display_point.column() as usize;
 7681
 7682        let target_x = line_layout.x_for_index(target_column);
 7683        let target_y =
 7684            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7685
 7686        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7687
 7688        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7689        border_color.l += 0.001;
 7690
 7691        let mut element = v_flex()
 7692            .items_end()
 7693            .when(flag_on_right, |el| el.items_start())
 7694            .child(if flag_on_right {
 7695                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7696                    .rounded_bl(px(0.))
 7697                    .rounded_tl(px(0.))
 7698                    .border_l_2()
 7699                    .border_color(border_color)
 7700            } else {
 7701                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7702                    .rounded_br(px(0.))
 7703                    .rounded_tr(px(0.))
 7704                    .border_r_2()
 7705                    .border_color(border_color)
 7706            })
 7707            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7708            .into_any();
 7709
 7710        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7711
 7712        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7713            - point(
 7714                if flag_on_right {
 7715                    POLE_WIDTH
 7716                } else {
 7717                    size.width - POLE_WIDTH
 7718                },
 7719                size.height - line_height,
 7720            );
 7721
 7722        origin.x = origin.x.max(content_origin.x);
 7723
 7724        element.prepaint_at(origin, window, cx);
 7725
 7726        Some((element, origin))
 7727    }
 7728
 7729    fn render_edit_prediction_scroll_popover(
 7730        &mut self,
 7731        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7732        scroll_icon: IconName,
 7733        visible_row_range: Range<DisplayRow>,
 7734        line_layouts: &[LineWithInvisibles],
 7735        newest_selection_head: Option<DisplayPoint>,
 7736        scrolled_content_origin: gpui::Point<Pixels>,
 7737        window: &mut Window,
 7738        cx: &mut App,
 7739    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7740        let mut element = self
 7741            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7742            .into_any();
 7743
 7744        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7745
 7746        let cursor = newest_selection_head?;
 7747        let cursor_row_layout =
 7748            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7749        let cursor_column = cursor.column() as usize;
 7750
 7751        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7752
 7753        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7754
 7755        element.prepaint_at(origin, window, cx);
 7756        Some((element, origin))
 7757    }
 7758
 7759    fn render_edit_prediction_eager_jump_popover(
 7760        &mut self,
 7761        text_bounds: &Bounds<Pixels>,
 7762        content_origin: gpui::Point<Pixels>,
 7763        editor_snapshot: &EditorSnapshot,
 7764        visible_row_range: Range<DisplayRow>,
 7765        scroll_top: f32,
 7766        scroll_bottom: f32,
 7767        line_height: Pixels,
 7768        scroll_pixel_position: gpui::Point<Pixels>,
 7769        target_display_point: DisplayPoint,
 7770        editor_width: Pixels,
 7771        window: &mut Window,
 7772        cx: &mut App,
 7773    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7774        if target_display_point.row().as_f32() < scroll_top {
 7775            let mut element = self
 7776                .render_edit_prediction_line_popover(
 7777                    "Jump to Edit",
 7778                    Some(IconName::ArrowUp),
 7779                    window,
 7780                    cx,
 7781                )?
 7782                .into_any();
 7783
 7784            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7785            let offset = point(
 7786                (text_bounds.size.width - size.width) / 2.,
 7787                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7788            );
 7789
 7790            let origin = text_bounds.origin + offset;
 7791            element.prepaint_at(origin, window, cx);
 7792            Some((element, origin))
 7793        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7794            let mut element = self
 7795                .render_edit_prediction_line_popover(
 7796                    "Jump to Edit",
 7797                    Some(IconName::ArrowDown),
 7798                    window,
 7799                    cx,
 7800                )?
 7801                .into_any();
 7802
 7803            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7804            let offset = point(
 7805                (text_bounds.size.width - size.width) / 2.,
 7806                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7807            );
 7808
 7809            let origin = text_bounds.origin + offset;
 7810            element.prepaint_at(origin, window, cx);
 7811            Some((element, origin))
 7812        } else {
 7813            self.render_edit_prediction_end_of_line_popover(
 7814                "Jump to Edit",
 7815                editor_snapshot,
 7816                visible_row_range,
 7817                target_display_point,
 7818                line_height,
 7819                scroll_pixel_position,
 7820                content_origin,
 7821                editor_width,
 7822                window,
 7823                cx,
 7824            )
 7825        }
 7826    }
 7827
 7828    fn render_edit_prediction_end_of_line_popover(
 7829        self: &mut Editor,
 7830        label: &'static str,
 7831        editor_snapshot: &EditorSnapshot,
 7832        visible_row_range: Range<DisplayRow>,
 7833        target_display_point: DisplayPoint,
 7834        line_height: Pixels,
 7835        scroll_pixel_position: gpui::Point<Pixels>,
 7836        content_origin: gpui::Point<Pixels>,
 7837        editor_width: Pixels,
 7838        window: &mut Window,
 7839        cx: &mut App,
 7840    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7841        let target_line_end = DisplayPoint::new(
 7842            target_display_point.row(),
 7843            editor_snapshot.line_len(target_display_point.row()),
 7844        );
 7845
 7846        let mut element = self
 7847            .render_edit_prediction_line_popover(label, None, window, cx)?
 7848            .into_any();
 7849
 7850        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7851
 7852        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7853
 7854        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7855        let mut origin = start_point
 7856            + line_origin
 7857            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7858        origin.x = origin.x.max(content_origin.x);
 7859
 7860        let max_x = content_origin.x + editor_width - size.width;
 7861
 7862        if origin.x > max_x {
 7863            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7864
 7865            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7866                origin.y += offset;
 7867                IconName::ArrowUp
 7868            } else {
 7869                origin.y -= offset;
 7870                IconName::ArrowDown
 7871            };
 7872
 7873            element = self
 7874                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7875                .into_any();
 7876
 7877            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7878
 7879            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7880        }
 7881
 7882        element.prepaint_at(origin, window, cx);
 7883        Some((element, origin))
 7884    }
 7885
 7886    fn render_edit_prediction_diff_popover(
 7887        self: &Editor,
 7888        text_bounds: &Bounds<Pixels>,
 7889        content_origin: gpui::Point<Pixels>,
 7890        right_margin: Pixels,
 7891        editor_snapshot: &EditorSnapshot,
 7892        visible_row_range: Range<DisplayRow>,
 7893        line_layouts: &[LineWithInvisibles],
 7894        line_height: Pixels,
 7895        scroll_pixel_position: gpui::Point<Pixels>,
 7896        newest_selection_head: Option<DisplayPoint>,
 7897        editor_width: Pixels,
 7898        style: &EditorStyle,
 7899        edits: &Vec<(Range<Anchor>, String)>,
 7900        edit_preview: &Option<language::EditPreview>,
 7901        snapshot: &language::BufferSnapshot,
 7902        window: &mut Window,
 7903        cx: &mut App,
 7904    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7905        let edit_start = edits
 7906            .first()
 7907            .unwrap()
 7908            .0
 7909            .start
 7910            .to_display_point(editor_snapshot);
 7911        let edit_end = edits
 7912            .last()
 7913            .unwrap()
 7914            .0
 7915            .end
 7916            .to_display_point(editor_snapshot);
 7917
 7918        let is_visible = visible_row_range.contains(&edit_start.row())
 7919            || visible_row_range.contains(&edit_end.row());
 7920        if !is_visible {
 7921            return None;
 7922        }
 7923
 7924        let highlighted_edits =
 7925            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7926
 7927        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7928        let line_count = highlighted_edits.text.lines().count();
 7929
 7930        const BORDER_WIDTH: Pixels = px(1.);
 7931
 7932        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7933        let has_keybind = keybind.is_some();
 7934
 7935        let mut element = h_flex()
 7936            .items_start()
 7937            .child(
 7938                h_flex()
 7939                    .bg(cx.theme().colors().editor_background)
 7940                    .border(BORDER_WIDTH)
 7941                    .shadow_sm()
 7942                    .border_color(cx.theme().colors().border)
 7943                    .rounded_l_lg()
 7944                    .when(line_count > 1, |el| el.rounded_br_lg())
 7945                    .pr_1()
 7946                    .child(styled_text),
 7947            )
 7948            .child(
 7949                h_flex()
 7950                    .h(line_height + BORDER_WIDTH * 2.)
 7951                    .px_1p5()
 7952                    .gap_1()
 7953                    // Workaround: For some reason, there's a gap if we don't do this
 7954                    .ml(-BORDER_WIDTH)
 7955                    .shadow(smallvec![gpui::BoxShadow {
 7956                        color: gpui::black().opacity(0.05),
 7957                        offset: point(px(1.), px(1.)),
 7958                        blur_radius: px(2.),
 7959                        spread_radius: px(0.),
 7960                    }])
 7961                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7962                    .border(BORDER_WIDTH)
 7963                    .border_color(cx.theme().colors().border)
 7964                    .rounded_r_lg()
 7965                    .id("edit_prediction_diff_popover_keybind")
 7966                    .when(!has_keybind, |el| {
 7967                        let status_colors = cx.theme().status();
 7968
 7969                        el.bg(status_colors.error_background)
 7970                            .border_color(status_colors.error.opacity(0.6))
 7971                            .child(Icon::new(IconName::Info).color(Color::Error))
 7972                            .cursor_default()
 7973                            .hoverable_tooltip(move |_window, cx| {
 7974                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7975                            })
 7976                    })
 7977                    .children(keybind),
 7978            )
 7979            .into_any();
 7980
 7981        let longest_row =
 7982            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7983        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7984            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7985        } else {
 7986            layout_line(
 7987                longest_row,
 7988                editor_snapshot,
 7989                style,
 7990                editor_width,
 7991                |_| false,
 7992                window,
 7993                cx,
 7994            )
 7995            .width
 7996        };
 7997
 7998        let viewport_bounds =
 7999            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8000                right: -right_margin,
 8001                ..Default::default()
 8002            });
 8003
 8004        let x_after_longest =
 8005            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8006                - scroll_pixel_position.x;
 8007
 8008        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8009
 8010        // Fully visible if it can be displayed within the window (allow overlapping other
 8011        // panes). However, this is only allowed if the popover starts within text_bounds.
 8012        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8013            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8014
 8015        let mut origin = if can_position_to_the_right {
 8016            point(
 8017                x_after_longest,
 8018                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8019                    - scroll_pixel_position.y,
 8020            )
 8021        } else {
 8022            let cursor_row = newest_selection_head.map(|head| head.row());
 8023            let above_edit = edit_start
 8024                .row()
 8025                .0
 8026                .checked_sub(line_count as u32)
 8027                .map(DisplayRow);
 8028            let below_edit = Some(edit_end.row() + 1);
 8029            let above_cursor =
 8030                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8031            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8032
 8033            // Place the edit popover adjacent to the edit if there is a location
 8034            // available that is onscreen and does not obscure the cursor. Otherwise,
 8035            // place it adjacent to the cursor.
 8036            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8037                .into_iter()
 8038                .flatten()
 8039                .find(|&start_row| {
 8040                    let end_row = start_row + line_count as u32;
 8041                    visible_row_range.contains(&start_row)
 8042                        && visible_row_range.contains(&end_row)
 8043                        && cursor_row.map_or(true, |cursor_row| {
 8044                            !((start_row..end_row).contains(&cursor_row))
 8045                        })
 8046                })?;
 8047
 8048            content_origin
 8049                + point(
 8050                    -scroll_pixel_position.x,
 8051                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8052                )
 8053        };
 8054
 8055        origin.x -= BORDER_WIDTH;
 8056
 8057        window.defer_draw(element, origin, 1);
 8058
 8059        // Do not return an element, since it will already be drawn due to defer_draw.
 8060        None
 8061    }
 8062
 8063    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8064        px(30.)
 8065    }
 8066
 8067    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8068        if self.read_only(cx) {
 8069            cx.theme().players().read_only()
 8070        } else {
 8071            self.style.as_ref().unwrap().local_player
 8072        }
 8073    }
 8074
 8075    fn render_edit_prediction_accept_keybind(
 8076        &self,
 8077        window: &mut Window,
 8078        cx: &App,
 8079    ) -> Option<AnyElement> {
 8080        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8081        let accept_keystroke = accept_binding.keystroke()?;
 8082
 8083        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8084
 8085        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8086            Color::Accent
 8087        } else {
 8088            Color::Muted
 8089        };
 8090
 8091        h_flex()
 8092            .px_0p5()
 8093            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8094            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8095            .text_size(TextSize::XSmall.rems(cx))
 8096            .child(h_flex().children(ui::render_modifiers(
 8097                &accept_keystroke.modifiers,
 8098                PlatformStyle::platform(),
 8099                Some(modifiers_color),
 8100                Some(IconSize::XSmall.rems().into()),
 8101                true,
 8102            )))
 8103            .when(is_platform_style_mac, |parent| {
 8104                parent.child(accept_keystroke.key.clone())
 8105            })
 8106            .when(!is_platform_style_mac, |parent| {
 8107                parent.child(
 8108                    Key::new(
 8109                        util::capitalize(&accept_keystroke.key),
 8110                        Some(Color::Default),
 8111                    )
 8112                    .size(Some(IconSize::XSmall.rems().into())),
 8113                )
 8114            })
 8115            .into_any()
 8116            .into()
 8117    }
 8118
 8119    fn render_edit_prediction_line_popover(
 8120        &self,
 8121        label: impl Into<SharedString>,
 8122        icon: Option<IconName>,
 8123        window: &mut Window,
 8124        cx: &App,
 8125    ) -> Option<Stateful<Div>> {
 8126        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8127
 8128        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8129        let has_keybind = keybind.is_some();
 8130
 8131        let result = h_flex()
 8132            .id("ep-line-popover")
 8133            .py_0p5()
 8134            .pl_1()
 8135            .pr(padding_right)
 8136            .gap_1()
 8137            .rounded_md()
 8138            .border_1()
 8139            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8140            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8141            .shadow_sm()
 8142            .when(!has_keybind, |el| {
 8143                let status_colors = cx.theme().status();
 8144
 8145                el.bg(status_colors.error_background)
 8146                    .border_color(status_colors.error.opacity(0.6))
 8147                    .pl_2()
 8148                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8149                    .cursor_default()
 8150                    .hoverable_tooltip(move |_window, cx| {
 8151                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8152                    })
 8153            })
 8154            .children(keybind)
 8155            .child(
 8156                Label::new(label)
 8157                    .size(LabelSize::Small)
 8158                    .when(!has_keybind, |el| {
 8159                        el.color(cx.theme().status().error.into()).strikethrough()
 8160                    }),
 8161            )
 8162            .when(!has_keybind, |el| {
 8163                el.child(
 8164                    h_flex().ml_1().child(
 8165                        Icon::new(IconName::Info)
 8166                            .size(IconSize::Small)
 8167                            .color(cx.theme().status().error.into()),
 8168                    ),
 8169                )
 8170            })
 8171            .when_some(icon, |element, icon| {
 8172                element.child(
 8173                    div()
 8174                        .mt(px(1.5))
 8175                        .child(Icon::new(icon).size(IconSize::Small)),
 8176                )
 8177            });
 8178
 8179        Some(result)
 8180    }
 8181
 8182    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8183        let accent_color = cx.theme().colors().text_accent;
 8184        let editor_bg_color = cx.theme().colors().editor_background;
 8185        editor_bg_color.blend(accent_color.opacity(0.1))
 8186    }
 8187
 8188    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8189        let accent_color = cx.theme().colors().text_accent;
 8190        let editor_bg_color = cx.theme().colors().editor_background;
 8191        editor_bg_color.blend(accent_color.opacity(0.6))
 8192    }
 8193
 8194    fn render_edit_prediction_cursor_popover(
 8195        &self,
 8196        min_width: Pixels,
 8197        max_width: Pixels,
 8198        cursor_point: Point,
 8199        style: &EditorStyle,
 8200        accept_keystroke: Option<&gpui::Keystroke>,
 8201        _window: &Window,
 8202        cx: &mut Context<Editor>,
 8203    ) -> Option<AnyElement> {
 8204        let provider = self.edit_prediction_provider.as_ref()?;
 8205
 8206        if provider.provider.needs_terms_acceptance(cx) {
 8207            return Some(
 8208                h_flex()
 8209                    .min_w(min_width)
 8210                    .flex_1()
 8211                    .px_2()
 8212                    .py_1()
 8213                    .gap_3()
 8214                    .elevation_2(cx)
 8215                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8216                    .id("accept-terms")
 8217                    .cursor_pointer()
 8218                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8219                    .on_click(cx.listener(|this, _event, window, cx| {
 8220                        cx.stop_propagation();
 8221                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8222                        window.dispatch_action(
 8223                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8224                            cx,
 8225                        );
 8226                    }))
 8227                    .child(
 8228                        h_flex()
 8229                            .flex_1()
 8230                            .gap_2()
 8231                            .child(Icon::new(IconName::ZedPredict))
 8232                            .child(Label::new("Accept Terms of Service"))
 8233                            .child(div().w_full())
 8234                            .child(
 8235                                Icon::new(IconName::ArrowUpRight)
 8236                                    .color(Color::Muted)
 8237                                    .size(IconSize::Small),
 8238                            )
 8239                            .into_any_element(),
 8240                    )
 8241                    .into_any(),
 8242            );
 8243        }
 8244
 8245        let is_refreshing = provider.provider.is_refreshing(cx);
 8246
 8247        fn pending_completion_container() -> Div {
 8248            h_flex()
 8249                .h_full()
 8250                .flex_1()
 8251                .gap_2()
 8252                .child(Icon::new(IconName::ZedPredict))
 8253        }
 8254
 8255        let completion = match &self.active_inline_completion {
 8256            Some(prediction) => {
 8257                if !self.has_visible_completions_menu() {
 8258                    const RADIUS: Pixels = px(6.);
 8259                    const BORDER_WIDTH: Pixels = px(1.);
 8260
 8261                    return Some(
 8262                        h_flex()
 8263                            .elevation_2(cx)
 8264                            .border(BORDER_WIDTH)
 8265                            .border_color(cx.theme().colors().border)
 8266                            .when(accept_keystroke.is_none(), |el| {
 8267                                el.border_color(cx.theme().status().error)
 8268                            })
 8269                            .rounded(RADIUS)
 8270                            .rounded_tl(px(0.))
 8271                            .overflow_hidden()
 8272                            .child(div().px_1p5().child(match &prediction.completion {
 8273                                InlineCompletion::Move { target, snapshot } => {
 8274                                    use text::ToPoint as _;
 8275                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8276                                    {
 8277                                        Icon::new(IconName::ZedPredictDown)
 8278                                    } else {
 8279                                        Icon::new(IconName::ZedPredictUp)
 8280                                    }
 8281                                }
 8282                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8283                            }))
 8284                            .child(
 8285                                h_flex()
 8286                                    .gap_1()
 8287                                    .py_1()
 8288                                    .px_2()
 8289                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8290                                    .border_l_1()
 8291                                    .border_color(cx.theme().colors().border)
 8292                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8293                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8294                                        el.child(
 8295                                            Label::new("Hold")
 8296                                                .size(LabelSize::Small)
 8297                                                .when(accept_keystroke.is_none(), |el| {
 8298                                                    el.strikethrough()
 8299                                                })
 8300                                                .line_height_style(LineHeightStyle::UiLabel),
 8301                                        )
 8302                                    })
 8303                                    .id("edit_prediction_cursor_popover_keybind")
 8304                                    .when(accept_keystroke.is_none(), |el| {
 8305                                        let status_colors = cx.theme().status();
 8306
 8307                                        el.bg(status_colors.error_background)
 8308                                            .border_color(status_colors.error.opacity(0.6))
 8309                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8310                                            .cursor_default()
 8311                                            .hoverable_tooltip(move |_window, cx| {
 8312                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8313                                                    .into()
 8314                                            })
 8315                                    })
 8316                                    .when_some(
 8317                                        accept_keystroke.as_ref(),
 8318                                        |el, accept_keystroke| {
 8319                                            el.child(h_flex().children(ui::render_modifiers(
 8320                                                &accept_keystroke.modifiers,
 8321                                                PlatformStyle::platform(),
 8322                                                Some(Color::Default),
 8323                                                Some(IconSize::XSmall.rems().into()),
 8324                                                false,
 8325                                            )))
 8326                                        },
 8327                                    ),
 8328                            )
 8329                            .into_any(),
 8330                    );
 8331                }
 8332
 8333                self.render_edit_prediction_cursor_popover_preview(
 8334                    prediction,
 8335                    cursor_point,
 8336                    style,
 8337                    cx,
 8338                )?
 8339            }
 8340
 8341            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8342                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8343                    stale_completion,
 8344                    cursor_point,
 8345                    style,
 8346                    cx,
 8347                )?,
 8348
 8349                None => {
 8350                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8351                }
 8352            },
 8353
 8354            None => pending_completion_container().child(Label::new("No Prediction")),
 8355        };
 8356
 8357        let completion = if is_refreshing {
 8358            completion
 8359                .with_animation(
 8360                    "loading-completion",
 8361                    Animation::new(Duration::from_secs(2))
 8362                        .repeat()
 8363                        .with_easing(pulsating_between(0.4, 0.8)),
 8364                    |label, delta| label.opacity(delta),
 8365                )
 8366                .into_any_element()
 8367        } else {
 8368            completion.into_any_element()
 8369        };
 8370
 8371        let has_completion = self.active_inline_completion.is_some();
 8372
 8373        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8374        Some(
 8375            h_flex()
 8376                .min_w(min_width)
 8377                .max_w(max_width)
 8378                .flex_1()
 8379                .elevation_2(cx)
 8380                .border_color(cx.theme().colors().border)
 8381                .child(
 8382                    div()
 8383                        .flex_1()
 8384                        .py_1()
 8385                        .px_2()
 8386                        .overflow_hidden()
 8387                        .child(completion),
 8388                )
 8389                .when_some(accept_keystroke, |el, accept_keystroke| {
 8390                    if !accept_keystroke.modifiers.modified() {
 8391                        return el;
 8392                    }
 8393
 8394                    el.child(
 8395                        h_flex()
 8396                            .h_full()
 8397                            .border_l_1()
 8398                            .rounded_r_lg()
 8399                            .border_color(cx.theme().colors().border)
 8400                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8401                            .gap_1()
 8402                            .py_1()
 8403                            .px_2()
 8404                            .child(
 8405                                h_flex()
 8406                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8407                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8408                                    .child(h_flex().children(ui::render_modifiers(
 8409                                        &accept_keystroke.modifiers,
 8410                                        PlatformStyle::platform(),
 8411                                        Some(if !has_completion {
 8412                                            Color::Muted
 8413                                        } else {
 8414                                            Color::Default
 8415                                        }),
 8416                                        None,
 8417                                        false,
 8418                                    ))),
 8419                            )
 8420                            .child(Label::new("Preview").into_any_element())
 8421                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8422                    )
 8423                })
 8424                .into_any(),
 8425        )
 8426    }
 8427
 8428    fn render_edit_prediction_cursor_popover_preview(
 8429        &self,
 8430        completion: &InlineCompletionState,
 8431        cursor_point: Point,
 8432        style: &EditorStyle,
 8433        cx: &mut Context<Editor>,
 8434    ) -> Option<Div> {
 8435        use text::ToPoint as _;
 8436
 8437        fn render_relative_row_jump(
 8438            prefix: impl Into<String>,
 8439            current_row: u32,
 8440            target_row: u32,
 8441        ) -> Div {
 8442            let (row_diff, arrow) = if target_row < current_row {
 8443                (current_row - target_row, IconName::ArrowUp)
 8444            } else {
 8445                (target_row - current_row, IconName::ArrowDown)
 8446            };
 8447
 8448            h_flex()
 8449                .child(
 8450                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8451                        .color(Color::Muted)
 8452                        .size(LabelSize::Small),
 8453                )
 8454                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8455        }
 8456
 8457        match &completion.completion {
 8458            InlineCompletion::Move {
 8459                target, snapshot, ..
 8460            } => Some(
 8461                h_flex()
 8462                    .px_2()
 8463                    .gap_2()
 8464                    .flex_1()
 8465                    .child(
 8466                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8467                            Icon::new(IconName::ZedPredictDown)
 8468                        } else {
 8469                            Icon::new(IconName::ZedPredictUp)
 8470                        },
 8471                    )
 8472                    .child(Label::new("Jump to Edit")),
 8473            ),
 8474
 8475            InlineCompletion::Edit {
 8476                edits,
 8477                edit_preview,
 8478                snapshot,
 8479                display_mode: _,
 8480            } => {
 8481                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8482
 8483                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8484                    &snapshot,
 8485                    &edits,
 8486                    edit_preview.as_ref()?,
 8487                    true,
 8488                    cx,
 8489                )
 8490                .first_line_preview();
 8491
 8492                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8493                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8494
 8495                let preview = h_flex()
 8496                    .gap_1()
 8497                    .min_w_16()
 8498                    .child(styled_text)
 8499                    .when(has_more_lines, |parent| parent.child(""));
 8500
 8501                let left = if first_edit_row != cursor_point.row {
 8502                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8503                        .into_any_element()
 8504                } else {
 8505                    Icon::new(IconName::ZedPredict).into_any_element()
 8506                };
 8507
 8508                Some(
 8509                    h_flex()
 8510                        .h_full()
 8511                        .flex_1()
 8512                        .gap_2()
 8513                        .pr_1()
 8514                        .overflow_x_hidden()
 8515                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8516                        .child(left)
 8517                        .child(preview),
 8518                )
 8519            }
 8520        }
 8521    }
 8522
 8523    fn render_context_menu(
 8524        &self,
 8525        style: &EditorStyle,
 8526        max_height_in_lines: u32,
 8527        window: &mut Window,
 8528        cx: &mut Context<Editor>,
 8529    ) -> Option<AnyElement> {
 8530        let menu = self.context_menu.borrow();
 8531        let menu = menu.as_ref()?;
 8532        if !menu.visible() {
 8533            return None;
 8534        };
 8535        Some(menu.render(style, max_height_in_lines, window, cx))
 8536    }
 8537
 8538    fn render_context_menu_aside(
 8539        &mut self,
 8540        max_size: Size<Pixels>,
 8541        window: &mut Window,
 8542        cx: &mut Context<Editor>,
 8543    ) -> Option<AnyElement> {
 8544        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8545            if menu.visible() {
 8546                menu.render_aside(self, max_size, window, cx)
 8547            } else {
 8548                None
 8549            }
 8550        })
 8551    }
 8552
 8553    fn hide_context_menu(
 8554        &mut self,
 8555        window: &mut Window,
 8556        cx: &mut Context<Self>,
 8557    ) -> Option<CodeContextMenu> {
 8558        cx.notify();
 8559        self.completion_tasks.clear();
 8560        let context_menu = self.context_menu.borrow_mut().take();
 8561        self.stale_inline_completion_in_menu.take();
 8562        self.update_visible_inline_completion(window, cx);
 8563        context_menu
 8564    }
 8565
 8566    fn show_snippet_choices(
 8567        &mut self,
 8568        choices: &Vec<String>,
 8569        selection: Range<Anchor>,
 8570        cx: &mut Context<Self>,
 8571    ) {
 8572        if selection.start.buffer_id.is_none() {
 8573            return;
 8574        }
 8575        let buffer_id = selection.start.buffer_id.unwrap();
 8576        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8577        let id = post_inc(&mut self.next_completion_id);
 8578        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8579
 8580        if let Some(buffer) = buffer {
 8581            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8582                CompletionsMenu::new_snippet_choices(
 8583                    id,
 8584                    true,
 8585                    choices,
 8586                    selection,
 8587                    buffer,
 8588                    snippet_sort_order,
 8589                ),
 8590            ));
 8591        }
 8592    }
 8593
 8594    pub fn insert_snippet(
 8595        &mut self,
 8596        insertion_ranges: &[Range<usize>],
 8597        snippet: Snippet,
 8598        window: &mut Window,
 8599        cx: &mut Context<Self>,
 8600    ) -> Result<()> {
 8601        struct Tabstop<T> {
 8602            is_end_tabstop: bool,
 8603            ranges: Vec<Range<T>>,
 8604            choices: Option<Vec<String>>,
 8605        }
 8606
 8607        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8608            let snippet_text: Arc<str> = snippet.text.clone().into();
 8609            let edits = insertion_ranges
 8610                .iter()
 8611                .cloned()
 8612                .map(|range| (range, snippet_text.clone()));
 8613            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8614
 8615            let snapshot = &*buffer.read(cx);
 8616            let snippet = &snippet;
 8617            snippet
 8618                .tabstops
 8619                .iter()
 8620                .map(|tabstop| {
 8621                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8622                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8623                    });
 8624                    let mut tabstop_ranges = tabstop
 8625                        .ranges
 8626                        .iter()
 8627                        .flat_map(|tabstop_range| {
 8628                            let mut delta = 0_isize;
 8629                            insertion_ranges.iter().map(move |insertion_range| {
 8630                                let insertion_start = insertion_range.start as isize + delta;
 8631                                delta +=
 8632                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8633
 8634                                let start = ((insertion_start + tabstop_range.start) as usize)
 8635                                    .min(snapshot.len());
 8636                                let end = ((insertion_start + tabstop_range.end) as usize)
 8637                                    .min(snapshot.len());
 8638                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8639                            })
 8640                        })
 8641                        .collect::<Vec<_>>();
 8642                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8643
 8644                    Tabstop {
 8645                        is_end_tabstop,
 8646                        ranges: tabstop_ranges,
 8647                        choices: tabstop.choices.clone(),
 8648                    }
 8649                })
 8650                .collect::<Vec<_>>()
 8651        });
 8652        if let Some(tabstop) = tabstops.first() {
 8653            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8654                s.select_ranges(tabstop.ranges.iter().cloned());
 8655            });
 8656
 8657            if let Some(choices) = &tabstop.choices {
 8658                if let Some(selection) = tabstop.ranges.first() {
 8659                    self.show_snippet_choices(choices, selection.clone(), cx)
 8660                }
 8661            }
 8662
 8663            // If we're already at the last tabstop and it's at the end of the snippet,
 8664            // we're done, we don't need to keep the state around.
 8665            if !tabstop.is_end_tabstop {
 8666                let choices = tabstops
 8667                    .iter()
 8668                    .map(|tabstop| tabstop.choices.clone())
 8669                    .collect();
 8670
 8671                let ranges = tabstops
 8672                    .into_iter()
 8673                    .map(|tabstop| tabstop.ranges)
 8674                    .collect::<Vec<_>>();
 8675
 8676                self.snippet_stack.push(SnippetState {
 8677                    active_index: 0,
 8678                    ranges,
 8679                    choices,
 8680                });
 8681            }
 8682
 8683            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8684            if self.autoclose_regions.is_empty() {
 8685                let snapshot = self.buffer.read(cx).snapshot(cx);
 8686                for selection in &mut self.selections.all::<Point>(cx) {
 8687                    let selection_head = selection.head();
 8688                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8689                        continue;
 8690                    };
 8691
 8692                    let mut bracket_pair = None;
 8693                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8694                    let prev_chars = snapshot
 8695                        .reversed_chars_at(selection_head)
 8696                        .collect::<String>();
 8697                    for (pair, enabled) in scope.brackets() {
 8698                        if enabled
 8699                            && pair.close
 8700                            && prev_chars.starts_with(pair.start.as_str())
 8701                            && next_chars.starts_with(pair.end.as_str())
 8702                        {
 8703                            bracket_pair = Some(pair.clone());
 8704                            break;
 8705                        }
 8706                    }
 8707                    if let Some(pair) = bracket_pair {
 8708                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8709                        let autoclose_enabled =
 8710                            self.use_autoclose && snapshot_settings.use_autoclose;
 8711                        if autoclose_enabled {
 8712                            let start = snapshot.anchor_after(selection_head);
 8713                            let end = snapshot.anchor_after(selection_head);
 8714                            self.autoclose_regions.push(AutocloseRegion {
 8715                                selection_id: selection.id,
 8716                                range: start..end,
 8717                                pair,
 8718                            });
 8719                        }
 8720                    }
 8721                }
 8722            }
 8723        }
 8724        Ok(())
 8725    }
 8726
 8727    pub fn move_to_next_snippet_tabstop(
 8728        &mut self,
 8729        window: &mut Window,
 8730        cx: &mut Context<Self>,
 8731    ) -> bool {
 8732        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8733    }
 8734
 8735    pub fn move_to_prev_snippet_tabstop(
 8736        &mut self,
 8737        window: &mut Window,
 8738        cx: &mut Context<Self>,
 8739    ) -> bool {
 8740        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8741    }
 8742
 8743    pub fn move_to_snippet_tabstop(
 8744        &mut self,
 8745        bias: Bias,
 8746        window: &mut Window,
 8747        cx: &mut Context<Self>,
 8748    ) -> bool {
 8749        if let Some(mut snippet) = self.snippet_stack.pop() {
 8750            match bias {
 8751                Bias::Left => {
 8752                    if snippet.active_index > 0 {
 8753                        snippet.active_index -= 1;
 8754                    } else {
 8755                        self.snippet_stack.push(snippet);
 8756                        return false;
 8757                    }
 8758                }
 8759                Bias::Right => {
 8760                    if snippet.active_index + 1 < snippet.ranges.len() {
 8761                        snippet.active_index += 1;
 8762                    } else {
 8763                        self.snippet_stack.push(snippet);
 8764                        return false;
 8765                    }
 8766                }
 8767            }
 8768            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8769                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8770                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8771                });
 8772
 8773                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8774                    if let Some(selection) = current_ranges.first() {
 8775                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8776                    }
 8777                }
 8778
 8779                // If snippet state is not at the last tabstop, push it back on the stack
 8780                if snippet.active_index + 1 < snippet.ranges.len() {
 8781                    self.snippet_stack.push(snippet);
 8782                }
 8783                return true;
 8784            }
 8785        }
 8786
 8787        false
 8788    }
 8789
 8790    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8791        self.transact(window, cx, |this, window, cx| {
 8792            this.select_all(&SelectAll, window, cx);
 8793            this.insert("", window, cx);
 8794        });
 8795    }
 8796
 8797    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8798        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8799        self.transact(window, cx, |this, window, cx| {
 8800            this.select_autoclose_pair(window, cx);
 8801            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8802            if !this.linked_edit_ranges.is_empty() {
 8803                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8804                let snapshot = this.buffer.read(cx).snapshot(cx);
 8805
 8806                for selection in selections.iter() {
 8807                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8808                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8809                    if selection_start.buffer_id != selection_end.buffer_id {
 8810                        continue;
 8811                    }
 8812                    if let Some(ranges) =
 8813                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8814                    {
 8815                        for (buffer, entries) in ranges {
 8816                            linked_ranges.entry(buffer).or_default().extend(entries);
 8817                        }
 8818                    }
 8819                }
 8820            }
 8821
 8822            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8823            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8824            for selection in &mut selections {
 8825                if selection.is_empty() {
 8826                    let old_head = selection.head();
 8827                    let mut new_head =
 8828                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8829                            .to_point(&display_map);
 8830                    if let Some((buffer, line_buffer_range)) = display_map
 8831                        .buffer_snapshot
 8832                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8833                    {
 8834                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8835                        let indent_len = match indent_size.kind {
 8836                            IndentKind::Space => {
 8837                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8838                            }
 8839                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8840                        };
 8841                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8842                            let indent_len = indent_len.get();
 8843                            new_head = cmp::min(
 8844                                new_head,
 8845                                MultiBufferPoint::new(
 8846                                    old_head.row,
 8847                                    ((old_head.column - 1) / indent_len) * indent_len,
 8848                                ),
 8849                            );
 8850                        }
 8851                    }
 8852
 8853                    selection.set_head(new_head, SelectionGoal::None);
 8854                }
 8855            }
 8856
 8857            this.signature_help_state.set_backspace_pressed(true);
 8858            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8859                s.select(selections)
 8860            });
 8861            this.insert("", window, cx);
 8862            let empty_str: Arc<str> = Arc::from("");
 8863            for (buffer, edits) in linked_ranges {
 8864                let snapshot = buffer.read(cx).snapshot();
 8865                use text::ToPoint as TP;
 8866
 8867                let edits = edits
 8868                    .into_iter()
 8869                    .map(|range| {
 8870                        let end_point = TP::to_point(&range.end, &snapshot);
 8871                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8872
 8873                        if end_point == start_point {
 8874                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8875                                .saturating_sub(1);
 8876                            start_point =
 8877                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8878                        };
 8879
 8880                        (start_point..end_point, empty_str.clone())
 8881                    })
 8882                    .sorted_by_key(|(range, _)| range.start)
 8883                    .collect::<Vec<_>>();
 8884                buffer.update(cx, |this, cx| {
 8885                    this.edit(edits, None, cx);
 8886                })
 8887            }
 8888            this.refresh_inline_completion(true, false, window, cx);
 8889            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8890        });
 8891    }
 8892
 8893    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8894        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8895        self.transact(window, cx, |this, window, cx| {
 8896            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8897                s.move_with(|map, selection| {
 8898                    if selection.is_empty() {
 8899                        let cursor = movement::right(map, selection.head());
 8900                        selection.end = cursor;
 8901                        selection.reversed = true;
 8902                        selection.goal = SelectionGoal::None;
 8903                    }
 8904                })
 8905            });
 8906            this.insert("", window, cx);
 8907            this.refresh_inline_completion(true, false, window, cx);
 8908        });
 8909    }
 8910
 8911    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8912        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8913        if self.move_to_prev_snippet_tabstop(window, cx) {
 8914            return;
 8915        }
 8916        self.outdent(&Outdent, window, cx);
 8917    }
 8918
 8919    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8920        if self.move_to_next_snippet_tabstop(window, cx) {
 8921            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8922            return;
 8923        }
 8924        if self.read_only(cx) {
 8925            return;
 8926        }
 8927        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8928        let mut selections = self.selections.all_adjusted(cx);
 8929        let buffer = self.buffer.read(cx);
 8930        let snapshot = buffer.snapshot(cx);
 8931        let rows_iter = selections.iter().map(|s| s.head().row);
 8932        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8933
 8934        let has_some_cursor_in_whitespace = selections
 8935            .iter()
 8936            .filter(|selection| selection.is_empty())
 8937            .any(|selection| {
 8938                let cursor = selection.head();
 8939                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8940                cursor.column < current_indent.len
 8941            });
 8942
 8943        let mut edits = Vec::new();
 8944        let mut prev_edited_row = 0;
 8945        let mut row_delta = 0;
 8946        for selection in &mut selections {
 8947            if selection.start.row != prev_edited_row {
 8948                row_delta = 0;
 8949            }
 8950            prev_edited_row = selection.end.row;
 8951
 8952            // If the selection is non-empty, then increase the indentation of the selected lines.
 8953            if !selection.is_empty() {
 8954                row_delta =
 8955                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8956                continue;
 8957            }
 8958
 8959            let cursor = selection.head();
 8960            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8961            if let Some(suggested_indent) =
 8962                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8963            {
 8964                // Don't do anything if already at suggested indent
 8965                // and there is any other cursor which is not
 8966                if has_some_cursor_in_whitespace
 8967                    && cursor.column == current_indent.len
 8968                    && current_indent.len == suggested_indent.len
 8969                {
 8970                    continue;
 8971                }
 8972
 8973                // Adjust line and move cursor to suggested indent
 8974                // if cursor is not at suggested indent
 8975                if cursor.column < suggested_indent.len
 8976                    && cursor.column <= current_indent.len
 8977                    && current_indent.len <= suggested_indent.len
 8978                {
 8979                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8980                    selection.end = selection.start;
 8981                    if row_delta == 0 {
 8982                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8983                            cursor.row,
 8984                            current_indent,
 8985                            suggested_indent,
 8986                        ));
 8987                        row_delta = suggested_indent.len - current_indent.len;
 8988                    }
 8989                    continue;
 8990                }
 8991
 8992                // If current indent is more than suggested indent
 8993                // only move cursor to current indent and skip indent
 8994                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8995                    selection.start = Point::new(cursor.row, current_indent.len);
 8996                    selection.end = selection.start;
 8997                    continue;
 8998                }
 8999            }
 9000
 9001            // Otherwise, insert a hard or soft tab.
 9002            let settings = buffer.language_settings_at(cursor, cx);
 9003            let tab_size = if settings.hard_tabs {
 9004                IndentSize::tab()
 9005            } else {
 9006                let tab_size = settings.tab_size.get();
 9007                let indent_remainder = snapshot
 9008                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9009                    .flat_map(str::chars)
 9010                    .fold(row_delta % tab_size, |counter: u32, c| {
 9011                        if c == '\t' {
 9012                            0
 9013                        } else {
 9014                            (counter + 1) % tab_size
 9015                        }
 9016                    });
 9017
 9018                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9019                IndentSize::spaces(chars_to_next_tab_stop)
 9020            };
 9021            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9022            selection.end = selection.start;
 9023            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9024            row_delta += tab_size.len;
 9025        }
 9026
 9027        self.transact(window, cx, |this, window, cx| {
 9028            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9029            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9030                s.select(selections)
 9031            });
 9032            this.refresh_inline_completion(true, false, window, cx);
 9033        });
 9034    }
 9035
 9036    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9037        if self.read_only(cx) {
 9038            return;
 9039        }
 9040        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9041        let mut selections = self.selections.all::<Point>(cx);
 9042        let mut prev_edited_row = 0;
 9043        let mut row_delta = 0;
 9044        let mut edits = Vec::new();
 9045        let buffer = self.buffer.read(cx);
 9046        let snapshot = buffer.snapshot(cx);
 9047        for selection in &mut selections {
 9048            if selection.start.row != prev_edited_row {
 9049                row_delta = 0;
 9050            }
 9051            prev_edited_row = selection.end.row;
 9052
 9053            row_delta =
 9054                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9055        }
 9056
 9057        self.transact(window, cx, |this, window, cx| {
 9058            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9059            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9060                s.select(selections)
 9061            });
 9062        });
 9063    }
 9064
 9065    fn indent_selection(
 9066        buffer: &MultiBuffer,
 9067        snapshot: &MultiBufferSnapshot,
 9068        selection: &mut Selection<Point>,
 9069        edits: &mut Vec<(Range<Point>, String)>,
 9070        delta_for_start_row: u32,
 9071        cx: &App,
 9072    ) -> u32 {
 9073        let settings = buffer.language_settings_at(selection.start, cx);
 9074        let tab_size = settings.tab_size.get();
 9075        let indent_kind = if settings.hard_tabs {
 9076            IndentKind::Tab
 9077        } else {
 9078            IndentKind::Space
 9079        };
 9080        let mut start_row = selection.start.row;
 9081        let mut end_row = selection.end.row + 1;
 9082
 9083        // If a selection ends at the beginning of a line, don't indent
 9084        // that last line.
 9085        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9086            end_row -= 1;
 9087        }
 9088
 9089        // Avoid re-indenting a row that has already been indented by a
 9090        // previous selection, but still update this selection's column
 9091        // to reflect that indentation.
 9092        if delta_for_start_row > 0 {
 9093            start_row += 1;
 9094            selection.start.column += delta_for_start_row;
 9095            if selection.end.row == selection.start.row {
 9096                selection.end.column += delta_for_start_row;
 9097            }
 9098        }
 9099
 9100        let mut delta_for_end_row = 0;
 9101        let has_multiple_rows = start_row + 1 != end_row;
 9102        for row in start_row..end_row {
 9103            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9104            let indent_delta = match (current_indent.kind, indent_kind) {
 9105                (IndentKind::Space, IndentKind::Space) => {
 9106                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9107                    IndentSize::spaces(columns_to_next_tab_stop)
 9108                }
 9109                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9110                (_, IndentKind::Tab) => IndentSize::tab(),
 9111            };
 9112
 9113            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9114                0
 9115            } else {
 9116                selection.start.column
 9117            };
 9118            let row_start = Point::new(row, start);
 9119            edits.push((
 9120                row_start..row_start,
 9121                indent_delta.chars().collect::<String>(),
 9122            ));
 9123
 9124            // Update this selection's endpoints to reflect the indentation.
 9125            if row == selection.start.row {
 9126                selection.start.column += indent_delta.len;
 9127            }
 9128            if row == selection.end.row {
 9129                selection.end.column += indent_delta.len;
 9130                delta_for_end_row = indent_delta.len;
 9131            }
 9132        }
 9133
 9134        if selection.start.row == selection.end.row {
 9135            delta_for_start_row + delta_for_end_row
 9136        } else {
 9137            delta_for_end_row
 9138        }
 9139    }
 9140
 9141    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9142        if self.read_only(cx) {
 9143            return;
 9144        }
 9145        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9146        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9147        let selections = self.selections.all::<Point>(cx);
 9148        let mut deletion_ranges = Vec::new();
 9149        let mut last_outdent = None;
 9150        {
 9151            let buffer = self.buffer.read(cx);
 9152            let snapshot = buffer.snapshot(cx);
 9153            for selection in &selections {
 9154                let settings = buffer.language_settings_at(selection.start, cx);
 9155                let tab_size = settings.tab_size.get();
 9156                let mut rows = selection.spanned_rows(false, &display_map);
 9157
 9158                // Avoid re-outdenting a row that has already been outdented by a
 9159                // previous selection.
 9160                if let Some(last_row) = last_outdent {
 9161                    if last_row == rows.start {
 9162                        rows.start = rows.start.next_row();
 9163                    }
 9164                }
 9165                let has_multiple_rows = rows.len() > 1;
 9166                for row in rows.iter_rows() {
 9167                    let indent_size = snapshot.indent_size_for_line(row);
 9168                    if indent_size.len > 0 {
 9169                        let deletion_len = match indent_size.kind {
 9170                            IndentKind::Space => {
 9171                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9172                                if columns_to_prev_tab_stop == 0 {
 9173                                    tab_size
 9174                                } else {
 9175                                    columns_to_prev_tab_stop
 9176                                }
 9177                            }
 9178                            IndentKind::Tab => 1,
 9179                        };
 9180                        let start = if has_multiple_rows
 9181                            || deletion_len > selection.start.column
 9182                            || indent_size.len < selection.start.column
 9183                        {
 9184                            0
 9185                        } else {
 9186                            selection.start.column - deletion_len
 9187                        };
 9188                        deletion_ranges.push(
 9189                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9190                        );
 9191                        last_outdent = Some(row);
 9192                    }
 9193                }
 9194            }
 9195        }
 9196
 9197        self.transact(window, cx, |this, window, cx| {
 9198            this.buffer.update(cx, |buffer, cx| {
 9199                let empty_str: Arc<str> = Arc::default();
 9200                buffer.edit(
 9201                    deletion_ranges
 9202                        .into_iter()
 9203                        .map(|range| (range, empty_str.clone())),
 9204                    None,
 9205                    cx,
 9206                );
 9207            });
 9208            let selections = this.selections.all::<usize>(cx);
 9209            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9210                s.select(selections)
 9211            });
 9212        });
 9213    }
 9214
 9215    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9216        if self.read_only(cx) {
 9217            return;
 9218        }
 9219        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9220        let selections = self
 9221            .selections
 9222            .all::<usize>(cx)
 9223            .into_iter()
 9224            .map(|s| s.range());
 9225
 9226        self.transact(window, cx, |this, window, cx| {
 9227            this.buffer.update(cx, |buffer, cx| {
 9228                buffer.autoindent_ranges(selections, cx);
 9229            });
 9230            let selections = this.selections.all::<usize>(cx);
 9231            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9232                s.select(selections)
 9233            });
 9234        });
 9235    }
 9236
 9237    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9238        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9239        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9240        let selections = self.selections.all::<Point>(cx);
 9241
 9242        let mut new_cursors = Vec::new();
 9243        let mut edit_ranges = Vec::new();
 9244        let mut selections = selections.iter().peekable();
 9245        while let Some(selection) = selections.next() {
 9246            let mut rows = selection.spanned_rows(false, &display_map);
 9247            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9248
 9249            // Accumulate contiguous regions of rows that we want to delete.
 9250            while let Some(next_selection) = selections.peek() {
 9251                let next_rows = next_selection.spanned_rows(false, &display_map);
 9252                if next_rows.start <= rows.end {
 9253                    rows.end = next_rows.end;
 9254                    selections.next().unwrap();
 9255                } else {
 9256                    break;
 9257                }
 9258            }
 9259
 9260            let buffer = &display_map.buffer_snapshot;
 9261            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9262            let edit_end;
 9263            let cursor_buffer_row;
 9264            if buffer.max_point().row >= rows.end.0 {
 9265                // If there's a line after the range, delete the \n from the end of the row range
 9266                // and position the cursor on the next line.
 9267                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9268                cursor_buffer_row = rows.end;
 9269            } else {
 9270                // If there isn't a line after the range, delete the \n from the line before the
 9271                // start of the row range and position the cursor there.
 9272                edit_start = edit_start.saturating_sub(1);
 9273                edit_end = buffer.len();
 9274                cursor_buffer_row = rows.start.previous_row();
 9275            }
 9276
 9277            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9278            *cursor.column_mut() =
 9279                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9280
 9281            new_cursors.push((
 9282                selection.id,
 9283                buffer.anchor_after(cursor.to_point(&display_map)),
 9284            ));
 9285            edit_ranges.push(edit_start..edit_end);
 9286        }
 9287
 9288        self.transact(window, cx, |this, window, cx| {
 9289            let buffer = this.buffer.update(cx, |buffer, cx| {
 9290                let empty_str: Arc<str> = Arc::default();
 9291                buffer.edit(
 9292                    edit_ranges
 9293                        .into_iter()
 9294                        .map(|range| (range, empty_str.clone())),
 9295                    None,
 9296                    cx,
 9297                );
 9298                buffer.snapshot(cx)
 9299            });
 9300            let new_selections = new_cursors
 9301                .into_iter()
 9302                .map(|(id, cursor)| {
 9303                    let cursor = cursor.to_point(&buffer);
 9304                    Selection {
 9305                        id,
 9306                        start: cursor,
 9307                        end: cursor,
 9308                        reversed: false,
 9309                        goal: SelectionGoal::None,
 9310                    }
 9311                })
 9312                .collect();
 9313
 9314            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9315                s.select(new_selections);
 9316            });
 9317        });
 9318    }
 9319
 9320    pub fn join_lines_impl(
 9321        &mut self,
 9322        insert_whitespace: bool,
 9323        window: &mut Window,
 9324        cx: &mut Context<Self>,
 9325    ) {
 9326        if self.read_only(cx) {
 9327            return;
 9328        }
 9329        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9330        for selection in self.selections.all::<Point>(cx) {
 9331            let start = MultiBufferRow(selection.start.row);
 9332            // Treat single line selections as if they include the next line. Otherwise this action
 9333            // would do nothing for single line selections individual cursors.
 9334            let end = if selection.start.row == selection.end.row {
 9335                MultiBufferRow(selection.start.row + 1)
 9336            } else {
 9337                MultiBufferRow(selection.end.row)
 9338            };
 9339
 9340            if let Some(last_row_range) = row_ranges.last_mut() {
 9341                if start <= last_row_range.end {
 9342                    last_row_range.end = end;
 9343                    continue;
 9344                }
 9345            }
 9346            row_ranges.push(start..end);
 9347        }
 9348
 9349        let snapshot = self.buffer.read(cx).snapshot(cx);
 9350        let mut cursor_positions = Vec::new();
 9351        for row_range in &row_ranges {
 9352            let anchor = snapshot.anchor_before(Point::new(
 9353                row_range.end.previous_row().0,
 9354                snapshot.line_len(row_range.end.previous_row()),
 9355            ));
 9356            cursor_positions.push(anchor..anchor);
 9357        }
 9358
 9359        self.transact(window, cx, |this, window, cx| {
 9360            for row_range in row_ranges.into_iter().rev() {
 9361                for row in row_range.iter_rows().rev() {
 9362                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9363                    let next_line_row = row.next_row();
 9364                    let indent = snapshot.indent_size_for_line(next_line_row);
 9365                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9366
 9367                    let replace =
 9368                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9369                            " "
 9370                        } else {
 9371                            ""
 9372                        };
 9373
 9374                    this.buffer.update(cx, |buffer, cx| {
 9375                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9376                    });
 9377                }
 9378            }
 9379
 9380            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9381                s.select_anchor_ranges(cursor_positions)
 9382            });
 9383        });
 9384    }
 9385
 9386    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9387        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9388        self.join_lines_impl(true, window, cx);
 9389    }
 9390
 9391    pub fn sort_lines_case_sensitive(
 9392        &mut self,
 9393        _: &SortLinesCaseSensitive,
 9394        window: &mut Window,
 9395        cx: &mut Context<Self>,
 9396    ) {
 9397        self.manipulate_lines(window, cx, |lines| lines.sort())
 9398    }
 9399
 9400    pub fn sort_lines_case_insensitive(
 9401        &mut self,
 9402        _: &SortLinesCaseInsensitive,
 9403        window: &mut Window,
 9404        cx: &mut Context<Self>,
 9405    ) {
 9406        self.manipulate_lines(window, cx, |lines| {
 9407            lines.sort_by_key(|line| line.to_lowercase())
 9408        })
 9409    }
 9410
 9411    pub fn unique_lines_case_insensitive(
 9412        &mut self,
 9413        _: &UniqueLinesCaseInsensitive,
 9414        window: &mut Window,
 9415        cx: &mut Context<Self>,
 9416    ) {
 9417        self.manipulate_lines(window, cx, |lines| {
 9418            let mut seen = HashSet::default();
 9419            lines.retain(|line| seen.insert(line.to_lowercase()));
 9420        })
 9421    }
 9422
 9423    pub fn unique_lines_case_sensitive(
 9424        &mut self,
 9425        _: &UniqueLinesCaseSensitive,
 9426        window: &mut Window,
 9427        cx: &mut Context<Self>,
 9428    ) {
 9429        self.manipulate_lines(window, cx, |lines| {
 9430            let mut seen = HashSet::default();
 9431            lines.retain(|line| seen.insert(*line));
 9432        })
 9433    }
 9434
 9435    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9436        let Some(project) = self.project.clone() else {
 9437            return;
 9438        };
 9439        self.reload(project, window, cx)
 9440            .detach_and_notify_err(window, cx);
 9441    }
 9442
 9443    pub fn restore_file(
 9444        &mut self,
 9445        _: &::git::RestoreFile,
 9446        window: &mut Window,
 9447        cx: &mut Context<Self>,
 9448    ) {
 9449        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9450        let mut buffer_ids = HashSet::default();
 9451        let snapshot = self.buffer().read(cx).snapshot(cx);
 9452        for selection in self.selections.all::<usize>(cx) {
 9453            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9454        }
 9455
 9456        let buffer = self.buffer().read(cx);
 9457        let ranges = buffer_ids
 9458            .into_iter()
 9459            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9460            .collect::<Vec<_>>();
 9461
 9462        self.restore_hunks_in_ranges(ranges, window, cx);
 9463    }
 9464
 9465    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9466        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9467        let selections = self
 9468            .selections
 9469            .all(cx)
 9470            .into_iter()
 9471            .map(|s| s.range())
 9472            .collect();
 9473        self.restore_hunks_in_ranges(selections, window, cx);
 9474    }
 9475
 9476    pub fn restore_hunks_in_ranges(
 9477        &mut self,
 9478        ranges: Vec<Range<Point>>,
 9479        window: &mut Window,
 9480        cx: &mut Context<Editor>,
 9481    ) {
 9482        let mut revert_changes = HashMap::default();
 9483        let chunk_by = self
 9484            .snapshot(window, cx)
 9485            .hunks_for_ranges(ranges)
 9486            .into_iter()
 9487            .chunk_by(|hunk| hunk.buffer_id);
 9488        for (buffer_id, hunks) in &chunk_by {
 9489            let hunks = hunks.collect::<Vec<_>>();
 9490            for hunk in &hunks {
 9491                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9492            }
 9493            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9494        }
 9495        drop(chunk_by);
 9496        if !revert_changes.is_empty() {
 9497            self.transact(window, cx, |editor, window, cx| {
 9498                editor.restore(revert_changes, window, cx);
 9499            });
 9500        }
 9501    }
 9502
 9503    pub fn open_active_item_in_terminal(
 9504        &mut self,
 9505        _: &OpenInTerminal,
 9506        window: &mut Window,
 9507        cx: &mut Context<Self>,
 9508    ) {
 9509        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9510            let project_path = buffer.read(cx).project_path(cx)?;
 9511            let project = self.project.as_ref()?.read(cx);
 9512            let entry = project.entry_for_path(&project_path, cx)?;
 9513            let parent = match &entry.canonical_path {
 9514                Some(canonical_path) => canonical_path.to_path_buf(),
 9515                None => project.absolute_path(&project_path, cx)?,
 9516            }
 9517            .parent()?
 9518            .to_path_buf();
 9519            Some(parent)
 9520        }) {
 9521            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9522        }
 9523    }
 9524
 9525    fn set_breakpoint_context_menu(
 9526        &mut self,
 9527        display_row: DisplayRow,
 9528        position: Option<Anchor>,
 9529        clicked_point: gpui::Point<Pixels>,
 9530        window: &mut Window,
 9531        cx: &mut Context<Self>,
 9532    ) {
 9533        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9534            return;
 9535        }
 9536        let source = self
 9537            .buffer
 9538            .read(cx)
 9539            .snapshot(cx)
 9540            .anchor_before(Point::new(display_row.0, 0u32));
 9541
 9542        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9543
 9544        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9545            self,
 9546            source,
 9547            clicked_point,
 9548            context_menu,
 9549            window,
 9550            cx,
 9551        );
 9552    }
 9553
 9554    fn add_edit_breakpoint_block(
 9555        &mut self,
 9556        anchor: Anchor,
 9557        breakpoint: &Breakpoint,
 9558        edit_action: BreakpointPromptEditAction,
 9559        window: &mut Window,
 9560        cx: &mut Context<Self>,
 9561    ) {
 9562        let weak_editor = cx.weak_entity();
 9563        let bp_prompt = cx.new(|cx| {
 9564            BreakpointPromptEditor::new(
 9565                weak_editor,
 9566                anchor,
 9567                breakpoint.clone(),
 9568                edit_action,
 9569                window,
 9570                cx,
 9571            )
 9572        });
 9573
 9574        let height = bp_prompt.update(cx, |this, cx| {
 9575            this.prompt
 9576                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9577        });
 9578        let cloned_prompt = bp_prompt.clone();
 9579        let blocks = vec![BlockProperties {
 9580            style: BlockStyle::Sticky,
 9581            placement: BlockPlacement::Above(anchor),
 9582            height: Some(height),
 9583            render: Arc::new(move |cx| {
 9584                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9585                cloned_prompt.clone().into_any_element()
 9586            }),
 9587            priority: 0,
 9588            render_in_minimap: true,
 9589        }];
 9590
 9591        let focus_handle = bp_prompt.focus_handle(cx);
 9592        window.focus(&focus_handle);
 9593
 9594        let block_ids = self.insert_blocks(blocks, None, cx);
 9595        bp_prompt.update(cx, |prompt, _| {
 9596            prompt.add_block_ids(block_ids);
 9597        });
 9598    }
 9599
 9600    pub(crate) fn breakpoint_at_row(
 9601        &self,
 9602        row: u32,
 9603        window: &mut Window,
 9604        cx: &mut Context<Self>,
 9605    ) -> Option<(Anchor, Breakpoint)> {
 9606        let snapshot = self.snapshot(window, cx);
 9607        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9608
 9609        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9610    }
 9611
 9612    pub(crate) fn breakpoint_at_anchor(
 9613        &self,
 9614        breakpoint_position: Anchor,
 9615        snapshot: &EditorSnapshot,
 9616        cx: &mut Context<Self>,
 9617    ) -> Option<(Anchor, Breakpoint)> {
 9618        let project = self.project.clone()?;
 9619
 9620        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9621            snapshot
 9622                .buffer_snapshot
 9623                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9624        })?;
 9625
 9626        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9627        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9628        let buffer_snapshot = buffer.read(cx).snapshot();
 9629
 9630        let row = buffer_snapshot
 9631            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9632            .row;
 9633
 9634        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9635        let anchor_end = snapshot
 9636            .buffer_snapshot
 9637            .anchor_after(Point::new(row, line_len));
 9638
 9639        let bp = self
 9640            .breakpoint_store
 9641            .as_ref()?
 9642            .read_with(cx, |breakpoint_store, cx| {
 9643                breakpoint_store
 9644                    .breakpoints(
 9645                        &buffer,
 9646                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9647                        &buffer_snapshot,
 9648                        cx,
 9649                    )
 9650                    .next()
 9651                    .and_then(|(bp, _)| {
 9652                        let breakpoint_row = buffer_snapshot
 9653                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9654                            .row;
 9655
 9656                        if breakpoint_row == row {
 9657                            snapshot
 9658                                .buffer_snapshot
 9659                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9660                                .map(|position| (position, bp.bp.clone()))
 9661                        } else {
 9662                            None
 9663                        }
 9664                    })
 9665            });
 9666        bp
 9667    }
 9668
 9669    pub fn edit_log_breakpoint(
 9670        &mut self,
 9671        _: &EditLogBreakpoint,
 9672        window: &mut Window,
 9673        cx: &mut Context<Self>,
 9674    ) {
 9675        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9676            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9677                message: None,
 9678                state: BreakpointState::Enabled,
 9679                condition: None,
 9680                hit_condition: None,
 9681            });
 9682
 9683            self.add_edit_breakpoint_block(
 9684                anchor,
 9685                &breakpoint,
 9686                BreakpointPromptEditAction::Log,
 9687                window,
 9688                cx,
 9689            );
 9690        }
 9691    }
 9692
 9693    fn breakpoints_at_cursors(
 9694        &self,
 9695        window: &mut Window,
 9696        cx: &mut Context<Self>,
 9697    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9698        let snapshot = self.snapshot(window, cx);
 9699        let cursors = self
 9700            .selections
 9701            .disjoint_anchors()
 9702            .into_iter()
 9703            .map(|selection| {
 9704                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9705
 9706                let breakpoint_position = self
 9707                    .breakpoint_at_row(cursor_position.row, window, cx)
 9708                    .map(|bp| bp.0)
 9709                    .unwrap_or_else(|| {
 9710                        snapshot
 9711                            .display_snapshot
 9712                            .buffer_snapshot
 9713                            .anchor_after(Point::new(cursor_position.row, 0))
 9714                    });
 9715
 9716                let breakpoint = self
 9717                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9718                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9719
 9720                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9721            })
 9722            // 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.
 9723            .collect::<HashMap<Anchor, _>>();
 9724
 9725        cursors.into_iter().collect()
 9726    }
 9727
 9728    pub fn enable_breakpoint(
 9729        &mut self,
 9730        _: &crate::actions::EnableBreakpoint,
 9731        window: &mut Window,
 9732        cx: &mut Context<Self>,
 9733    ) {
 9734        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9735            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9736                continue;
 9737            };
 9738            self.edit_breakpoint_at_anchor(
 9739                anchor,
 9740                breakpoint,
 9741                BreakpointEditAction::InvertState,
 9742                cx,
 9743            );
 9744        }
 9745    }
 9746
 9747    pub fn disable_breakpoint(
 9748        &mut self,
 9749        _: &crate::actions::DisableBreakpoint,
 9750        window: &mut Window,
 9751        cx: &mut Context<Self>,
 9752    ) {
 9753        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9754            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9755                continue;
 9756            };
 9757            self.edit_breakpoint_at_anchor(
 9758                anchor,
 9759                breakpoint,
 9760                BreakpointEditAction::InvertState,
 9761                cx,
 9762            );
 9763        }
 9764    }
 9765
 9766    pub fn toggle_breakpoint(
 9767        &mut self,
 9768        _: &crate::actions::ToggleBreakpoint,
 9769        window: &mut Window,
 9770        cx: &mut Context<Self>,
 9771    ) {
 9772        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9773            if let Some(breakpoint) = breakpoint {
 9774                self.edit_breakpoint_at_anchor(
 9775                    anchor,
 9776                    breakpoint,
 9777                    BreakpointEditAction::Toggle,
 9778                    cx,
 9779                );
 9780            } else {
 9781                self.edit_breakpoint_at_anchor(
 9782                    anchor,
 9783                    Breakpoint::new_standard(),
 9784                    BreakpointEditAction::Toggle,
 9785                    cx,
 9786                );
 9787            }
 9788        }
 9789    }
 9790
 9791    pub fn edit_breakpoint_at_anchor(
 9792        &mut self,
 9793        breakpoint_position: Anchor,
 9794        breakpoint: Breakpoint,
 9795        edit_action: BreakpointEditAction,
 9796        cx: &mut Context<Self>,
 9797    ) {
 9798        let Some(breakpoint_store) = &self.breakpoint_store else {
 9799            return;
 9800        };
 9801
 9802        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9803            if breakpoint_position == Anchor::min() {
 9804                self.buffer()
 9805                    .read(cx)
 9806                    .excerpt_buffer_ids()
 9807                    .into_iter()
 9808                    .next()
 9809            } else {
 9810                None
 9811            }
 9812        }) else {
 9813            return;
 9814        };
 9815
 9816        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9817            return;
 9818        };
 9819
 9820        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9821            breakpoint_store.toggle_breakpoint(
 9822                buffer,
 9823                BreakpointWithPosition {
 9824                    position: breakpoint_position.text_anchor,
 9825                    bp: breakpoint,
 9826                },
 9827                edit_action,
 9828                cx,
 9829            );
 9830        });
 9831
 9832        cx.notify();
 9833    }
 9834
 9835    #[cfg(any(test, feature = "test-support"))]
 9836    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9837        self.breakpoint_store.clone()
 9838    }
 9839
 9840    pub fn prepare_restore_change(
 9841        &self,
 9842        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9843        hunk: &MultiBufferDiffHunk,
 9844        cx: &mut App,
 9845    ) -> Option<()> {
 9846        if hunk.is_created_file() {
 9847            return None;
 9848        }
 9849        let buffer = self.buffer.read(cx);
 9850        let diff = buffer.diff_for(hunk.buffer_id)?;
 9851        let buffer = buffer.buffer(hunk.buffer_id)?;
 9852        let buffer = buffer.read(cx);
 9853        let original_text = diff
 9854            .read(cx)
 9855            .base_text()
 9856            .as_rope()
 9857            .slice(hunk.diff_base_byte_range.clone());
 9858        let buffer_snapshot = buffer.snapshot();
 9859        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9860        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9861            probe
 9862                .0
 9863                .start
 9864                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9865                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9866        }) {
 9867            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9868            Some(())
 9869        } else {
 9870            None
 9871        }
 9872    }
 9873
 9874    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9875        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9876    }
 9877
 9878    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9879        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9880    }
 9881
 9882    fn manipulate_lines<Fn>(
 9883        &mut self,
 9884        window: &mut Window,
 9885        cx: &mut Context<Self>,
 9886        mut callback: Fn,
 9887    ) where
 9888        Fn: FnMut(&mut Vec<&str>),
 9889    {
 9890        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9891
 9892        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9893        let buffer = self.buffer.read(cx).snapshot(cx);
 9894
 9895        let mut edits = Vec::new();
 9896
 9897        let selections = self.selections.all::<Point>(cx);
 9898        let mut selections = selections.iter().peekable();
 9899        let mut contiguous_row_selections = Vec::new();
 9900        let mut new_selections = Vec::new();
 9901        let mut added_lines = 0;
 9902        let mut removed_lines = 0;
 9903
 9904        while let Some(selection) = selections.next() {
 9905            let (start_row, end_row) = consume_contiguous_rows(
 9906                &mut contiguous_row_selections,
 9907                selection,
 9908                &display_map,
 9909                &mut selections,
 9910            );
 9911
 9912            let start_point = Point::new(start_row.0, 0);
 9913            let end_point = Point::new(
 9914                end_row.previous_row().0,
 9915                buffer.line_len(end_row.previous_row()),
 9916            );
 9917            let text = buffer
 9918                .text_for_range(start_point..end_point)
 9919                .collect::<String>();
 9920
 9921            let mut lines = text.split('\n').collect_vec();
 9922
 9923            let lines_before = lines.len();
 9924            callback(&mut lines);
 9925            let lines_after = lines.len();
 9926
 9927            edits.push((start_point..end_point, lines.join("\n")));
 9928
 9929            // Selections must change based on added and removed line count
 9930            let start_row =
 9931                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9932            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9933            new_selections.push(Selection {
 9934                id: selection.id,
 9935                start: start_row,
 9936                end: end_row,
 9937                goal: SelectionGoal::None,
 9938                reversed: selection.reversed,
 9939            });
 9940
 9941            if lines_after > lines_before {
 9942                added_lines += lines_after - lines_before;
 9943            } else if lines_before > lines_after {
 9944                removed_lines += lines_before - lines_after;
 9945            }
 9946        }
 9947
 9948        self.transact(window, cx, |this, window, cx| {
 9949            let buffer = this.buffer.update(cx, |buffer, cx| {
 9950                buffer.edit(edits, None, cx);
 9951                buffer.snapshot(cx)
 9952            });
 9953
 9954            // Recalculate offsets on newly edited buffer
 9955            let new_selections = new_selections
 9956                .iter()
 9957                .map(|s| {
 9958                    let start_point = Point::new(s.start.0, 0);
 9959                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9960                    Selection {
 9961                        id: s.id,
 9962                        start: buffer.point_to_offset(start_point),
 9963                        end: buffer.point_to_offset(end_point),
 9964                        goal: s.goal,
 9965                        reversed: s.reversed,
 9966                    }
 9967                })
 9968                .collect();
 9969
 9970            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9971                s.select(new_selections);
 9972            });
 9973
 9974            this.request_autoscroll(Autoscroll::fit(), cx);
 9975        });
 9976    }
 9977
 9978    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9979        self.manipulate_text(window, cx, |text| {
 9980            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9981            if has_upper_case_characters {
 9982                text.to_lowercase()
 9983            } else {
 9984                text.to_uppercase()
 9985            }
 9986        })
 9987    }
 9988
 9989    pub fn convert_to_upper_case(
 9990        &mut self,
 9991        _: &ConvertToUpperCase,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) {
 9995        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9996    }
 9997
 9998    pub fn convert_to_lower_case(
 9999        &mut self,
10000        _: &ConvertToLowerCase,
10001        window: &mut Window,
10002        cx: &mut Context<Self>,
10003    ) {
10004        self.manipulate_text(window, cx, |text| text.to_lowercase())
10005    }
10006
10007    pub fn convert_to_title_case(
10008        &mut self,
10009        _: &ConvertToTitleCase,
10010        window: &mut Window,
10011        cx: &mut Context<Self>,
10012    ) {
10013        self.manipulate_text(window, cx, |text| {
10014            text.split('\n')
10015                .map(|line| line.to_case(Case::Title))
10016                .join("\n")
10017        })
10018    }
10019
10020    pub fn convert_to_snake_case(
10021        &mut self,
10022        _: &ConvertToSnakeCase,
10023        window: &mut Window,
10024        cx: &mut Context<Self>,
10025    ) {
10026        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10027    }
10028
10029    pub fn convert_to_kebab_case(
10030        &mut self,
10031        _: &ConvertToKebabCase,
10032        window: &mut Window,
10033        cx: &mut Context<Self>,
10034    ) {
10035        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10036    }
10037
10038    pub fn convert_to_upper_camel_case(
10039        &mut self,
10040        _: &ConvertToUpperCamelCase,
10041        window: &mut Window,
10042        cx: &mut Context<Self>,
10043    ) {
10044        self.manipulate_text(window, cx, |text| {
10045            text.split('\n')
10046                .map(|line| line.to_case(Case::UpperCamel))
10047                .join("\n")
10048        })
10049    }
10050
10051    pub fn convert_to_lower_camel_case(
10052        &mut self,
10053        _: &ConvertToLowerCamelCase,
10054        window: &mut Window,
10055        cx: &mut Context<Self>,
10056    ) {
10057        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10058    }
10059
10060    pub fn convert_to_opposite_case(
10061        &mut self,
10062        _: &ConvertToOppositeCase,
10063        window: &mut Window,
10064        cx: &mut Context<Self>,
10065    ) {
10066        self.manipulate_text(window, cx, |text| {
10067            text.chars()
10068                .fold(String::with_capacity(text.len()), |mut t, c| {
10069                    if c.is_uppercase() {
10070                        t.extend(c.to_lowercase());
10071                    } else {
10072                        t.extend(c.to_uppercase());
10073                    }
10074                    t
10075                })
10076        })
10077    }
10078
10079    pub fn convert_to_rot13(
10080        &mut self,
10081        _: &ConvertToRot13,
10082        window: &mut Window,
10083        cx: &mut Context<Self>,
10084    ) {
10085        self.manipulate_text(window, cx, |text| {
10086            text.chars()
10087                .map(|c| match c {
10088                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10089                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10090                    _ => c,
10091                })
10092                .collect()
10093        })
10094    }
10095
10096    pub fn convert_to_rot47(
10097        &mut self,
10098        _: &ConvertToRot47,
10099        window: &mut Window,
10100        cx: &mut Context<Self>,
10101    ) {
10102        self.manipulate_text(window, cx, |text| {
10103            text.chars()
10104                .map(|c| {
10105                    let code_point = c as u32;
10106                    if code_point >= 33 && code_point <= 126 {
10107                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10108                    }
10109                    c
10110                })
10111                .collect()
10112        })
10113    }
10114
10115    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10116    where
10117        Fn: FnMut(&str) -> String,
10118    {
10119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10120        let buffer = self.buffer.read(cx).snapshot(cx);
10121
10122        let mut new_selections = Vec::new();
10123        let mut edits = Vec::new();
10124        let mut selection_adjustment = 0i32;
10125
10126        for selection in self.selections.all::<usize>(cx) {
10127            let selection_is_empty = selection.is_empty();
10128
10129            let (start, end) = if selection_is_empty {
10130                let word_range = movement::surrounding_word(
10131                    &display_map,
10132                    selection.start.to_display_point(&display_map),
10133                );
10134                let start = word_range.start.to_offset(&display_map, Bias::Left);
10135                let end = word_range.end.to_offset(&display_map, Bias::Left);
10136                (start, end)
10137            } else {
10138                (selection.start, selection.end)
10139            };
10140
10141            let text = buffer.text_for_range(start..end).collect::<String>();
10142            let old_length = text.len() as i32;
10143            let text = callback(&text);
10144
10145            new_selections.push(Selection {
10146                start: (start as i32 - selection_adjustment) as usize,
10147                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10148                goal: SelectionGoal::None,
10149                ..selection
10150            });
10151
10152            selection_adjustment += old_length - text.len() as i32;
10153
10154            edits.push((start..end, text));
10155        }
10156
10157        self.transact(window, cx, |this, window, cx| {
10158            this.buffer.update(cx, |buffer, cx| {
10159                buffer.edit(edits, None, cx);
10160            });
10161
10162            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10163                s.select(new_selections);
10164            });
10165
10166            this.request_autoscroll(Autoscroll::fit(), cx);
10167        });
10168    }
10169
10170    pub fn duplicate(
10171        &mut self,
10172        upwards: bool,
10173        whole_lines: bool,
10174        window: &mut Window,
10175        cx: &mut Context<Self>,
10176    ) {
10177        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10178
10179        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10180        let buffer = &display_map.buffer_snapshot;
10181        let selections = self.selections.all::<Point>(cx);
10182
10183        let mut edits = Vec::new();
10184        let mut selections_iter = selections.iter().peekable();
10185        while let Some(selection) = selections_iter.next() {
10186            let mut rows = selection.spanned_rows(false, &display_map);
10187            // duplicate line-wise
10188            if whole_lines || selection.start == selection.end {
10189                // Avoid duplicating the same lines twice.
10190                while let Some(next_selection) = selections_iter.peek() {
10191                    let next_rows = next_selection.spanned_rows(false, &display_map);
10192                    if next_rows.start < rows.end {
10193                        rows.end = next_rows.end;
10194                        selections_iter.next().unwrap();
10195                    } else {
10196                        break;
10197                    }
10198                }
10199
10200                // Copy the text from the selected row region and splice it either at the start
10201                // or end of the region.
10202                let start = Point::new(rows.start.0, 0);
10203                let end = Point::new(
10204                    rows.end.previous_row().0,
10205                    buffer.line_len(rows.end.previous_row()),
10206                );
10207                let text = buffer
10208                    .text_for_range(start..end)
10209                    .chain(Some("\n"))
10210                    .collect::<String>();
10211                let insert_location = if upwards {
10212                    Point::new(rows.end.0, 0)
10213                } else {
10214                    start
10215                };
10216                edits.push((insert_location..insert_location, text));
10217            } else {
10218                // duplicate character-wise
10219                let start = selection.start;
10220                let end = selection.end;
10221                let text = buffer.text_for_range(start..end).collect::<String>();
10222                edits.push((selection.end..selection.end, text));
10223            }
10224        }
10225
10226        self.transact(window, cx, |this, _, cx| {
10227            this.buffer.update(cx, |buffer, cx| {
10228                buffer.edit(edits, None, cx);
10229            });
10230
10231            this.request_autoscroll(Autoscroll::fit(), cx);
10232        });
10233    }
10234
10235    pub fn duplicate_line_up(
10236        &mut self,
10237        _: &DuplicateLineUp,
10238        window: &mut Window,
10239        cx: &mut Context<Self>,
10240    ) {
10241        self.duplicate(true, true, window, cx);
10242    }
10243
10244    pub fn duplicate_line_down(
10245        &mut self,
10246        _: &DuplicateLineDown,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        self.duplicate(false, true, window, cx);
10251    }
10252
10253    pub fn duplicate_selection(
10254        &mut self,
10255        _: &DuplicateSelection,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        self.duplicate(false, false, window, cx);
10260    }
10261
10262    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10263        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10264
10265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10266        let buffer = self.buffer.read(cx).snapshot(cx);
10267
10268        let mut edits = Vec::new();
10269        let mut unfold_ranges = Vec::new();
10270        let mut refold_creases = Vec::new();
10271
10272        let selections = self.selections.all::<Point>(cx);
10273        let mut selections = selections.iter().peekable();
10274        let mut contiguous_row_selections = Vec::new();
10275        let mut new_selections = Vec::new();
10276
10277        while let Some(selection) = selections.next() {
10278            // Find all the selections that span a contiguous row range
10279            let (start_row, end_row) = consume_contiguous_rows(
10280                &mut contiguous_row_selections,
10281                selection,
10282                &display_map,
10283                &mut selections,
10284            );
10285
10286            // Move the text spanned by the row range to be before the line preceding the row range
10287            if start_row.0 > 0 {
10288                let range_to_move = Point::new(
10289                    start_row.previous_row().0,
10290                    buffer.line_len(start_row.previous_row()),
10291                )
10292                    ..Point::new(
10293                        end_row.previous_row().0,
10294                        buffer.line_len(end_row.previous_row()),
10295                    );
10296                let insertion_point = display_map
10297                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10298                    .0;
10299
10300                // Don't move lines across excerpts
10301                if buffer
10302                    .excerpt_containing(insertion_point..range_to_move.end)
10303                    .is_some()
10304                {
10305                    let text = buffer
10306                        .text_for_range(range_to_move.clone())
10307                        .flat_map(|s| s.chars())
10308                        .skip(1)
10309                        .chain(['\n'])
10310                        .collect::<String>();
10311
10312                    edits.push((
10313                        buffer.anchor_after(range_to_move.start)
10314                            ..buffer.anchor_before(range_to_move.end),
10315                        String::new(),
10316                    ));
10317                    let insertion_anchor = buffer.anchor_after(insertion_point);
10318                    edits.push((insertion_anchor..insertion_anchor, text));
10319
10320                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10321
10322                    // Move selections up
10323                    new_selections.extend(contiguous_row_selections.drain(..).map(
10324                        |mut selection| {
10325                            selection.start.row -= row_delta;
10326                            selection.end.row -= row_delta;
10327                            selection
10328                        },
10329                    ));
10330
10331                    // Move folds up
10332                    unfold_ranges.push(range_to_move.clone());
10333                    for fold in display_map.folds_in_range(
10334                        buffer.anchor_before(range_to_move.start)
10335                            ..buffer.anchor_after(range_to_move.end),
10336                    ) {
10337                        let mut start = fold.range.start.to_point(&buffer);
10338                        let mut end = fold.range.end.to_point(&buffer);
10339                        start.row -= row_delta;
10340                        end.row -= row_delta;
10341                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10342                    }
10343                }
10344            }
10345
10346            // If we didn't move line(s), preserve the existing selections
10347            new_selections.append(&mut contiguous_row_selections);
10348        }
10349
10350        self.transact(window, cx, |this, window, cx| {
10351            this.unfold_ranges(&unfold_ranges, true, true, cx);
10352            this.buffer.update(cx, |buffer, cx| {
10353                for (range, text) in edits {
10354                    buffer.edit([(range, text)], None, cx);
10355                }
10356            });
10357            this.fold_creases(refold_creases, true, window, cx);
10358            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10359                s.select(new_selections);
10360            })
10361        });
10362    }
10363
10364    pub fn move_line_down(
10365        &mut self,
10366        _: &MoveLineDown,
10367        window: &mut Window,
10368        cx: &mut Context<Self>,
10369    ) {
10370        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10371
10372        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10373        let buffer = self.buffer.read(cx).snapshot(cx);
10374
10375        let mut edits = Vec::new();
10376        let mut unfold_ranges = Vec::new();
10377        let mut refold_creases = Vec::new();
10378
10379        let selections = self.selections.all::<Point>(cx);
10380        let mut selections = selections.iter().peekable();
10381        let mut contiguous_row_selections = Vec::new();
10382        let mut new_selections = Vec::new();
10383
10384        while let Some(selection) = selections.next() {
10385            // Find all the selections that span a contiguous row range
10386            let (start_row, end_row) = consume_contiguous_rows(
10387                &mut contiguous_row_selections,
10388                selection,
10389                &display_map,
10390                &mut selections,
10391            );
10392
10393            // Move the text spanned by the row range to be after the last line of the row range
10394            if end_row.0 <= buffer.max_point().row {
10395                let range_to_move =
10396                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10397                let insertion_point = display_map
10398                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10399                    .0;
10400
10401                // Don't move lines across excerpt boundaries
10402                if buffer
10403                    .excerpt_containing(range_to_move.start..insertion_point)
10404                    .is_some()
10405                {
10406                    let mut text = String::from("\n");
10407                    text.extend(buffer.text_for_range(range_to_move.clone()));
10408                    text.pop(); // Drop trailing newline
10409                    edits.push((
10410                        buffer.anchor_after(range_to_move.start)
10411                            ..buffer.anchor_before(range_to_move.end),
10412                        String::new(),
10413                    ));
10414                    let insertion_anchor = buffer.anchor_after(insertion_point);
10415                    edits.push((insertion_anchor..insertion_anchor, text));
10416
10417                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10418
10419                    // Move selections down
10420                    new_selections.extend(contiguous_row_selections.drain(..).map(
10421                        |mut selection| {
10422                            selection.start.row += row_delta;
10423                            selection.end.row += row_delta;
10424                            selection
10425                        },
10426                    ));
10427
10428                    // Move folds down
10429                    unfold_ranges.push(range_to_move.clone());
10430                    for fold in display_map.folds_in_range(
10431                        buffer.anchor_before(range_to_move.start)
10432                            ..buffer.anchor_after(range_to_move.end),
10433                    ) {
10434                        let mut start = fold.range.start.to_point(&buffer);
10435                        let mut end = fold.range.end.to_point(&buffer);
10436                        start.row += row_delta;
10437                        end.row += row_delta;
10438                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10439                    }
10440                }
10441            }
10442
10443            // If we didn't move line(s), preserve the existing selections
10444            new_selections.append(&mut contiguous_row_selections);
10445        }
10446
10447        self.transact(window, cx, |this, window, cx| {
10448            this.unfold_ranges(&unfold_ranges, true, true, cx);
10449            this.buffer.update(cx, |buffer, cx| {
10450                for (range, text) in edits {
10451                    buffer.edit([(range, text)], None, cx);
10452                }
10453            });
10454            this.fold_creases(refold_creases, true, window, cx);
10455            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10456                s.select(new_selections)
10457            });
10458        });
10459    }
10460
10461    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10462        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10463        let text_layout_details = &self.text_layout_details(window);
10464        self.transact(window, cx, |this, window, cx| {
10465            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10466                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10467                s.move_with(|display_map, selection| {
10468                    if !selection.is_empty() {
10469                        return;
10470                    }
10471
10472                    let mut head = selection.head();
10473                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10474                    if head.column() == display_map.line_len(head.row()) {
10475                        transpose_offset = display_map
10476                            .buffer_snapshot
10477                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10478                    }
10479
10480                    if transpose_offset == 0 {
10481                        return;
10482                    }
10483
10484                    *head.column_mut() += 1;
10485                    head = display_map.clip_point(head, Bias::Right);
10486                    let goal = SelectionGoal::HorizontalPosition(
10487                        display_map
10488                            .x_for_display_point(head, text_layout_details)
10489                            .into(),
10490                    );
10491                    selection.collapse_to(head, goal);
10492
10493                    let transpose_start = display_map
10494                        .buffer_snapshot
10495                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10496                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10497                        let transpose_end = display_map
10498                            .buffer_snapshot
10499                            .clip_offset(transpose_offset + 1, Bias::Right);
10500                        if let Some(ch) =
10501                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10502                        {
10503                            edits.push((transpose_start..transpose_offset, String::new()));
10504                            edits.push((transpose_end..transpose_end, ch.to_string()));
10505                        }
10506                    }
10507                });
10508                edits
10509            });
10510            this.buffer
10511                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10512            let selections = this.selections.all::<usize>(cx);
10513            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10514                s.select(selections);
10515            });
10516        });
10517    }
10518
10519    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10520        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10521        self.rewrap_impl(RewrapOptions::default(), cx)
10522    }
10523
10524    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10525        let buffer = self.buffer.read(cx).snapshot(cx);
10526        let selections = self.selections.all::<Point>(cx);
10527        let mut selections = selections.iter().peekable();
10528
10529        let mut edits = Vec::new();
10530        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10531
10532        while let Some(selection) = selections.next() {
10533            let mut start_row = selection.start.row;
10534            let mut end_row = selection.end.row;
10535
10536            // Skip selections that overlap with a range that has already been rewrapped.
10537            let selection_range = start_row..end_row;
10538            if rewrapped_row_ranges
10539                .iter()
10540                .any(|range| range.overlaps(&selection_range))
10541            {
10542                continue;
10543            }
10544
10545            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10546
10547            // Since not all lines in the selection may be at the same indent
10548            // level, choose the indent size that is the most common between all
10549            // of the lines.
10550            //
10551            // If there is a tie, we use the deepest indent.
10552            let (indent_size, indent_end) = {
10553                let mut indent_size_occurrences = HashMap::default();
10554                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10555
10556                for row in start_row..=end_row {
10557                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10558                    rows_by_indent_size.entry(indent).or_default().push(row);
10559                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10560                }
10561
10562                let indent_size = indent_size_occurrences
10563                    .into_iter()
10564                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10565                    .map(|(indent, _)| indent)
10566                    .unwrap_or_default();
10567                let row = rows_by_indent_size[&indent_size][0];
10568                let indent_end = Point::new(row, indent_size.len);
10569
10570                (indent_size, indent_end)
10571            };
10572
10573            let mut line_prefix = indent_size.chars().collect::<String>();
10574
10575            let mut inside_comment = false;
10576            if let Some(comment_prefix) =
10577                buffer
10578                    .language_scope_at(selection.head())
10579                    .and_then(|language| {
10580                        language
10581                            .line_comment_prefixes()
10582                            .iter()
10583                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10584                            .cloned()
10585                    })
10586            {
10587                line_prefix.push_str(&comment_prefix);
10588                inside_comment = true;
10589            }
10590
10591            let language_settings = buffer.language_settings_at(selection.head(), cx);
10592            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10593                RewrapBehavior::InComments => inside_comment,
10594                RewrapBehavior::InSelections => !selection.is_empty(),
10595                RewrapBehavior::Anywhere => true,
10596            };
10597
10598            let should_rewrap = options.override_language_settings
10599                || allow_rewrap_based_on_language
10600                || self.hard_wrap.is_some();
10601            if !should_rewrap {
10602                continue;
10603            }
10604
10605            if selection.is_empty() {
10606                'expand_upwards: while start_row > 0 {
10607                    let prev_row = start_row - 1;
10608                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10609                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10610                    {
10611                        start_row = prev_row;
10612                    } else {
10613                        break 'expand_upwards;
10614                    }
10615                }
10616
10617                'expand_downwards: while end_row < buffer.max_point().row {
10618                    let next_row = end_row + 1;
10619                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10620                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10621                    {
10622                        end_row = next_row;
10623                    } else {
10624                        break 'expand_downwards;
10625                    }
10626                }
10627            }
10628
10629            let start = Point::new(start_row, 0);
10630            let start_offset = start.to_offset(&buffer);
10631            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10632            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10633            let Some(lines_without_prefixes) = selection_text
10634                .lines()
10635                .map(|line| {
10636                    line.strip_prefix(&line_prefix)
10637                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10638                        .with_context(|| {
10639                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10640                        })
10641                })
10642                .collect::<Result<Vec<_>, _>>()
10643                .log_err()
10644            else {
10645                continue;
10646            };
10647
10648            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10649                buffer
10650                    .language_settings_at(Point::new(start_row, 0), cx)
10651                    .preferred_line_length as usize
10652            });
10653            let wrapped_text = wrap_with_prefix(
10654                line_prefix,
10655                lines_without_prefixes.join("\n"),
10656                wrap_column,
10657                tab_size,
10658                options.preserve_existing_whitespace,
10659            );
10660
10661            // TODO: should always use char-based diff while still supporting cursor behavior that
10662            // matches vim.
10663            let mut diff_options = DiffOptions::default();
10664            if options.override_language_settings {
10665                diff_options.max_word_diff_len = 0;
10666                diff_options.max_word_diff_line_count = 0;
10667            } else {
10668                diff_options.max_word_diff_len = usize::MAX;
10669                diff_options.max_word_diff_line_count = usize::MAX;
10670            }
10671
10672            for (old_range, new_text) in
10673                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10674            {
10675                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10676                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10677                edits.push((edit_start..edit_end, new_text));
10678            }
10679
10680            rewrapped_row_ranges.push(start_row..=end_row);
10681        }
10682
10683        self.buffer
10684            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10685    }
10686
10687    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10688        let mut text = String::new();
10689        let buffer = self.buffer.read(cx).snapshot(cx);
10690        let mut selections = self.selections.all::<Point>(cx);
10691        let mut clipboard_selections = Vec::with_capacity(selections.len());
10692        {
10693            let max_point = buffer.max_point();
10694            let mut is_first = true;
10695            for selection in &mut selections {
10696                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10697                if is_entire_line {
10698                    selection.start = Point::new(selection.start.row, 0);
10699                    if !selection.is_empty() && selection.end.column == 0 {
10700                        selection.end = cmp::min(max_point, selection.end);
10701                    } else {
10702                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10703                    }
10704                    selection.goal = SelectionGoal::None;
10705                }
10706                if is_first {
10707                    is_first = false;
10708                } else {
10709                    text += "\n";
10710                }
10711                let mut len = 0;
10712                for chunk in buffer.text_for_range(selection.start..selection.end) {
10713                    text.push_str(chunk);
10714                    len += chunk.len();
10715                }
10716                clipboard_selections.push(ClipboardSelection {
10717                    len,
10718                    is_entire_line,
10719                    first_line_indent: buffer
10720                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10721                        .len,
10722                });
10723            }
10724        }
10725
10726        self.transact(window, cx, |this, window, cx| {
10727            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10728                s.select(selections);
10729            });
10730            this.insert("", window, cx);
10731        });
10732        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10733    }
10734
10735    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10736        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10737        let item = self.cut_common(window, cx);
10738        cx.write_to_clipboard(item);
10739    }
10740
10741    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10742        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10743        self.change_selections(None, window, cx, |s| {
10744            s.move_with(|snapshot, sel| {
10745                if sel.is_empty() {
10746                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10747                }
10748            });
10749        });
10750        let item = self.cut_common(window, cx);
10751        cx.set_global(KillRing(item))
10752    }
10753
10754    pub fn kill_ring_yank(
10755        &mut self,
10756        _: &KillRingYank,
10757        window: &mut Window,
10758        cx: &mut Context<Self>,
10759    ) {
10760        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10761        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10762            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10763                (kill_ring.text().to_string(), kill_ring.metadata_json())
10764            } else {
10765                return;
10766            }
10767        } else {
10768            return;
10769        };
10770        self.do_paste(&text, metadata, false, window, cx);
10771    }
10772
10773    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10774        self.do_copy(true, cx);
10775    }
10776
10777    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10778        self.do_copy(false, cx);
10779    }
10780
10781    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10782        let selections = self.selections.all::<Point>(cx);
10783        let buffer = self.buffer.read(cx).read(cx);
10784        let mut text = String::new();
10785
10786        let mut clipboard_selections = Vec::with_capacity(selections.len());
10787        {
10788            let max_point = buffer.max_point();
10789            let mut is_first = true;
10790            for selection in &selections {
10791                let mut start = selection.start;
10792                let mut end = selection.end;
10793                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10794                if is_entire_line {
10795                    start = Point::new(start.row, 0);
10796                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10797                }
10798
10799                let mut trimmed_selections = Vec::new();
10800                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10801                    let row = MultiBufferRow(start.row);
10802                    let first_indent = buffer.indent_size_for_line(row);
10803                    if first_indent.len == 0 || start.column > first_indent.len {
10804                        trimmed_selections.push(start..end);
10805                    } else {
10806                        trimmed_selections.push(
10807                            Point::new(row.0, first_indent.len)
10808                                ..Point::new(row.0, buffer.line_len(row)),
10809                        );
10810                        for row in start.row + 1..=end.row {
10811                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10812                            if row == end.row {
10813                                line_len = end.column;
10814                            }
10815                            if line_len == 0 {
10816                                trimmed_selections
10817                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10818                                continue;
10819                            }
10820                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10821                            if row_indent_size.len >= first_indent.len {
10822                                trimmed_selections.push(
10823                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10824                                );
10825                            } else {
10826                                trimmed_selections.clear();
10827                                trimmed_selections.push(start..end);
10828                                break;
10829                            }
10830                        }
10831                    }
10832                } else {
10833                    trimmed_selections.push(start..end);
10834                }
10835
10836                for trimmed_range in trimmed_selections {
10837                    if is_first {
10838                        is_first = false;
10839                    } else {
10840                        text += "\n";
10841                    }
10842                    let mut len = 0;
10843                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10844                        text.push_str(chunk);
10845                        len += chunk.len();
10846                    }
10847                    clipboard_selections.push(ClipboardSelection {
10848                        len,
10849                        is_entire_line,
10850                        first_line_indent: buffer
10851                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10852                            .len,
10853                    });
10854                }
10855            }
10856        }
10857
10858        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10859            text,
10860            clipboard_selections,
10861        ));
10862    }
10863
10864    pub fn do_paste(
10865        &mut self,
10866        text: &String,
10867        clipboard_selections: Option<Vec<ClipboardSelection>>,
10868        handle_entire_lines: bool,
10869        window: &mut Window,
10870        cx: &mut Context<Self>,
10871    ) {
10872        if self.read_only(cx) {
10873            return;
10874        }
10875
10876        let clipboard_text = Cow::Borrowed(text);
10877
10878        self.transact(window, cx, |this, window, cx| {
10879            if let Some(mut clipboard_selections) = clipboard_selections {
10880                let old_selections = this.selections.all::<usize>(cx);
10881                let all_selections_were_entire_line =
10882                    clipboard_selections.iter().all(|s| s.is_entire_line);
10883                let first_selection_indent_column =
10884                    clipboard_selections.first().map(|s| s.first_line_indent);
10885                if clipboard_selections.len() != old_selections.len() {
10886                    clipboard_selections.drain(..);
10887                }
10888                let cursor_offset = this.selections.last::<usize>(cx).head();
10889                let mut auto_indent_on_paste = true;
10890
10891                this.buffer.update(cx, |buffer, cx| {
10892                    let snapshot = buffer.read(cx);
10893                    auto_indent_on_paste = snapshot
10894                        .language_settings_at(cursor_offset, cx)
10895                        .auto_indent_on_paste;
10896
10897                    let mut start_offset = 0;
10898                    let mut edits = Vec::new();
10899                    let mut original_indent_columns = Vec::new();
10900                    for (ix, selection) in old_selections.iter().enumerate() {
10901                        let to_insert;
10902                        let entire_line;
10903                        let original_indent_column;
10904                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10905                            let end_offset = start_offset + clipboard_selection.len;
10906                            to_insert = &clipboard_text[start_offset..end_offset];
10907                            entire_line = clipboard_selection.is_entire_line;
10908                            start_offset = end_offset + 1;
10909                            original_indent_column = Some(clipboard_selection.first_line_indent);
10910                        } else {
10911                            to_insert = clipboard_text.as_str();
10912                            entire_line = all_selections_were_entire_line;
10913                            original_indent_column = first_selection_indent_column
10914                        }
10915
10916                        // If the corresponding selection was empty when this slice of the
10917                        // clipboard text was written, then the entire line containing the
10918                        // selection was copied. If this selection is also currently empty,
10919                        // then paste the line before the current line of the buffer.
10920                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10921                            let column = selection.start.to_point(&snapshot).column as usize;
10922                            let line_start = selection.start - column;
10923                            line_start..line_start
10924                        } else {
10925                            selection.range()
10926                        };
10927
10928                        edits.push((range, to_insert));
10929                        original_indent_columns.push(original_indent_column);
10930                    }
10931                    drop(snapshot);
10932
10933                    buffer.edit(
10934                        edits,
10935                        if auto_indent_on_paste {
10936                            Some(AutoindentMode::Block {
10937                                original_indent_columns,
10938                            })
10939                        } else {
10940                            None
10941                        },
10942                        cx,
10943                    );
10944                });
10945
10946                let selections = this.selections.all::<usize>(cx);
10947                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10948                    s.select(selections)
10949                });
10950            } else {
10951                this.insert(&clipboard_text, window, cx);
10952            }
10953        });
10954    }
10955
10956    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10957        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10958        if let Some(item) = cx.read_from_clipboard() {
10959            let entries = item.entries();
10960
10961            match entries.first() {
10962                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10963                // of all the pasted entries.
10964                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10965                    .do_paste(
10966                        clipboard_string.text(),
10967                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10968                        true,
10969                        window,
10970                        cx,
10971                    ),
10972                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10973            }
10974        }
10975    }
10976
10977    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10978        if self.read_only(cx) {
10979            return;
10980        }
10981
10982        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10983
10984        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10985            if let Some((selections, _)) =
10986                self.selection_history.transaction(transaction_id).cloned()
10987            {
10988                self.change_selections(None, window, cx, |s| {
10989                    s.select_anchors(selections.to_vec());
10990                });
10991            } else {
10992                log::error!(
10993                    "No entry in selection_history found for undo. \
10994                     This may correspond to a bug where undo does not update the selection. \
10995                     If this is occurring, please add details to \
10996                     https://github.com/zed-industries/zed/issues/22692"
10997                );
10998            }
10999            self.request_autoscroll(Autoscroll::fit(), cx);
11000            self.unmark_text(window, cx);
11001            self.refresh_inline_completion(true, false, window, cx);
11002            cx.emit(EditorEvent::Edited { transaction_id });
11003            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11004        }
11005    }
11006
11007    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11008        if self.read_only(cx) {
11009            return;
11010        }
11011
11012        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11013
11014        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11015            if let Some((_, Some(selections))) =
11016                self.selection_history.transaction(transaction_id).cloned()
11017            {
11018                self.change_selections(None, window, cx, |s| {
11019                    s.select_anchors(selections.to_vec());
11020                });
11021            } else {
11022                log::error!(
11023                    "No entry in selection_history found for redo. \
11024                     This may correspond to a bug where undo does not update the selection. \
11025                     If this is occurring, please add details to \
11026                     https://github.com/zed-industries/zed/issues/22692"
11027                );
11028            }
11029            self.request_autoscroll(Autoscroll::fit(), cx);
11030            self.unmark_text(window, cx);
11031            self.refresh_inline_completion(true, false, window, cx);
11032            cx.emit(EditorEvent::Edited { transaction_id });
11033        }
11034    }
11035
11036    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11037        self.buffer
11038            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11039    }
11040
11041    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11042        self.buffer
11043            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11044    }
11045
11046    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11047        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11048        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11049            s.move_with(|map, selection| {
11050                let cursor = if selection.is_empty() {
11051                    movement::left(map, selection.start)
11052                } else {
11053                    selection.start
11054                };
11055                selection.collapse_to(cursor, SelectionGoal::None);
11056            });
11057        })
11058    }
11059
11060    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11061        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11062        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11063            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11064        })
11065    }
11066
11067    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11068        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11069        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11070            s.move_with(|map, selection| {
11071                let cursor = if selection.is_empty() {
11072                    movement::right(map, selection.end)
11073                } else {
11074                    selection.end
11075                };
11076                selection.collapse_to(cursor, SelectionGoal::None)
11077            });
11078        })
11079    }
11080
11081    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11082        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11083        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11084            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11085        })
11086    }
11087
11088    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11089        if self.take_rename(true, window, cx).is_some() {
11090            return;
11091        }
11092
11093        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11094            cx.propagate();
11095            return;
11096        }
11097
11098        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11099
11100        let text_layout_details = &self.text_layout_details(window);
11101        let selection_count = self.selections.count();
11102        let first_selection = self.selections.first_anchor();
11103
11104        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11105            s.move_with(|map, selection| {
11106                if !selection.is_empty() {
11107                    selection.goal = SelectionGoal::None;
11108                }
11109                let (cursor, goal) = movement::up(
11110                    map,
11111                    selection.start,
11112                    selection.goal,
11113                    false,
11114                    text_layout_details,
11115                );
11116                selection.collapse_to(cursor, goal);
11117            });
11118        });
11119
11120        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11121        {
11122            cx.propagate();
11123        }
11124    }
11125
11126    pub fn move_up_by_lines(
11127        &mut self,
11128        action: &MoveUpByLines,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        if self.take_rename(true, window, cx).is_some() {
11133            return;
11134        }
11135
11136        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11137            cx.propagate();
11138            return;
11139        }
11140
11141        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11142
11143        let text_layout_details = &self.text_layout_details(window);
11144
11145        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11146            s.move_with(|map, selection| {
11147                if !selection.is_empty() {
11148                    selection.goal = SelectionGoal::None;
11149                }
11150                let (cursor, goal) = movement::up_by_rows(
11151                    map,
11152                    selection.start,
11153                    action.lines,
11154                    selection.goal,
11155                    false,
11156                    text_layout_details,
11157                );
11158                selection.collapse_to(cursor, goal);
11159            });
11160        })
11161    }
11162
11163    pub fn move_down_by_lines(
11164        &mut self,
11165        action: &MoveDownByLines,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        if self.take_rename(true, window, cx).is_some() {
11170            return;
11171        }
11172
11173        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11174            cx.propagate();
11175            return;
11176        }
11177
11178        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11179
11180        let text_layout_details = &self.text_layout_details(window);
11181
11182        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11183            s.move_with(|map, selection| {
11184                if !selection.is_empty() {
11185                    selection.goal = SelectionGoal::None;
11186                }
11187                let (cursor, goal) = movement::down_by_rows(
11188                    map,
11189                    selection.start,
11190                    action.lines,
11191                    selection.goal,
11192                    false,
11193                    text_layout_details,
11194                );
11195                selection.collapse_to(cursor, goal);
11196            });
11197        })
11198    }
11199
11200    pub fn select_down_by_lines(
11201        &mut self,
11202        action: &SelectDownByLines,
11203        window: &mut Window,
11204        cx: &mut Context<Self>,
11205    ) {
11206        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11207        let text_layout_details = &self.text_layout_details(window);
11208        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11209            s.move_heads_with(|map, head, goal| {
11210                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11211            })
11212        })
11213    }
11214
11215    pub fn select_up_by_lines(
11216        &mut self,
11217        action: &SelectUpByLines,
11218        window: &mut Window,
11219        cx: &mut Context<Self>,
11220    ) {
11221        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11222        let text_layout_details = &self.text_layout_details(window);
11223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11224            s.move_heads_with(|map, head, goal| {
11225                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11226            })
11227        })
11228    }
11229
11230    pub fn select_page_up(
11231        &mut self,
11232        _: &SelectPageUp,
11233        window: &mut Window,
11234        cx: &mut Context<Self>,
11235    ) {
11236        let Some(row_count) = self.visible_row_count() else {
11237            return;
11238        };
11239
11240        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11241
11242        let text_layout_details = &self.text_layout_details(window);
11243
11244        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11245            s.move_heads_with(|map, head, goal| {
11246                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11247            })
11248        })
11249    }
11250
11251    pub fn move_page_up(
11252        &mut self,
11253        action: &MovePageUp,
11254        window: &mut Window,
11255        cx: &mut Context<Self>,
11256    ) {
11257        if self.take_rename(true, window, cx).is_some() {
11258            return;
11259        }
11260
11261        if self
11262            .context_menu
11263            .borrow_mut()
11264            .as_mut()
11265            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11266            .unwrap_or(false)
11267        {
11268            return;
11269        }
11270
11271        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11272            cx.propagate();
11273            return;
11274        }
11275
11276        let Some(row_count) = self.visible_row_count() else {
11277            return;
11278        };
11279
11280        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11281
11282        let autoscroll = if action.center_cursor {
11283            Autoscroll::center()
11284        } else {
11285            Autoscroll::fit()
11286        };
11287
11288        let text_layout_details = &self.text_layout_details(window);
11289
11290        self.change_selections(Some(autoscroll), window, cx, |s| {
11291            s.move_with(|map, selection| {
11292                if !selection.is_empty() {
11293                    selection.goal = SelectionGoal::None;
11294                }
11295                let (cursor, goal) = movement::up_by_rows(
11296                    map,
11297                    selection.end,
11298                    row_count,
11299                    selection.goal,
11300                    false,
11301                    text_layout_details,
11302                );
11303                selection.collapse_to(cursor, goal);
11304            });
11305        });
11306    }
11307
11308    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11309        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11310        let text_layout_details = &self.text_layout_details(window);
11311        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11312            s.move_heads_with(|map, head, goal| {
11313                movement::up(map, head, goal, false, text_layout_details)
11314            })
11315        })
11316    }
11317
11318    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11319        self.take_rename(true, window, cx);
11320
11321        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11322            cx.propagate();
11323            return;
11324        }
11325
11326        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11327
11328        let text_layout_details = &self.text_layout_details(window);
11329        let selection_count = self.selections.count();
11330        let first_selection = self.selections.first_anchor();
11331
11332        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11333            s.move_with(|map, selection| {
11334                if !selection.is_empty() {
11335                    selection.goal = SelectionGoal::None;
11336                }
11337                let (cursor, goal) = movement::down(
11338                    map,
11339                    selection.end,
11340                    selection.goal,
11341                    false,
11342                    text_layout_details,
11343                );
11344                selection.collapse_to(cursor, goal);
11345            });
11346        });
11347
11348        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11349        {
11350            cx.propagate();
11351        }
11352    }
11353
11354    pub fn select_page_down(
11355        &mut self,
11356        _: &SelectPageDown,
11357        window: &mut Window,
11358        cx: &mut Context<Self>,
11359    ) {
11360        let Some(row_count) = self.visible_row_count() else {
11361            return;
11362        };
11363
11364        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11365
11366        let text_layout_details = &self.text_layout_details(window);
11367
11368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11369            s.move_heads_with(|map, head, goal| {
11370                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11371            })
11372        })
11373    }
11374
11375    pub fn move_page_down(
11376        &mut self,
11377        action: &MovePageDown,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        if self.take_rename(true, window, cx).is_some() {
11382            return;
11383        }
11384
11385        if self
11386            .context_menu
11387            .borrow_mut()
11388            .as_mut()
11389            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11390            .unwrap_or(false)
11391        {
11392            return;
11393        }
11394
11395        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11396            cx.propagate();
11397            return;
11398        }
11399
11400        let Some(row_count) = self.visible_row_count() else {
11401            return;
11402        };
11403
11404        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11405
11406        let autoscroll = if action.center_cursor {
11407            Autoscroll::center()
11408        } else {
11409            Autoscroll::fit()
11410        };
11411
11412        let text_layout_details = &self.text_layout_details(window);
11413        self.change_selections(Some(autoscroll), window, cx, |s| {
11414            s.move_with(|map, selection| {
11415                if !selection.is_empty() {
11416                    selection.goal = SelectionGoal::None;
11417                }
11418                let (cursor, goal) = movement::down_by_rows(
11419                    map,
11420                    selection.end,
11421                    row_count,
11422                    selection.goal,
11423                    false,
11424                    text_layout_details,
11425                );
11426                selection.collapse_to(cursor, goal);
11427            });
11428        });
11429    }
11430
11431    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11432        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11433        let text_layout_details = &self.text_layout_details(window);
11434        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11435            s.move_heads_with(|map, head, goal| {
11436                movement::down(map, head, goal, false, text_layout_details)
11437            })
11438        });
11439    }
11440
11441    pub fn context_menu_first(
11442        &mut self,
11443        _: &ContextMenuFirst,
11444        _window: &mut Window,
11445        cx: &mut Context<Self>,
11446    ) {
11447        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11448            context_menu.select_first(self.completion_provider.as_deref(), cx);
11449        }
11450    }
11451
11452    pub fn context_menu_prev(
11453        &mut self,
11454        _: &ContextMenuPrevious,
11455        _window: &mut Window,
11456        cx: &mut Context<Self>,
11457    ) {
11458        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11459            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11460        }
11461    }
11462
11463    pub fn context_menu_next(
11464        &mut self,
11465        _: &ContextMenuNext,
11466        _window: &mut Window,
11467        cx: &mut Context<Self>,
11468    ) {
11469        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11470            context_menu.select_next(self.completion_provider.as_deref(), cx);
11471        }
11472    }
11473
11474    pub fn context_menu_last(
11475        &mut self,
11476        _: &ContextMenuLast,
11477        _window: &mut Window,
11478        cx: &mut Context<Self>,
11479    ) {
11480        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11481            context_menu.select_last(self.completion_provider.as_deref(), cx);
11482        }
11483    }
11484
11485    pub fn move_to_previous_word_start(
11486        &mut self,
11487        _: &MoveToPreviousWordStart,
11488        window: &mut Window,
11489        cx: &mut Context<Self>,
11490    ) {
11491        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11492        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11493            s.move_cursors_with(|map, head, _| {
11494                (
11495                    movement::previous_word_start(map, head),
11496                    SelectionGoal::None,
11497                )
11498            });
11499        })
11500    }
11501
11502    pub fn move_to_previous_subword_start(
11503        &mut self,
11504        _: &MoveToPreviousSubwordStart,
11505        window: &mut Window,
11506        cx: &mut Context<Self>,
11507    ) {
11508        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11509        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11510            s.move_cursors_with(|map, head, _| {
11511                (
11512                    movement::previous_subword_start(map, head),
11513                    SelectionGoal::None,
11514                )
11515            });
11516        })
11517    }
11518
11519    pub fn select_to_previous_word_start(
11520        &mut self,
11521        _: &SelectToPreviousWordStart,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11526        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11527            s.move_heads_with(|map, head, _| {
11528                (
11529                    movement::previous_word_start(map, head),
11530                    SelectionGoal::None,
11531                )
11532            });
11533        })
11534    }
11535
11536    pub fn select_to_previous_subword_start(
11537        &mut self,
11538        _: &SelectToPreviousSubwordStart,
11539        window: &mut Window,
11540        cx: &mut Context<Self>,
11541    ) {
11542        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11543        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11544            s.move_heads_with(|map, head, _| {
11545                (
11546                    movement::previous_subword_start(map, head),
11547                    SelectionGoal::None,
11548                )
11549            });
11550        })
11551    }
11552
11553    pub fn delete_to_previous_word_start(
11554        &mut self,
11555        action: &DeleteToPreviousWordStart,
11556        window: &mut Window,
11557        cx: &mut Context<Self>,
11558    ) {
11559        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11560        self.transact(window, cx, |this, window, cx| {
11561            this.select_autoclose_pair(window, cx);
11562            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11563                s.move_with(|map, selection| {
11564                    if selection.is_empty() {
11565                        let cursor = if action.ignore_newlines {
11566                            movement::previous_word_start(map, selection.head())
11567                        } else {
11568                            movement::previous_word_start_or_newline(map, selection.head())
11569                        };
11570                        selection.set_head(cursor, SelectionGoal::None);
11571                    }
11572                });
11573            });
11574            this.insert("", window, cx);
11575        });
11576    }
11577
11578    pub fn delete_to_previous_subword_start(
11579        &mut self,
11580        _: &DeleteToPreviousSubwordStart,
11581        window: &mut Window,
11582        cx: &mut Context<Self>,
11583    ) {
11584        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11585        self.transact(window, cx, |this, window, cx| {
11586            this.select_autoclose_pair(window, cx);
11587            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11588                s.move_with(|map, selection| {
11589                    if selection.is_empty() {
11590                        let cursor = movement::previous_subword_start(map, selection.head());
11591                        selection.set_head(cursor, SelectionGoal::None);
11592                    }
11593                });
11594            });
11595            this.insert("", window, cx);
11596        });
11597    }
11598
11599    pub fn move_to_next_word_end(
11600        &mut self,
11601        _: &MoveToNextWordEnd,
11602        window: &mut Window,
11603        cx: &mut Context<Self>,
11604    ) {
11605        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11606        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11607            s.move_cursors_with(|map, head, _| {
11608                (movement::next_word_end(map, head), SelectionGoal::None)
11609            });
11610        })
11611    }
11612
11613    pub fn move_to_next_subword_end(
11614        &mut self,
11615        _: &MoveToNextSubwordEnd,
11616        window: &mut Window,
11617        cx: &mut Context<Self>,
11618    ) {
11619        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11620        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11621            s.move_cursors_with(|map, head, _| {
11622                (movement::next_subword_end(map, head), SelectionGoal::None)
11623            });
11624        })
11625    }
11626
11627    pub fn select_to_next_word_end(
11628        &mut self,
11629        _: &SelectToNextWordEnd,
11630        window: &mut Window,
11631        cx: &mut Context<Self>,
11632    ) {
11633        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11634        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11635            s.move_heads_with(|map, head, _| {
11636                (movement::next_word_end(map, head), SelectionGoal::None)
11637            });
11638        })
11639    }
11640
11641    pub fn select_to_next_subword_end(
11642        &mut self,
11643        _: &SelectToNextSubwordEnd,
11644        window: &mut Window,
11645        cx: &mut Context<Self>,
11646    ) {
11647        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11648        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11649            s.move_heads_with(|map, head, _| {
11650                (movement::next_subword_end(map, head), SelectionGoal::None)
11651            });
11652        })
11653    }
11654
11655    pub fn delete_to_next_word_end(
11656        &mut self,
11657        action: &DeleteToNextWordEnd,
11658        window: &mut Window,
11659        cx: &mut Context<Self>,
11660    ) {
11661        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11662        self.transact(window, cx, |this, window, cx| {
11663            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11664                s.move_with(|map, selection| {
11665                    if selection.is_empty() {
11666                        let cursor = if action.ignore_newlines {
11667                            movement::next_word_end(map, selection.head())
11668                        } else {
11669                            movement::next_word_end_or_newline(map, selection.head())
11670                        };
11671                        selection.set_head(cursor, SelectionGoal::None);
11672                    }
11673                });
11674            });
11675            this.insert("", window, cx);
11676        });
11677    }
11678
11679    pub fn delete_to_next_subword_end(
11680        &mut self,
11681        _: &DeleteToNextSubwordEnd,
11682        window: &mut Window,
11683        cx: &mut Context<Self>,
11684    ) {
11685        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11686        self.transact(window, cx, |this, window, cx| {
11687            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11688                s.move_with(|map, selection| {
11689                    if selection.is_empty() {
11690                        let cursor = movement::next_subword_end(map, selection.head());
11691                        selection.set_head(cursor, SelectionGoal::None);
11692                    }
11693                });
11694            });
11695            this.insert("", window, cx);
11696        });
11697    }
11698
11699    pub fn move_to_beginning_of_line(
11700        &mut self,
11701        action: &MoveToBeginningOfLine,
11702        window: &mut Window,
11703        cx: &mut Context<Self>,
11704    ) {
11705        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11706        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11707            s.move_cursors_with(|map, head, _| {
11708                (
11709                    movement::indented_line_beginning(
11710                        map,
11711                        head,
11712                        action.stop_at_soft_wraps,
11713                        action.stop_at_indent,
11714                    ),
11715                    SelectionGoal::None,
11716                )
11717            });
11718        })
11719    }
11720
11721    pub fn select_to_beginning_of_line(
11722        &mut self,
11723        action: &SelectToBeginningOfLine,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11728        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11729            s.move_heads_with(|map, head, _| {
11730                (
11731                    movement::indented_line_beginning(
11732                        map,
11733                        head,
11734                        action.stop_at_soft_wraps,
11735                        action.stop_at_indent,
11736                    ),
11737                    SelectionGoal::None,
11738                )
11739            });
11740        });
11741    }
11742
11743    pub fn delete_to_beginning_of_line(
11744        &mut self,
11745        action: &DeleteToBeginningOfLine,
11746        window: &mut Window,
11747        cx: &mut Context<Self>,
11748    ) {
11749        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11750        self.transact(window, cx, |this, window, cx| {
11751            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11752                s.move_with(|_, selection| {
11753                    selection.reversed = true;
11754                });
11755            });
11756
11757            this.select_to_beginning_of_line(
11758                &SelectToBeginningOfLine {
11759                    stop_at_soft_wraps: false,
11760                    stop_at_indent: action.stop_at_indent,
11761                },
11762                window,
11763                cx,
11764            );
11765            this.backspace(&Backspace, window, cx);
11766        });
11767    }
11768
11769    pub fn move_to_end_of_line(
11770        &mut self,
11771        action: &MoveToEndOfLine,
11772        window: &mut Window,
11773        cx: &mut Context<Self>,
11774    ) {
11775        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11776        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11777            s.move_cursors_with(|map, head, _| {
11778                (
11779                    movement::line_end(map, head, action.stop_at_soft_wraps),
11780                    SelectionGoal::None,
11781                )
11782            });
11783        })
11784    }
11785
11786    pub fn select_to_end_of_line(
11787        &mut self,
11788        action: &SelectToEndOfLine,
11789        window: &mut Window,
11790        cx: &mut Context<Self>,
11791    ) {
11792        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11793        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11794            s.move_heads_with(|map, head, _| {
11795                (
11796                    movement::line_end(map, head, action.stop_at_soft_wraps),
11797                    SelectionGoal::None,
11798                )
11799            });
11800        })
11801    }
11802
11803    pub fn delete_to_end_of_line(
11804        &mut self,
11805        _: &DeleteToEndOfLine,
11806        window: &mut Window,
11807        cx: &mut Context<Self>,
11808    ) {
11809        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11810        self.transact(window, cx, |this, window, cx| {
11811            this.select_to_end_of_line(
11812                &SelectToEndOfLine {
11813                    stop_at_soft_wraps: false,
11814                },
11815                window,
11816                cx,
11817            );
11818            this.delete(&Delete, window, cx);
11819        });
11820    }
11821
11822    pub fn cut_to_end_of_line(
11823        &mut self,
11824        _: &CutToEndOfLine,
11825        window: &mut Window,
11826        cx: &mut Context<Self>,
11827    ) {
11828        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11829        self.transact(window, cx, |this, window, cx| {
11830            this.select_to_end_of_line(
11831                &SelectToEndOfLine {
11832                    stop_at_soft_wraps: false,
11833                },
11834                window,
11835                cx,
11836            );
11837            this.cut(&Cut, window, cx);
11838        });
11839    }
11840
11841    pub fn move_to_start_of_paragraph(
11842        &mut self,
11843        _: &MoveToStartOfParagraph,
11844        window: &mut Window,
11845        cx: &mut Context<Self>,
11846    ) {
11847        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11848            cx.propagate();
11849            return;
11850        }
11851        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11852        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11853            s.move_with(|map, selection| {
11854                selection.collapse_to(
11855                    movement::start_of_paragraph(map, selection.head(), 1),
11856                    SelectionGoal::None,
11857                )
11858            });
11859        })
11860    }
11861
11862    pub fn move_to_end_of_paragraph(
11863        &mut self,
11864        _: &MoveToEndOfParagraph,
11865        window: &mut Window,
11866        cx: &mut Context<Self>,
11867    ) {
11868        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11869            cx.propagate();
11870            return;
11871        }
11872        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11873        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11874            s.move_with(|map, selection| {
11875                selection.collapse_to(
11876                    movement::end_of_paragraph(map, selection.head(), 1),
11877                    SelectionGoal::None,
11878                )
11879            });
11880        })
11881    }
11882
11883    pub fn select_to_start_of_paragraph(
11884        &mut self,
11885        _: &SelectToStartOfParagraph,
11886        window: &mut Window,
11887        cx: &mut Context<Self>,
11888    ) {
11889        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11890            cx.propagate();
11891            return;
11892        }
11893        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11894        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11895            s.move_heads_with(|map, head, _| {
11896                (
11897                    movement::start_of_paragraph(map, head, 1),
11898                    SelectionGoal::None,
11899                )
11900            });
11901        })
11902    }
11903
11904    pub fn select_to_end_of_paragraph(
11905        &mut self,
11906        _: &SelectToEndOfParagraph,
11907        window: &mut Window,
11908        cx: &mut Context<Self>,
11909    ) {
11910        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11911            cx.propagate();
11912            return;
11913        }
11914        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11915        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11916            s.move_heads_with(|map, head, _| {
11917                (
11918                    movement::end_of_paragraph(map, head, 1),
11919                    SelectionGoal::None,
11920                )
11921            });
11922        })
11923    }
11924
11925    pub fn move_to_start_of_excerpt(
11926        &mut self,
11927        _: &MoveToStartOfExcerpt,
11928        window: &mut Window,
11929        cx: &mut Context<Self>,
11930    ) {
11931        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11932            cx.propagate();
11933            return;
11934        }
11935        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11936        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11937            s.move_with(|map, selection| {
11938                selection.collapse_to(
11939                    movement::start_of_excerpt(
11940                        map,
11941                        selection.head(),
11942                        workspace::searchable::Direction::Prev,
11943                    ),
11944                    SelectionGoal::None,
11945                )
11946            });
11947        })
11948    }
11949
11950    pub fn move_to_start_of_next_excerpt(
11951        &mut self,
11952        _: &MoveToStartOfNextExcerpt,
11953        window: &mut Window,
11954        cx: &mut Context<Self>,
11955    ) {
11956        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11957            cx.propagate();
11958            return;
11959        }
11960
11961        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11962            s.move_with(|map, selection| {
11963                selection.collapse_to(
11964                    movement::start_of_excerpt(
11965                        map,
11966                        selection.head(),
11967                        workspace::searchable::Direction::Next,
11968                    ),
11969                    SelectionGoal::None,
11970                )
11971            });
11972        })
11973    }
11974
11975    pub fn move_to_end_of_excerpt(
11976        &mut self,
11977        _: &MoveToEndOfExcerpt,
11978        window: &mut Window,
11979        cx: &mut Context<Self>,
11980    ) {
11981        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11982            cx.propagate();
11983            return;
11984        }
11985        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11986        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11987            s.move_with(|map, selection| {
11988                selection.collapse_to(
11989                    movement::end_of_excerpt(
11990                        map,
11991                        selection.head(),
11992                        workspace::searchable::Direction::Next,
11993                    ),
11994                    SelectionGoal::None,
11995                )
11996            });
11997        })
11998    }
11999
12000    pub fn move_to_end_of_previous_excerpt(
12001        &mut self,
12002        _: &MoveToEndOfPreviousExcerpt,
12003        window: &mut Window,
12004        cx: &mut Context<Self>,
12005    ) {
12006        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12007            cx.propagate();
12008            return;
12009        }
12010        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12011        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12012            s.move_with(|map, selection| {
12013                selection.collapse_to(
12014                    movement::end_of_excerpt(
12015                        map,
12016                        selection.head(),
12017                        workspace::searchable::Direction::Prev,
12018                    ),
12019                    SelectionGoal::None,
12020                )
12021            });
12022        })
12023    }
12024
12025    pub fn select_to_start_of_excerpt(
12026        &mut self,
12027        _: &SelectToStartOfExcerpt,
12028        window: &mut Window,
12029        cx: &mut Context<Self>,
12030    ) {
12031        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12032            cx.propagate();
12033            return;
12034        }
12035        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12036        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12037            s.move_heads_with(|map, head, _| {
12038                (
12039                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12040                    SelectionGoal::None,
12041                )
12042            });
12043        })
12044    }
12045
12046    pub fn select_to_start_of_next_excerpt(
12047        &mut self,
12048        _: &SelectToStartOfNextExcerpt,
12049        window: &mut Window,
12050        cx: &mut Context<Self>,
12051    ) {
12052        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12053            cx.propagate();
12054            return;
12055        }
12056        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12057        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12058            s.move_heads_with(|map, head, _| {
12059                (
12060                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12061                    SelectionGoal::None,
12062                )
12063            });
12064        })
12065    }
12066
12067    pub fn select_to_end_of_excerpt(
12068        &mut self,
12069        _: &SelectToEndOfExcerpt,
12070        window: &mut Window,
12071        cx: &mut Context<Self>,
12072    ) {
12073        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12074            cx.propagate();
12075            return;
12076        }
12077        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12078        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12079            s.move_heads_with(|map, head, _| {
12080                (
12081                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12082                    SelectionGoal::None,
12083                )
12084            });
12085        })
12086    }
12087
12088    pub fn select_to_end_of_previous_excerpt(
12089        &mut self,
12090        _: &SelectToEndOfPreviousExcerpt,
12091        window: &mut Window,
12092        cx: &mut Context<Self>,
12093    ) {
12094        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12095            cx.propagate();
12096            return;
12097        }
12098        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12099        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12100            s.move_heads_with(|map, head, _| {
12101                (
12102                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12103                    SelectionGoal::None,
12104                )
12105            });
12106        })
12107    }
12108
12109    pub fn move_to_beginning(
12110        &mut self,
12111        _: &MoveToBeginning,
12112        window: &mut Window,
12113        cx: &mut Context<Self>,
12114    ) {
12115        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12116            cx.propagate();
12117            return;
12118        }
12119        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12120        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12121            s.select_ranges(vec![0..0]);
12122        });
12123    }
12124
12125    pub fn select_to_beginning(
12126        &mut self,
12127        _: &SelectToBeginning,
12128        window: &mut Window,
12129        cx: &mut Context<Self>,
12130    ) {
12131        let mut selection = self.selections.last::<Point>(cx);
12132        selection.set_head(Point::zero(), SelectionGoal::None);
12133        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12134        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12135            s.select(vec![selection]);
12136        });
12137    }
12138
12139    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12140        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12141            cx.propagate();
12142            return;
12143        }
12144        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12145        let cursor = self.buffer.read(cx).read(cx).len();
12146        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12147            s.select_ranges(vec![cursor..cursor])
12148        });
12149    }
12150
12151    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12152        self.nav_history = nav_history;
12153    }
12154
12155    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12156        self.nav_history.as_ref()
12157    }
12158
12159    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12160        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12161    }
12162
12163    fn push_to_nav_history(
12164        &mut self,
12165        cursor_anchor: Anchor,
12166        new_position: Option<Point>,
12167        is_deactivate: bool,
12168        cx: &mut Context<Self>,
12169    ) {
12170        if let Some(nav_history) = self.nav_history.as_mut() {
12171            let buffer = self.buffer.read(cx).read(cx);
12172            let cursor_position = cursor_anchor.to_point(&buffer);
12173            let scroll_state = self.scroll_manager.anchor();
12174            let scroll_top_row = scroll_state.top_row(&buffer);
12175            drop(buffer);
12176
12177            if let Some(new_position) = new_position {
12178                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12179                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12180                    return;
12181                }
12182            }
12183
12184            nav_history.push(
12185                Some(NavigationData {
12186                    cursor_anchor,
12187                    cursor_position,
12188                    scroll_anchor: scroll_state,
12189                    scroll_top_row,
12190                }),
12191                cx,
12192            );
12193            cx.emit(EditorEvent::PushedToNavHistory {
12194                anchor: cursor_anchor,
12195                is_deactivate,
12196            })
12197        }
12198    }
12199
12200    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12202        let buffer = self.buffer.read(cx).snapshot(cx);
12203        let mut selection = self.selections.first::<usize>(cx);
12204        selection.set_head(buffer.len(), SelectionGoal::None);
12205        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12206            s.select(vec![selection]);
12207        });
12208    }
12209
12210    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12211        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12212        let end = self.buffer.read(cx).read(cx).len();
12213        self.change_selections(None, window, cx, |s| {
12214            s.select_ranges(vec![0..end]);
12215        });
12216    }
12217
12218    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12220        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12221        let mut selections = self.selections.all::<Point>(cx);
12222        let max_point = display_map.buffer_snapshot.max_point();
12223        for selection in &mut selections {
12224            let rows = selection.spanned_rows(true, &display_map);
12225            selection.start = Point::new(rows.start.0, 0);
12226            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12227            selection.reversed = false;
12228        }
12229        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12230            s.select(selections);
12231        });
12232    }
12233
12234    pub fn split_selection_into_lines(
12235        &mut self,
12236        _: &SplitSelectionIntoLines,
12237        window: &mut Window,
12238        cx: &mut Context<Self>,
12239    ) {
12240        let selections = self
12241            .selections
12242            .all::<Point>(cx)
12243            .into_iter()
12244            .map(|selection| selection.start..selection.end)
12245            .collect::<Vec<_>>();
12246        self.unfold_ranges(&selections, true, true, cx);
12247
12248        let mut new_selection_ranges = Vec::new();
12249        {
12250            let buffer = self.buffer.read(cx).read(cx);
12251            for selection in selections {
12252                for row in selection.start.row..selection.end.row {
12253                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12254                    new_selection_ranges.push(cursor..cursor);
12255                }
12256
12257                let is_multiline_selection = selection.start.row != selection.end.row;
12258                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12259                // so this action feels more ergonomic when paired with other selection operations
12260                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12261                if !should_skip_last {
12262                    new_selection_ranges.push(selection.end..selection.end);
12263                }
12264            }
12265        }
12266        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12267            s.select_ranges(new_selection_ranges);
12268        });
12269    }
12270
12271    pub fn add_selection_above(
12272        &mut self,
12273        _: &AddSelectionAbove,
12274        window: &mut Window,
12275        cx: &mut Context<Self>,
12276    ) {
12277        self.add_selection(true, window, cx);
12278    }
12279
12280    pub fn add_selection_below(
12281        &mut self,
12282        _: &AddSelectionBelow,
12283        window: &mut Window,
12284        cx: &mut Context<Self>,
12285    ) {
12286        self.add_selection(false, window, cx);
12287    }
12288
12289    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12290        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12291
12292        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12293        let mut selections = self.selections.all::<Point>(cx);
12294        let text_layout_details = self.text_layout_details(window);
12295        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12296            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12297            let range = oldest_selection.display_range(&display_map).sorted();
12298
12299            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12300            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12301            let positions = start_x.min(end_x)..start_x.max(end_x);
12302
12303            selections.clear();
12304            let mut stack = Vec::new();
12305            for row in range.start.row().0..=range.end.row().0 {
12306                if let Some(selection) = self.selections.build_columnar_selection(
12307                    &display_map,
12308                    DisplayRow(row),
12309                    &positions,
12310                    oldest_selection.reversed,
12311                    &text_layout_details,
12312                ) {
12313                    stack.push(selection.id);
12314                    selections.push(selection);
12315                }
12316            }
12317
12318            if above {
12319                stack.reverse();
12320            }
12321
12322            AddSelectionsState { above, stack }
12323        });
12324
12325        let last_added_selection = *state.stack.last().unwrap();
12326        let mut new_selections = Vec::new();
12327        if above == state.above {
12328            let end_row = if above {
12329                DisplayRow(0)
12330            } else {
12331                display_map.max_point().row()
12332            };
12333
12334            'outer: for selection in selections {
12335                if selection.id == last_added_selection {
12336                    let range = selection.display_range(&display_map).sorted();
12337                    debug_assert_eq!(range.start.row(), range.end.row());
12338                    let mut row = range.start.row();
12339                    let positions =
12340                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12341                            px(start)..px(end)
12342                        } else {
12343                            let start_x =
12344                                display_map.x_for_display_point(range.start, &text_layout_details);
12345                            let end_x =
12346                                display_map.x_for_display_point(range.end, &text_layout_details);
12347                            start_x.min(end_x)..start_x.max(end_x)
12348                        };
12349
12350                    while row != end_row {
12351                        if above {
12352                            row.0 -= 1;
12353                        } else {
12354                            row.0 += 1;
12355                        }
12356
12357                        if let Some(new_selection) = self.selections.build_columnar_selection(
12358                            &display_map,
12359                            row,
12360                            &positions,
12361                            selection.reversed,
12362                            &text_layout_details,
12363                        ) {
12364                            state.stack.push(new_selection.id);
12365                            if above {
12366                                new_selections.push(new_selection);
12367                                new_selections.push(selection);
12368                            } else {
12369                                new_selections.push(selection);
12370                                new_selections.push(new_selection);
12371                            }
12372
12373                            continue 'outer;
12374                        }
12375                    }
12376                }
12377
12378                new_selections.push(selection);
12379            }
12380        } else {
12381            new_selections = selections;
12382            new_selections.retain(|s| s.id != last_added_selection);
12383            state.stack.pop();
12384        }
12385
12386        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12387            s.select(new_selections);
12388        });
12389        if state.stack.len() > 1 {
12390            self.add_selections_state = Some(state);
12391        }
12392    }
12393
12394    fn select_match_ranges(
12395        &mut self,
12396        range: Range<usize>,
12397        reversed: bool,
12398        replace_newest: bool,
12399        auto_scroll: Option<Autoscroll>,
12400        window: &mut Window,
12401        cx: &mut Context<Editor>,
12402    ) {
12403        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12404        self.change_selections(auto_scroll, window, cx, |s| {
12405            if replace_newest {
12406                s.delete(s.newest_anchor().id);
12407            }
12408            if reversed {
12409                s.insert_range(range.end..range.start);
12410            } else {
12411                s.insert_range(range);
12412            }
12413        });
12414    }
12415
12416    pub fn select_next_match_internal(
12417        &mut self,
12418        display_map: &DisplaySnapshot,
12419        replace_newest: bool,
12420        autoscroll: Option<Autoscroll>,
12421        window: &mut Window,
12422        cx: &mut Context<Self>,
12423    ) -> Result<()> {
12424        let buffer = &display_map.buffer_snapshot;
12425        let mut selections = self.selections.all::<usize>(cx);
12426        if let Some(mut select_next_state) = self.select_next_state.take() {
12427            let query = &select_next_state.query;
12428            if !select_next_state.done {
12429                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12430                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12431                let mut next_selected_range = None;
12432
12433                let bytes_after_last_selection =
12434                    buffer.bytes_in_range(last_selection.end..buffer.len());
12435                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12436                let query_matches = query
12437                    .stream_find_iter(bytes_after_last_selection)
12438                    .map(|result| (last_selection.end, result))
12439                    .chain(
12440                        query
12441                            .stream_find_iter(bytes_before_first_selection)
12442                            .map(|result| (0, result)),
12443                    );
12444
12445                for (start_offset, query_match) in query_matches {
12446                    let query_match = query_match.unwrap(); // can only fail due to I/O
12447                    let offset_range =
12448                        start_offset + query_match.start()..start_offset + query_match.end();
12449                    let display_range = offset_range.start.to_display_point(display_map)
12450                        ..offset_range.end.to_display_point(display_map);
12451
12452                    if !select_next_state.wordwise
12453                        || (!movement::is_inside_word(display_map, display_range.start)
12454                            && !movement::is_inside_word(display_map, display_range.end))
12455                    {
12456                        // TODO: This is n^2, because we might check all the selections
12457                        if !selections
12458                            .iter()
12459                            .any(|selection| selection.range().overlaps(&offset_range))
12460                        {
12461                            next_selected_range = Some(offset_range);
12462                            break;
12463                        }
12464                    }
12465                }
12466
12467                if let Some(next_selected_range) = next_selected_range {
12468                    self.select_match_ranges(
12469                        next_selected_range,
12470                        last_selection.reversed,
12471                        replace_newest,
12472                        autoscroll,
12473                        window,
12474                        cx,
12475                    );
12476                } else {
12477                    select_next_state.done = true;
12478                }
12479            }
12480
12481            self.select_next_state = Some(select_next_state);
12482        } else {
12483            let mut only_carets = true;
12484            let mut same_text_selected = true;
12485            let mut selected_text = None;
12486
12487            let mut selections_iter = selections.iter().peekable();
12488            while let Some(selection) = selections_iter.next() {
12489                if selection.start != selection.end {
12490                    only_carets = false;
12491                }
12492
12493                if same_text_selected {
12494                    if selected_text.is_none() {
12495                        selected_text =
12496                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12497                    }
12498
12499                    if let Some(next_selection) = selections_iter.peek() {
12500                        if next_selection.range().len() == selection.range().len() {
12501                            let next_selected_text = buffer
12502                                .text_for_range(next_selection.range())
12503                                .collect::<String>();
12504                            if Some(next_selected_text) != selected_text {
12505                                same_text_selected = false;
12506                                selected_text = None;
12507                            }
12508                        } else {
12509                            same_text_selected = false;
12510                            selected_text = None;
12511                        }
12512                    }
12513                }
12514            }
12515
12516            if only_carets {
12517                for selection in &mut selections {
12518                    let word_range = movement::surrounding_word(
12519                        display_map,
12520                        selection.start.to_display_point(display_map),
12521                    );
12522                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12523                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12524                    selection.goal = SelectionGoal::None;
12525                    selection.reversed = false;
12526                    self.select_match_ranges(
12527                        selection.start..selection.end,
12528                        selection.reversed,
12529                        replace_newest,
12530                        autoscroll,
12531                        window,
12532                        cx,
12533                    );
12534                }
12535
12536                if selections.len() == 1 {
12537                    let selection = selections
12538                        .last()
12539                        .expect("ensured that there's only one selection");
12540                    let query = buffer
12541                        .text_for_range(selection.start..selection.end)
12542                        .collect::<String>();
12543                    let is_empty = query.is_empty();
12544                    let select_state = SelectNextState {
12545                        query: AhoCorasick::new(&[query])?,
12546                        wordwise: true,
12547                        done: is_empty,
12548                    };
12549                    self.select_next_state = Some(select_state);
12550                } else {
12551                    self.select_next_state = None;
12552                }
12553            } else if let Some(selected_text) = selected_text {
12554                self.select_next_state = Some(SelectNextState {
12555                    query: AhoCorasick::new(&[selected_text])?,
12556                    wordwise: false,
12557                    done: false,
12558                });
12559                self.select_next_match_internal(
12560                    display_map,
12561                    replace_newest,
12562                    autoscroll,
12563                    window,
12564                    cx,
12565                )?;
12566            }
12567        }
12568        Ok(())
12569    }
12570
12571    pub fn select_all_matches(
12572        &mut self,
12573        _action: &SelectAllMatches,
12574        window: &mut Window,
12575        cx: &mut Context<Self>,
12576    ) -> Result<()> {
12577        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12578
12579        self.push_to_selection_history();
12580        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12581
12582        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12583        let Some(select_next_state) = self.select_next_state.as_mut() else {
12584            return Ok(());
12585        };
12586        if select_next_state.done {
12587            return Ok(());
12588        }
12589
12590        let mut new_selections = Vec::new();
12591
12592        let reversed = self.selections.oldest::<usize>(cx).reversed;
12593        let buffer = &display_map.buffer_snapshot;
12594        let query_matches = select_next_state
12595            .query
12596            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12597
12598        for query_match in query_matches.into_iter() {
12599            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12600            let offset_range = if reversed {
12601                query_match.end()..query_match.start()
12602            } else {
12603                query_match.start()..query_match.end()
12604            };
12605            let display_range = offset_range.start.to_display_point(&display_map)
12606                ..offset_range.end.to_display_point(&display_map);
12607
12608            if !select_next_state.wordwise
12609                || (!movement::is_inside_word(&display_map, display_range.start)
12610                    && !movement::is_inside_word(&display_map, display_range.end))
12611            {
12612                new_selections.push(offset_range.start..offset_range.end);
12613            }
12614        }
12615
12616        select_next_state.done = true;
12617        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12618        self.change_selections(None, window, cx, |selections| {
12619            selections.select_ranges(new_selections)
12620        });
12621
12622        Ok(())
12623    }
12624
12625    pub fn select_next(
12626        &mut self,
12627        action: &SelectNext,
12628        window: &mut Window,
12629        cx: &mut Context<Self>,
12630    ) -> Result<()> {
12631        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12632        self.push_to_selection_history();
12633        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12634        self.select_next_match_internal(
12635            &display_map,
12636            action.replace_newest,
12637            Some(Autoscroll::newest()),
12638            window,
12639            cx,
12640        )?;
12641        Ok(())
12642    }
12643
12644    pub fn select_previous(
12645        &mut self,
12646        action: &SelectPrevious,
12647        window: &mut Window,
12648        cx: &mut Context<Self>,
12649    ) -> Result<()> {
12650        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12651        self.push_to_selection_history();
12652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12653        let buffer = &display_map.buffer_snapshot;
12654        let mut selections = self.selections.all::<usize>(cx);
12655        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12656            let query = &select_prev_state.query;
12657            if !select_prev_state.done {
12658                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12659                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12660                let mut next_selected_range = None;
12661                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12662                let bytes_before_last_selection =
12663                    buffer.reversed_bytes_in_range(0..last_selection.start);
12664                let bytes_after_first_selection =
12665                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12666                let query_matches = query
12667                    .stream_find_iter(bytes_before_last_selection)
12668                    .map(|result| (last_selection.start, result))
12669                    .chain(
12670                        query
12671                            .stream_find_iter(bytes_after_first_selection)
12672                            .map(|result| (buffer.len(), result)),
12673                    );
12674                for (end_offset, query_match) in query_matches {
12675                    let query_match = query_match.unwrap(); // can only fail due to I/O
12676                    let offset_range =
12677                        end_offset - query_match.end()..end_offset - query_match.start();
12678                    let display_range = offset_range.start.to_display_point(&display_map)
12679                        ..offset_range.end.to_display_point(&display_map);
12680
12681                    if !select_prev_state.wordwise
12682                        || (!movement::is_inside_word(&display_map, display_range.start)
12683                            && !movement::is_inside_word(&display_map, display_range.end))
12684                    {
12685                        next_selected_range = Some(offset_range);
12686                        break;
12687                    }
12688                }
12689
12690                if let Some(next_selected_range) = next_selected_range {
12691                    self.select_match_ranges(
12692                        next_selected_range,
12693                        last_selection.reversed,
12694                        action.replace_newest,
12695                        Some(Autoscroll::newest()),
12696                        window,
12697                        cx,
12698                    );
12699                } else {
12700                    select_prev_state.done = true;
12701                }
12702            }
12703
12704            self.select_prev_state = Some(select_prev_state);
12705        } else {
12706            let mut only_carets = true;
12707            let mut same_text_selected = true;
12708            let mut selected_text = None;
12709
12710            let mut selections_iter = selections.iter().peekable();
12711            while let Some(selection) = selections_iter.next() {
12712                if selection.start != selection.end {
12713                    only_carets = false;
12714                }
12715
12716                if same_text_selected {
12717                    if selected_text.is_none() {
12718                        selected_text =
12719                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12720                    }
12721
12722                    if let Some(next_selection) = selections_iter.peek() {
12723                        if next_selection.range().len() == selection.range().len() {
12724                            let next_selected_text = buffer
12725                                .text_for_range(next_selection.range())
12726                                .collect::<String>();
12727                            if Some(next_selected_text) != selected_text {
12728                                same_text_selected = false;
12729                                selected_text = None;
12730                            }
12731                        } else {
12732                            same_text_selected = false;
12733                            selected_text = None;
12734                        }
12735                    }
12736                }
12737            }
12738
12739            if only_carets {
12740                for selection in &mut selections {
12741                    let word_range = movement::surrounding_word(
12742                        &display_map,
12743                        selection.start.to_display_point(&display_map),
12744                    );
12745                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12746                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12747                    selection.goal = SelectionGoal::None;
12748                    selection.reversed = false;
12749                    self.select_match_ranges(
12750                        selection.start..selection.end,
12751                        selection.reversed,
12752                        action.replace_newest,
12753                        Some(Autoscroll::newest()),
12754                        window,
12755                        cx,
12756                    );
12757                }
12758                if selections.len() == 1 {
12759                    let selection = selections
12760                        .last()
12761                        .expect("ensured that there's only one selection");
12762                    let query = buffer
12763                        .text_for_range(selection.start..selection.end)
12764                        .collect::<String>();
12765                    let is_empty = query.is_empty();
12766                    let select_state = SelectNextState {
12767                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12768                        wordwise: true,
12769                        done: is_empty,
12770                    };
12771                    self.select_prev_state = Some(select_state);
12772                } else {
12773                    self.select_prev_state = None;
12774                }
12775            } else if let Some(selected_text) = selected_text {
12776                self.select_prev_state = Some(SelectNextState {
12777                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12778                    wordwise: false,
12779                    done: false,
12780                });
12781                self.select_previous(action, window, cx)?;
12782            }
12783        }
12784        Ok(())
12785    }
12786
12787    pub fn find_next_match(
12788        &mut self,
12789        _: &FindNextMatch,
12790        window: &mut Window,
12791        cx: &mut Context<Self>,
12792    ) -> Result<()> {
12793        let selections = self.selections.disjoint_anchors();
12794        match selections.first() {
12795            Some(first) if selections.len() >= 2 => {
12796                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12797                    s.select_ranges([first.range()]);
12798                });
12799            }
12800            _ => self.select_next(
12801                &SelectNext {
12802                    replace_newest: true,
12803                },
12804                window,
12805                cx,
12806            )?,
12807        }
12808        Ok(())
12809    }
12810
12811    pub fn find_previous_match(
12812        &mut self,
12813        _: &FindPreviousMatch,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) -> Result<()> {
12817        let selections = self.selections.disjoint_anchors();
12818        match selections.last() {
12819            Some(last) if selections.len() >= 2 => {
12820                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12821                    s.select_ranges([last.range()]);
12822                });
12823            }
12824            _ => self.select_previous(
12825                &SelectPrevious {
12826                    replace_newest: true,
12827                },
12828                window,
12829                cx,
12830            )?,
12831        }
12832        Ok(())
12833    }
12834
12835    pub fn toggle_comments(
12836        &mut self,
12837        action: &ToggleComments,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        if self.read_only(cx) {
12842            return;
12843        }
12844        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12845        let text_layout_details = &self.text_layout_details(window);
12846        self.transact(window, cx, |this, window, cx| {
12847            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12848            let mut edits = Vec::new();
12849            let mut selection_edit_ranges = Vec::new();
12850            let mut last_toggled_row = None;
12851            let snapshot = this.buffer.read(cx).read(cx);
12852            let empty_str: Arc<str> = Arc::default();
12853            let mut suffixes_inserted = Vec::new();
12854            let ignore_indent = action.ignore_indent;
12855
12856            fn comment_prefix_range(
12857                snapshot: &MultiBufferSnapshot,
12858                row: MultiBufferRow,
12859                comment_prefix: &str,
12860                comment_prefix_whitespace: &str,
12861                ignore_indent: bool,
12862            ) -> Range<Point> {
12863                let indent_size = if ignore_indent {
12864                    0
12865                } else {
12866                    snapshot.indent_size_for_line(row).len
12867                };
12868
12869                let start = Point::new(row.0, indent_size);
12870
12871                let mut line_bytes = snapshot
12872                    .bytes_in_range(start..snapshot.max_point())
12873                    .flatten()
12874                    .copied();
12875
12876                // If this line currently begins with the line comment prefix, then record
12877                // the range containing the prefix.
12878                if line_bytes
12879                    .by_ref()
12880                    .take(comment_prefix.len())
12881                    .eq(comment_prefix.bytes())
12882                {
12883                    // Include any whitespace that matches the comment prefix.
12884                    let matching_whitespace_len = line_bytes
12885                        .zip(comment_prefix_whitespace.bytes())
12886                        .take_while(|(a, b)| a == b)
12887                        .count() as u32;
12888                    let end = Point::new(
12889                        start.row,
12890                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12891                    );
12892                    start..end
12893                } else {
12894                    start..start
12895                }
12896            }
12897
12898            fn comment_suffix_range(
12899                snapshot: &MultiBufferSnapshot,
12900                row: MultiBufferRow,
12901                comment_suffix: &str,
12902                comment_suffix_has_leading_space: bool,
12903            ) -> Range<Point> {
12904                let end = Point::new(row.0, snapshot.line_len(row));
12905                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12906
12907                let mut line_end_bytes = snapshot
12908                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12909                    .flatten()
12910                    .copied();
12911
12912                let leading_space_len = if suffix_start_column > 0
12913                    && line_end_bytes.next() == Some(b' ')
12914                    && comment_suffix_has_leading_space
12915                {
12916                    1
12917                } else {
12918                    0
12919                };
12920
12921                // If this line currently begins with the line comment prefix, then record
12922                // the range containing the prefix.
12923                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12924                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12925                    start..end
12926                } else {
12927                    end..end
12928                }
12929            }
12930
12931            // TODO: Handle selections that cross excerpts
12932            for selection in &mut selections {
12933                let start_column = snapshot
12934                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12935                    .len;
12936                let language = if let Some(language) =
12937                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12938                {
12939                    language
12940                } else {
12941                    continue;
12942                };
12943
12944                selection_edit_ranges.clear();
12945
12946                // If multiple selections contain a given row, avoid processing that
12947                // row more than once.
12948                let mut start_row = MultiBufferRow(selection.start.row);
12949                if last_toggled_row == Some(start_row) {
12950                    start_row = start_row.next_row();
12951                }
12952                let end_row =
12953                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12954                        MultiBufferRow(selection.end.row - 1)
12955                    } else {
12956                        MultiBufferRow(selection.end.row)
12957                    };
12958                last_toggled_row = Some(end_row);
12959
12960                if start_row > end_row {
12961                    continue;
12962                }
12963
12964                // If the language has line comments, toggle those.
12965                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12966
12967                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12968                if ignore_indent {
12969                    full_comment_prefixes = full_comment_prefixes
12970                        .into_iter()
12971                        .map(|s| Arc::from(s.trim_end()))
12972                        .collect();
12973                }
12974
12975                if !full_comment_prefixes.is_empty() {
12976                    let first_prefix = full_comment_prefixes
12977                        .first()
12978                        .expect("prefixes is non-empty");
12979                    let prefix_trimmed_lengths = full_comment_prefixes
12980                        .iter()
12981                        .map(|p| p.trim_end_matches(' ').len())
12982                        .collect::<SmallVec<[usize; 4]>>();
12983
12984                    let mut all_selection_lines_are_comments = true;
12985
12986                    for row in start_row.0..=end_row.0 {
12987                        let row = MultiBufferRow(row);
12988                        if start_row < end_row && snapshot.is_line_blank(row) {
12989                            continue;
12990                        }
12991
12992                        let prefix_range = full_comment_prefixes
12993                            .iter()
12994                            .zip(prefix_trimmed_lengths.iter().copied())
12995                            .map(|(prefix, trimmed_prefix_len)| {
12996                                comment_prefix_range(
12997                                    snapshot.deref(),
12998                                    row,
12999                                    &prefix[..trimmed_prefix_len],
13000                                    &prefix[trimmed_prefix_len..],
13001                                    ignore_indent,
13002                                )
13003                            })
13004                            .max_by_key(|range| range.end.column - range.start.column)
13005                            .expect("prefixes is non-empty");
13006
13007                        if prefix_range.is_empty() {
13008                            all_selection_lines_are_comments = false;
13009                        }
13010
13011                        selection_edit_ranges.push(prefix_range);
13012                    }
13013
13014                    if all_selection_lines_are_comments {
13015                        edits.extend(
13016                            selection_edit_ranges
13017                                .iter()
13018                                .cloned()
13019                                .map(|range| (range, empty_str.clone())),
13020                        );
13021                    } else {
13022                        let min_column = selection_edit_ranges
13023                            .iter()
13024                            .map(|range| range.start.column)
13025                            .min()
13026                            .unwrap_or(0);
13027                        edits.extend(selection_edit_ranges.iter().map(|range| {
13028                            let position = Point::new(range.start.row, min_column);
13029                            (position..position, first_prefix.clone())
13030                        }));
13031                    }
13032                } else if let Some((full_comment_prefix, comment_suffix)) =
13033                    language.block_comment_delimiters()
13034                {
13035                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13036                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13037                    let prefix_range = comment_prefix_range(
13038                        snapshot.deref(),
13039                        start_row,
13040                        comment_prefix,
13041                        comment_prefix_whitespace,
13042                        ignore_indent,
13043                    );
13044                    let suffix_range = comment_suffix_range(
13045                        snapshot.deref(),
13046                        end_row,
13047                        comment_suffix.trim_start_matches(' '),
13048                        comment_suffix.starts_with(' '),
13049                    );
13050
13051                    if prefix_range.is_empty() || suffix_range.is_empty() {
13052                        edits.push((
13053                            prefix_range.start..prefix_range.start,
13054                            full_comment_prefix.clone(),
13055                        ));
13056                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13057                        suffixes_inserted.push((end_row, comment_suffix.len()));
13058                    } else {
13059                        edits.push((prefix_range, empty_str.clone()));
13060                        edits.push((suffix_range, empty_str.clone()));
13061                    }
13062                } else {
13063                    continue;
13064                }
13065            }
13066
13067            drop(snapshot);
13068            this.buffer.update(cx, |buffer, cx| {
13069                buffer.edit(edits, None, cx);
13070            });
13071
13072            // Adjust selections so that they end before any comment suffixes that
13073            // were inserted.
13074            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13075            let mut selections = this.selections.all::<Point>(cx);
13076            let snapshot = this.buffer.read(cx).read(cx);
13077            for selection in &mut selections {
13078                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13079                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13080                        Ordering::Less => {
13081                            suffixes_inserted.next();
13082                            continue;
13083                        }
13084                        Ordering::Greater => break,
13085                        Ordering::Equal => {
13086                            if selection.end.column == snapshot.line_len(row) {
13087                                if selection.is_empty() {
13088                                    selection.start.column -= suffix_len as u32;
13089                                }
13090                                selection.end.column -= suffix_len as u32;
13091                            }
13092                            break;
13093                        }
13094                    }
13095                }
13096            }
13097
13098            drop(snapshot);
13099            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13100                s.select(selections)
13101            });
13102
13103            let selections = this.selections.all::<Point>(cx);
13104            let selections_on_single_row = selections.windows(2).all(|selections| {
13105                selections[0].start.row == selections[1].start.row
13106                    && selections[0].end.row == selections[1].end.row
13107                    && selections[0].start.row == selections[0].end.row
13108            });
13109            let selections_selecting = selections
13110                .iter()
13111                .any(|selection| selection.start != selection.end);
13112            let advance_downwards = action.advance_downwards
13113                && selections_on_single_row
13114                && !selections_selecting
13115                && !matches!(this.mode, EditorMode::SingleLine { .. });
13116
13117            if advance_downwards {
13118                let snapshot = this.buffer.read(cx).snapshot(cx);
13119
13120                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13121                    s.move_cursors_with(|display_snapshot, display_point, _| {
13122                        let mut point = display_point.to_point(display_snapshot);
13123                        point.row += 1;
13124                        point = snapshot.clip_point(point, Bias::Left);
13125                        let display_point = point.to_display_point(display_snapshot);
13126                        let goal = SelectionGoal::HorizontalPosition(
13127                            display_snapshot
13128                                .x_for_display_point(display_point, text_layout_details)
13129                                .into(),
13130                        );
13131                        (display_point, goal)
13132                    })
13133                });
13134            }
13135        });
13136    }
13137
13138    pub fn select_enclosing_symbol(
13139        &mut self,
13140        _: &SelectEnclosingSymbol,
13141        window: &mut Window,
13142        cx: &mut Context<Self>,
13143    ) {
13144        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13145
13146        let buffer = self.buffer.read(cx).snapshot(cx);
13147        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13148
13149        fn update_selection(
13150            selection: &Selection<usize>,
13151            buffer_snap: &MultiBufferSnapshot,
13152        ) -> Option<Selection<usize>> {
13153            let cursor = selection.head();
13154            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13155            for symbol in symbols.iter().rev() {
13156                let start = symbol.range.start.to_offset(buffer_snap);
13157                let end = symbol.range.end.to_offset(buffer_snap);
13158                let new_range = start..end;
13159                if start < selection.start || end > selection.end {
13160                    return Some(Selection {
13161                        id: selection.id,
13162                        start: new_range.start,
13163                        end: new_range.end,
13164                        goal: SelectionGoal::None,
13165                        reversed: selection.reversed,
13166                    });
13167                }
13168            }
13169            None
13170        }
13171
13172        let mut selected_larger_symbol = false;
13173        let new_selections = old_selections
13174            .iter()
13175            .map(|selection| match update_selection(selection, &buffer) {
13176                Some(new_selection) => {
13177                    if new_selection.range() != selection.range() {
13178                        selected_larger_symbol = true;
13179                    }
13180                    new_selection
13181                }
13182                None => selection.clone(),
13183            })
13184            .collect::<Vec<_>>();
13185
13186        if selected_larger_symbol {
13187            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13188                s.select(new_selections);
13189            });
13190        }
13191    }
13192
13193    pub fn select_larger_syntax_node(
13194        &mut self,
13195        _: &SelectLargerSyntaxNode,
13196        window: &mut Window,
13197        cx: &mut Context<Self>,
13198    ) {
13199        let Some(visible_row_count) = self.visible_row_count() else {
13200            return;
13201        };
13202        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13203        if old_selections.is_empty() {
13204            return;
13205        }
13206
13207        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13208
13209        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13210        let buffer = self.buffer.read(cx).snapshot(cx);
13211
13212        let mut selected_larger_node = false;
13213        let mut new_selections = old_selections
13214            .iter()
13215            .map(|selection| {
13216                let old_range = selection.start..selection.end;
13217
13218                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13219                    // manually select word at selection
13220                    if ["string_content", "inline"].contains(&node.kind()) {
13221                        let word_range = {
13222                            let display_point = buffer
13223                                .offset_to_point(old_range.start)
13224                                .to_display_point(&display_map);
13225                            let Range { start, end } =
13226                                movement::surrounding_word(&display_map, display_point);
13227                            start.to_point(&display_map).to_offset(&buffer)
13228                                ..end.to_point(&display_map).to_offset(&buffer)
13229                        };
13230                        // ignore if word is already selected
13231                        if !word_range.is_empty() && old_range != word_range {
13232                            let last_word_range = {
13233                                let display_point = buffer
13234                                    .offset_to_point(old_range.end)
13235                                    .to_display_point(&display_map);
13236                                let Range { start, end } =
13237                                    movement::surrounding_word(&display_map, display_point);
13238                                start.to_point(&display_map).to_offset(&buffer)
13239                                    ..end.to_point(&display_map).to_offset(&buffer)
13240                            };
13241                            // only select word if start and end point belongs to same word
13242                            if word_range == last_word_range {
13243                                selected_larger_node = true;
13244                                return Selection {
13245                                    id: selection.id,
13246                                    start: word_range.start,
13247                                    end: word_range.end,
13248                                    goal: SelectionGoal::None,
13249                                    reversed: selection.reversed,
13250                                };
13251                            }
13252                        }
13253                    }
13254                }
13255
13256                let mut new_range = old_range.clone();
13257                while let Some((_node, containing_range)) =
13258                    buffer.syntax_ancestor(new_range.clone())
13259                {
13260                    new_range = match containing_range {
13261                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13262                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13263                    };
13264                    if !display_map.intersects_fold(new_range.start)
13265                        && !display_map.intersects_fold(new_range.end)
13266                    {
13267                        break;
13268                    }
13269                }
13270
13271                selected_larger_node |= new_range != old_range;
13272                Selection {
13273                    id: selection.id,
13274                    start: new_range.start,
13275                    end: new_range.end,
13276                    goal: SelectionGoal::None,
13277                    reversed: selection.reversed,
13278                }
13279            })
13280            .collect::<Vec<_>>();
13281
13282        if !selected_larger_node {
13283            return; // don't put this call in the history
13284        }
13285
13286        // scroll based on transformation done to the last selection created by the user
13287        let (last_old, last_new) = old_selections
13288            .last()
13289            .zip(new_selections.last().cloned())
13290            .expect("old_selections isn't empty");
13291
13292        // revert selection
13293        let is_selection_reversed = {
13294            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13295            new_selections.last_mut().expect("checked above").reversed =
13296                should_newest_selection_be_reversed;
13297            should_newest_selection_be_reversed
13298        };
13299
13300        if selected_larger_node {
13301            self.select_syntax_node_history.disable_clearing = true;
13302            self.change_selections(None, window, cx, |s| {
13303                s.select(new_selections.clone());
13304            });
13305            self.select_syntax_node_history.disable_clearing = false;
13306        }
13307
13308        let start_row = last_new.start.to_display_point(&display_map).row().0;
13309        let end_row = last_new.end.to_display_point(&display_map).row().0;
13310        let selection_height = end_row - start_row + 1;
13311        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13312
13313        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13314        let scroll_behavior = if fits_on_the_screen {
13315            self.request_autoscroll(Autoscroll::fit(), cx);
13316            SelectSyntaxNodeScrollBehavior::FitSelection
13317        } else if is_selection_reversed {
13318            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13319            SelectSyntaxNodeScrollBehavior::CursorTop
13320        } else {
13321            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13322            SelectSyntaxNodeScrollBehavior::CursorBottom
13323        };
13324
13325        self.select_syntax_node_history.push((
13326            old_selections,
13327            scroll_behavior,
13328            is_selection_reversed,
13329        ));
13330    }
13331
13332    pub fn select_smaller_syntax_node(
13333        &mut self,
13334        _: &SelectSmallerSyntaxNode,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13339
13340        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13341            self.select_syntax_node_history.pop()
13342        {
13343            if let Some(selection) = selections.last_mut() {
13344                selection.reversed = is_selection_reversed;
13345            }
13346
13347            self.select_syntax_node_history.disable_clearing = true;
13348            self.change_selections(None, window, cx, |s| {
13349                s.select(selections.to_vec());
13350            });
13351            self.select_syntax_node_history.disable_clearing = false;
13352
13353            match scroll_behavior {
13354                SelectSyntaxNodeScrollBehavior::CursorTop => {
13355                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13356                }
13357                SelectSyntaxNodeScrollBehavior::FitSelection => {
13358                    self.request_autoscroll(Autoscroll::fit(), cx);
13359                }
13360                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13361                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13362                }
13363            }
13364        }
13365    }
13366
13367    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13368        if !EditorSettings::get_global(cx).gutter.runnables {
13369            self.clear_tasks();
13370            return Task::ready(());
13371        }
13372        let project = self.project.as_ref().map(Entity::downgrade);
13373        let task_sources = self.lsp_task_sources(cx);
13374        cx.spawn_in(window, async move |editor, cx| {
13375            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13376            let Some(project) = project.and_then(|p| p.upgrade()) else {
13377                return;
13378            };
13379            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13380                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13381            }) else {
13382                return;
13383            };
13384
13385            let hide_runnables = project
13386                .update(cx, |project, cx| {
13387                    // Do not display any test indicators in non-dev server remote projects.
13388                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13389                })
13390                .unwrap_or(true);
13391            if hide_runnables {
13392                return;
13393            }
13394            let new_rows =
13395                cx.background_spawn({
13396                    let snapshot = display_snapshot.clone();
13397                    async move {
13398                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13399                    }
13400                })
13401                    .await;
13402            let Ok(lsp_tasks) =
13403                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13404            else {
13405                return;
13406            };
13407            let lsp_tasks = lsp_tasks.await;
13408
13409            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13410                lsp_tasks
13411                    .into_iter()
13412                    .flat_map(|(kind, tasks)| {
13413                        tasks.into_iter().filter_map(move |(location, task)| {
13414                            Some((kind.clone(), location?, task))
13415                        })
13416                    })
13417                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13418                        let buffer = location.target.buffer;
13419                        let buffer_snapshot = buffer.read(cx).snapshot();
13420                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13421                            |(excerpt_id, snapshot, _)| {
13422                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13423                                    display_snapshot
13424                                        .buffer_snapshot
13425                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13426                                } else {
13427                                    None
13428                                }
13429                            },
13430                        );
13431                        if let Some(offset) = offset {
13432                            let task_buffer_range =
13433                                location.target.range.to_point(&buffer_snapshot);
13434                            let context_buffer_range =
13435                                task_buffer_range.to_offset(&buffer_snapshot);
13436                            let context_range = BufferOffset(context_buffer_range.start)
13437                                ..BufferOffset(context_buffer_range.end);
13438
13439                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13440                                .or_insert_with(|| RunnableTasks {
13441                                    templates: Vec::new(),
13442                                    offset,
13443                                    column: task_buffer_range.start.column,
13444                                    extra_variables: HashMap::default(),
13445                                    context_range,
13446                                })
13447                                .templates
13448                                .push((kind, task.original_task().clone()));
13449                        }
13450
13451                        acc
13452                    })
13453            }) else {
13454                return;
13455            };
13456
13457            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13458            editor
13459                .update(cx, |editor, _| {
13460                    editor.clear_tasks();
13461                    for (key, mut value) in rows {
13462                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13463                            value.templates.extend(lsp_tasks.templates);
13464                        }
13465
13466                        editor.insert_tasks(key, value);
13467                    }
13468                    for (key, value) in lsp_tasks_by_rows {
13469                        editor.insert_tasks(key, value);
13470                    }
13471                })
13472                .ok();
13473        })
13474    }
13475    fn fetch_runnable_ranges(
13476        snapshot: &DisplaySnapshot,
13477        range: Range<Anchor>,
13478    ) -> Vec<language::RunnableRange> {
13479        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13480    }
13481
13482    fn runnable_rows(
13483        project: Entity<Project>,
13484        snapshot: DisplaySnapshot,
13485        runnable_ranges: Vec<RunnableRange>,
13486        mut cx: AsyncWindowContext,
13487    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13488        runnable_ranges
13489            .into_iter()
13490            .filter_map(|mut runnable| {
13491                let tasks = cx
13492                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13493                    .ok()?;
13494                if tasks.is_empty() {
13495                    return None;
13496                }
13497
13498                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13499
13500                let row = snapshot
13501                    .buffer_snapshot
13502                    .buffer_line_for_row(MultiBufferRow(point.row))?
13503                    .1
13504                    .start
13505                    .row;
13506
13507                let context_range =
13508                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13509                Some((
13510                    (runnable.buffer_id, row),
13511                    RunnableTasks {
13512                        templates: tasks,
13513                        offset: snapshot
13514                            .buffer_snapshot
13515                            .anchor_before(runnable.run_range.start),
13516                        context_range,
13517                        column: point.column,
13518                        extra_variables: runnable.extra_captures,
13519                    },
13520                ))
13521            })
13522            .collect()
13523    }
13524
13525    fn templates_with_tags(
13526        project: &Entity<Project>,
13527        runnable: &mut Runnable,
13528        cx: &mut App,
13529    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13530        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13531            let (worktree_id, file) = project
13532                .buffer_for_id(runnable.buffer, cx)
13533                .and_then(|buffer| buffer.read(cx).file())
13534                .map(|file| (file.worktree_id(cx), file.clone()))
13535                .unzip();
13536
13537            (
13538                project.task_store().read(cx).task_inventory().cloned(),
13539                worktree_id,
13540                file,
13541            )
13542        });
13543
13544        let mut templates_with_tags = mem::take(&mut runnable.tags)
13545            .into_iter()
13546            .flat_map(|RunnableTag(tag)| {
13547                inventory
13548                    .as_ref()
13549                    .into_iter()
13550                    .flat_map(|inventory| {
13551                        inventory.read(cx).list_tasks(
13552                            file.clone(),
13553                            Some(runnable.language.clone()),
13554                            worktree_id,
13555                            cx,
13556                        )
13557                    })
13558                    .filter(move |(_, template)| {
13559                        template.tags.iter().any(|source_tag| source_tag == &tag)
13560                    })
13561            })
13562            .sorted_by_key(|(kind, _)| kind.to_owned())
13563            .collect::<Vec<_>>();
13564        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13565            // Strongest source wins; if we have worktree tag binding, prefer that to
13566            // global and language bindings;
13567            // if we have a global binding, prefer that to language binding.
13568            let first_mismatch = templates_with_tags
13569                .iter()
13570                .position(|(tag_source, _)| tag_source != leading_tag_source);
13571            if let Some(index) = first_mismatch {
13572                templates_with_tags.truncate(index);
13573            }
13574        }
13575
13576        templates_with_tags
13577    }
13578
13579    pub fn move_to_enclosing_bracket(
13580        &mut self,
13581        _: &MoveToEnclosingBracket,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13586        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13587            s.move_offsets_with(|snapshot, selection| {
13588                let Some(enclosing_bracket_ranges) =
13589                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13590                else {
13591                    return;
13592                };
13593
13594                let mut best_length = usize::MAX;
13595                let mut best_inside = false;
13596                let mut best_in_bracket_range = false;
13597                let mut best_destination = None;
13598                for (open, close) in enclosing_bracket_ranges {
13599                    let close = close.to_inclusive();
13600                    let length = close.end() - open.start;
13601                    let inside = selection.start >= open.end && selection.end <= *close.start();
13602                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13603                        || close.contains(&selection.head());
13604
13605                    // If best is next to a bracket and current isn't, skip
13606                    if !in_bracket_range && best_in_bracket_range {
13607                        continue;
13608                    }
13609
13610                    // Prefer smaller lengths unless best is inside and current isn't
13611                    if length > best_length && (best_inside || !inside) {
13612                        continue;
13613                    }
13614
13615                    best_length = length;
13616                    best_inside = inside;
13617                    best_in_bracket_range = in_bracket_range;
13618                    best_destination = Some(
13619                        if close.contains(&selection.start) && close.contains(&selection.end) {
13620                            if inside { open.end } else { open.start }
13621                        } else if inside {
13622                            *close.start()
13623                        } else {
13624                            *close.end()
13625                        },
13626                    );
13627                }
13628
13629                if let Some(destination) = best_destination {
13630                    selection.collapse_to(destination, SelectionGoal::None);
13631                }
13632            })
13633        });
13634    }
13635
13636    pub fn undo_selection(
13637        &mut self,
13638        _: &UndoSelection,
13639        window: &mut Window,
13640        cx: &mut Context<Self>,
13641    ) {
13642        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13643        self.end_selection(window, cx);
13644        self.selection_history.mode = SelectionHistoryMode::Undoing;
13645        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13646            self.change_selections(None, window, cx, |s| {
13647                s.select_anchors(entry.selections.to_vec())
13648            });
13649            self.select_next_state = entry.select_next_state;
13650            self.select_prev_state = entry.select_prev_state;
13651            self.add_selections_state = entry.add_selections_state;
13652            self.request_autoscroll(Autoscroll::newest(), cx);
13653        }
13654        self.selection_history.mode = SelectionHistoryMode::Normal;
13655    }
13656
13657    pub fn redo_selection(
13658        &mut self,
13659        _: &RedoSelection,
13660        window: &mut Window,
13661        cx: &mut Context<Self>,
13662    ) {
13663        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13664        self.end_selection(window, cx);
13665        self.selection_history.mode = SelectionHistoryMode::Redoing;
13666        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13667            self.change_selections(None, window, cx, |s| {
13668                s.select_anchors(entry.selections.to_vec())
13669            });
13670            self.select_next_state = entry.select_next_state;
13671            self.select_prev_state = entry.select_prev_state;
13672            self.add_selections_state = entry.add_selections_state;
13673            self.request_autoscroll(Autoscroll::newest(), cx);
13674        }
13675        self.selection_history.mode = SelectionHistoryMode::Normal;
13676    }
13677
13678    pub fn expand_excerpts(
13679        &mut self,
13680        action: &ExpandExcerpts,
13681        _: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13685    }
13686
13687    pub fn expand_excerpts_down(
13688        &mut self,
13689        action: &ExpandExcerptsDown,
13690        _: &mut Window,
13691        cx: &mut Context<Self>,
13692    ) {
13693        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13694    }
13695
13696    pub fn expand_excerpts_up(
13697        &mut self,
13698        action: &ExpandExcerptsUp,
13699        _: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13703    }
13704
13705    pub fn expand_excerpts_for_direction(
13706        &mut self,
13707        lines: u32,
13708        direction: ExpandExcerptDirection,
13709
13710        cx: &mut Context<Self>,
13711    ) {
13712        let selections = self.selections.disjoint_anchors();
13713
13714        let lines = if lines == 0 {
13715            EditorSettings::get_global(cx).expand_excerpt_lines
13716        } else {
13717            lines
13718        };
13719
13720        self.buffer.update(cx, |buffer, cx| {
13721            let snapshot = buffer.snapshot(cx);
13722            let mut excerpt_ids = selections
13723                .iter()
13724                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13725                .collect::<Vec<_>>();
13726            excerpt_ids.sort();
13727            excerpt_ids.dedup();
13728            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13729        })
13730    }
13731
13732    pub fn expand_excerpt(
13733        &mut self,
13734        excerpt: ExcerptId,
13735        direction: ExpandExcerptDirection,
13736        window: &mut Window,
13737        cx: &mut Context<Self>,
13738    ) {
13739        let current_scroll_position = self.scroll_position(cx);
13740        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13741        let mut should_scroll_up = false;
13742
13743        if direction == ExpandExcerptDirection::Down {
13744            let multi_buffer = self.buffer.read(cx);
13745            let snapshot = multi_buffer.snapshot(cx);
13746            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13747                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13748                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13749                        let buffer_snapshot = buffer.read(cx).snapshot();
13750                        let excerpt_end_row =
13751                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13752                        let last_row = buffer_snapshot.max_point().row;
13753                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13754                        should_scroll_up = lines_below >= lines_to_expand;
13755                    }
13756                }
13757            }
13758        }
13759
13760        self.buffer.update(cx, |buffer, cx| {
13761            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13762        });
13763
13764        if should_scroll_up {
13765            let new_scroll_position =
13766                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13767            self.set_scroll_position(new_scroll_position, window, cx);
13768        }
13769    }
13770
13771    pub fn go_to_singleton_buffer_point(
13772        &mut self,
13773        point: Point,
13774        window: &mut Window,
13775        cx: &mut Context<Self>,
13776    ) {
13777        self.go_to_singleton_buffer_range(point..point, window, cx);
13778    }
13779
13780    pub fn go_to_singleton_buffer_range(
13781        &mut self,
13782        range: Range<Point>,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) {
13786        let multibuffer = self.buffer().read(cx);
13787        let Some(buffer) = multibuffer.as_singleton() else {
13788            return;
13789        };
13790        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13791            return;
13792        };
13793        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13794            return;
13795        };
13796        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13797            s.select_anchor_ranges([start..end])
13798        });
13799    }
13800
13801    pub fn go_to_diagnostic(
13802        &mut self,
13803        _: &GoToDiagnostic,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13808        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13809    }
13810
13811    pub fn go_to_prev_diagnostic(
13812        &mut self,
13813        _: &GoToPreviousDiagnostic,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13818        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13819    }
13820
13821    pub fn go_to_diagnostic_impl(
13822        &mut self,
13823        direction: Direction,
13824        window: &mut Window,
13825        cx: &mut Context<Self>,
13826    ) {
13827        let buffer = self.buffer.read(cx).snapshot(cx);
13828        let selection = self.selections.newest::<usize>(cx);
13829
13830        let mut active_group_id = None;
13831        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13832            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13833                active_group_id = Some(active_group.group_id);
13834            }
13835        }
13836
13837        fn filtered(
13838            snapshot: EditorSnapshot,
13839            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13840        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13841            diagnostics
13842                .filter(|entry| entry.range.start != entry.range.end)
13843                .filter(|entry| !entry.diagnostic.is_unnecessary)
13844                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13845        }
13846
13847        let snapshot = self.snapshot(window, cx);
13848        let before = filtered(
13849            snapshot.clone(),
13850            buffer
13851                .diagnostics_in_range(0..selection.start)
13852                .filter(|entry| entry.range.start <= selection.start),
13853        );
13854        let after = filtered(
13855            snapshot,
13856            buffer
13857                .diagnostics_in_range(selection.start..buffer.len())
13858                .filter(|entry| entry.range.start >= selection.start),
13859        );
13860
13861        let mut found: Option<DiagnosticEntry<usize>> = None;
13862        if direction == Direction::Prev {
13863            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13864            {
13865                for diagnostic in prev_diagnostics.into_iter().rev() {
13866                    if diagnostic.range.start != selection.start
13867                        || active_group_id
13868                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13869                    {
13870                        found = Some(diagnostic);
13871                        break 'outer;
13872                    }
13873                }
13874            }
13875        } else {
13876            for diagnostic in after.chain(before) {
13877                if diagnostic.range.start != selection.start
13878                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13879                {
13880                    found = Some(diagnostic);
13881                    break;
13882                }
13883            }
13884        }
13885        let Some(next_diagnostic) = found else {
13886            return;
13887        };
13888
13889        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13890            return;
13891        };
13892        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13893            s.select_ranges(vec![
13894                next_diagnostic.range.start..next_diagnostic.range.start,
13895            ])
13896        });
13897        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13898        self.refresh_inline_completion(false, true, window, cx);
13899    }
13900
13901    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13902        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13903        let snapshot = self.snapshot(window, cx);
13904        let selection = self.selections.newest::<Point>(cx);
13905        self.go_to_hunk_before_or_after_position(
13906            &snapshot,
13907            selection.head(),
13908            Direction::Next,
13909            window,
13910            cx,
13911        );
13912    }
13913
13914    pub fn go_to_hunk_before_or_after_position(
13915        &mut self,
13916        snapshot: &EditorSnapshot,
13917        position: Point,
13918        direction: Direction,
13919        window: &mut Window,
13920        cx: &mut Context<Editor>,
13921    ) {
13922        let row = if direction == Direction::Next {
13923            self.hunk_after_position(snapshot, position)
13924                .map(|hunk| hunk.row_range.start)
13925        } else {
13926            self.hunk_before_position(snapshot, position)
13927        };
13928
13929        if let Some(row) = row {
13930            let destination = Point::new(row.0, 0);
13931            let autoscroll = Autoscroll::center();
13932
13933            self.unfold_ranges(&[destination..destination], false, false, cx);
13934            self.change_selections(Some(autoscroll), window, cx, |s| {
13935                s.select_ranges([destination..destination]);
13936            });
13937        }
13938    }
13939
13940    fn hunk_after_position(
13941        &mut self,
13942        snapshot: &EditorSnapshot,
13943        position: Point,
13944    ) -> Option<MultiBufferDiffHunk> {
13945        snapshot
13946            .buffer_snapshot
13947            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13948            .find(|hunk| hunk.row_range.start.0 > position.row)
13949            .or_else(|| {
13950                snapshot
13951                    .buffer_snapshot
13952                    .diff_hunks_in_range(Point::zero()..position)
13953                    .find(|hunk| hunk.row_range.end.0 < position.row)
13954            })
13955    }
13956
13957    fn go_to_prev_hunk(
13958        &mut self,
13959        _: &GoToPreviousHunk,
13960        window: &mut Window,
13961        cx: &mut Context<Self>,
13962    ) {
13963        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13964        let snapshot = self.snapshot(window, cx);
13965        let selection = self.selections.newest::<Point>(cx);
13966        self.go_to_hunk_before_or_after_position(
13967            &snapshot,
13968            selection.head(),
13969            Direction::Prev,
13970            window,
13971            cx,
13972        );
13973    }
13974
13975    fn hunk_before_position(
13976        &mut self,
13977        snapshot: &EditorSnapshot,
13978        position: Point,
13979    ) -> Option<MultiBufferRow> {
13980        snapshot
13981            .buffer_snapshot
13982            .diff_hunk_before(position)
13983            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13984    }
13985
13986    fn go_to_next_change(
13987        &mut self,
13988        _: &GoToNextChange,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if let Some(selections) = self
13993            .change_list
13994            .next_change(1, Direction::Next)
13995            .map(|s| s.to_vec())
13996        {
13997            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13998                let map = s.display_map();
13999                s.select_display_ranges(selections.iter().map(|a| {
14000                    let point = a.to_display_point(&map);
14001                    point..point
14002                }))
14003            })
14004        }
14005    }
14006
14007    fn go_to_previous_change(
14008        &mut self,
14009        _: &GoToPreviousChange,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) {
14013        if let Some(selections) = self
14014            .change_list
14015            .next_change(1, Direction::Prev)
14016            .map(|s| s.to_vec())
14017        {
14018            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14019                let map = s.display_map();
14020                s.select_display_ranges(selections.iter().map(|a| {
14021                    let point = a.to_display_point(&map);
14022                    point..point
14023                }))
14024            })
14025        }
14026    }
14027
14028    fn go_to_line<T: 'static>(
14029        &mut self,
14030        position: Anchor,
14031        highlight_color: Option<Hsla>,
14032        window: &mut Window,
14033        cx: &mut Context<Self>,
14034    ) {
14035        let snapshot = self.snapshot(window, cx).display_snapshot;
14036        let position = position.to_point(&snapshot.buffer_snapshot);
14037        let start = snapshot
14038            .buffer_snapshot
14039            .clip_point(Point::new(position.row, 0), Bias::Left);
14040        let end = start + Point::new(1, 0);
14041        let start = snapshot.buffer_snapshot.anchor_before(start);
14042        let end = snapshot.buffer_snapshot.anchor_before(end);
14043
14044        self.highlight_rows::<T>(
14045            start..end,
14046            highlight_color
14047                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14048            Default::default(),
14049            cx,
14050        );
14051
14052        if self.buffer.read(cx).is_singleton() {
14053            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14054        }
14055    }
14056
14057    pub fn go_to_definition(
14058        &mut self,
14059        _: &GoToDefinition,
14060        window: &mut Window,
14061        cx: &mut Context<Self>,
14062    ) -> Task<Result<Navigated>> {
14063        let definition =
14064            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14065        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14066        cx.spawn_in(window, async move |editor, cx| {
14067            if definition.await? == Navigated::Yes {
14068                return Ok(Navigated::Yes);
14069            }
14070            match fallback_strategy {
14071                GoToDefinitionFallback::None => Ok(Navigated::No),
14072                GoToDefinitionFallback::FindAllReferences => {
14073                    match editor.update_in(cx, |editor, window, cx| {
14074                        editor.find_all_references(&FindAllReferences, window, cx)
14075                    })? {
14076                        Some(references) => references.await,
14077                        None => Ok(Navigated::No),
14078                    }
14079                }
14080            }
14081        })
14082    }
14083
14084    pub fn go_to_declaration(
14085        &mut self,
14086        _: &GoToDeclaration,
14087        window: &mut Window,
14088        cx: &mut Context<Self>,
14089    ) -> Task<Result<Navigated>> {
14090        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14091    }
14092
14093    pub fn go_to_declaration_split(
14094        &mut self,
14095        _: &GoToDeclaration,
14096        window: &mut Window,
14097        cx: &mut Context<Self>,
14098    ) -> Task<Result<Navigated>> {
14099        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14100    }
14101
14102    pub fn go_to_implementation(
14103        &mut self,
14104        _: &GoToImplementation,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) -> Task<Result<Navigated>> {
14108        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14109    }
14110
14111    pub fn go_to_implementation_split(
14112        &mut self,
14113        _: &GoToImplementationSplit,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) -> Task<Result<Navigated>> {
14117        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14118    }
14119
14120    pub fn go_to_type_definition(
14121        &mut self,
14122        _: &GoToTypeDefinition,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) -> Task<Result<Navigated>> {
14126        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14127    }
14128
14129    pub fn go_to_definition_split(
14130        &mut self,
14131        _: &GoToDefinitionSplit,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) -> Task<Result<Navigated>> {
14135        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14136    }
14137
14138    pub fn go_to_type_definition_split(
14139        &mut self,
14140        _: &GoToTypeDefinitionSplit,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) -> Task<Result<Navigated>> {
14144        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14145    }
14146
14147    fn go_to_definition_of_kind(
14148        &mut self,
14149        kind: GotoDefinitionKind,
14150        split: bool,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) -> Task<Result<Navigated>> {
14154        let Some(provider) = self.semantics_provider.clone() else {
14155            return Task::ready(Ok(Navigated::No));
14156        };
14157        let head = self.selections.newest::<usize>(cx).head();
14158        let buffer = self.buffer.read(cx);
14159        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14160            text_anchor
14161        } else {
14162            return Task::ready(Ok(Navigated::No));
14163        };
14164
14165        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14166            return Task::ready(Ok(Navigated::No));
14167        };
14168
14169        cx.spawn_in(window, async move |editor, cx| {
14170            let definitions = definitions.await?;
14171            let navigated = editor
14172                .update_in(cx, |editor, window, cx| {
14173                    editor.navigate_to_hover_links(
14174                        Some(kind),
14175                        definitions
14176                            .into_iter()
14177                            .filter(|location| {
14178                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14179                            })
14180                            .map(HoverLink::Text)
14181                            .collect::<Vec<_>>(),
14182                        split,
14183                        window,
14184                        cx,
14185                    )
14186                })?
14187                .await?;
14188            anyhow::Ok(navigated)
14189        })
14190    }
14191
14192    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14193        let selection = self.selections.newest_anchor();
14194        let head = selection.head();
14195        let tail = selection.tail();
14196
14197        let Some((buffer, start_position)) =
14198            self.buffer.read(cx).text_anchor_for_position(head, cx)
14199        else {
14200            return;
14201        };
14202
14203        let end_position = if head != tail {
14204            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14205                return;
14206            };
14207            Some(pos)
14208        } else {
14209            None
14210        };
14211
14212        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14213            let url = if let Some(end_pos) = end_position {
14214                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14215            } else {
14216                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14217            };
14218
14219            if let Some(url) = url {
14220                editor.update(cx, |_, cx| {
14221                    cx.open_url(&url);
14222                })
14223            } else {
14224                Ok(())
14225            }
14226        });
14227
14228        url_finder.detach();
14229    }
14230
14231    pub fn open_selected_filename(
14232        &mut self,
14233        _: &OpenSelectedFilename,
14234        window: &mut Window,
14235        cx: &mut Context<Self>,
14236    ) {
14237        let Some(workspace) = self.workspace() else {
14238            return;
14239        };
14240
14241        let position = self.selections.newest_anchor().head();
14242
14243        let Some((buffer, buffer_position)) =
14244            self.buffer.read(cx).text_anchor_for_position(position, cx)
14245        else {
14246            return;
14247        };
14248
14249        let project = self.project.clone();
14250
14251        cx.spawn_in(window, async move |_, cx| {
14252            let result = find_file(&buffer, project, buffer_position, cx).await;
14253
14254            if let Some((_, path)) = result {
14255                workspace
14256                    .update_in(cx, |workspace, window, cx| {
14257                        workspace.open_resolved_path(path, window, cx)
14258                    })?
14259                    .await?;
14260            }
14261            anyhow::Ok(())
14262        })
14263        .detach();
14264    }
14265
14266    pub(crate) fn navigate_to_hover_links(
14267        &mut self,
14268        kind: Option<GotoDefinitionKind>,
14269        mut definitions: Vec<HoverLink>,
14270        split: bool,
14271        window: &mut Window,
14272        cx: &mut Context<Editor>,
14273    ) -> Task<Result<Navigated>> {
14274        // If there is one definition, just open it directly
14275        if definitions.len() == 1 {
14276            let definition = definitions.pop().unwrap();
14277
14278            enum TargetTaskResult {
14279                Location(Option<Location>),
14280                AlreadyNavigated,
14281            }
14282
14283            let target_task = match definition {
14284                HoverLink::Text(link) => {
14285                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14286                }
14287                HoverLink::InlayHint(lsp_location, server_id) => {
14288                    let computation =
14289                        self.compute_target_location(lsp_location, server_id, window, cx);
14290                    cx.background_spawn(async move {
14291                        let location = computation.await?;
14292                        Ok(TargetTaskResult::Location(location))
14293                    })
14294                }
14295                HoverLink::Url(url) => {
14296                    cx.open_url(&url);
14297                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14298                }
14299                HoverLink::File(path) => {
14300                    if let Some(workspace) = self.workspace() {
14301                        cx.spawn_in(window, async move |_, cx| {
14302                            workspace
14303                                .update_in(cx, |workspace, window, cx| {
14304                                    workspace.open_resolved_path(path, window, cx)
14305                                })?
14306                                .await
14307                                .map(|_| TargetTaskResult::AlreadyNavigated)
14308                        })
14309                    } else {
14310                        Task::ready(Ok(TargetTaskResult::Location(None)))
14311                    }
14312                }
14313            };
14314            cx.spawn_in(window, async move |editor, cx| {
14315                let target = match target_task.await.context("target resolution task")? {
14316                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14317                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14318                    TargetTaskResult::Location(Some(target)) => target,
14319                };
14320
14321                editor.update_in(cx, |editor, window, cx| {
14322                    let Some(workspace) = editor.workspace() else {
14323                        return Navigated::No;
14324                    };
14325                    let pane = workspace.read(cx).active_pane().clone();
14326
14327                    let range = target.range.to_point(target.buffer.read(cx));
14328                    let range = editor.range_for_match(&range);
14329                    let range = collapse_multiline_range(range);
14330
14331                    if !split
14332                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14333                    {
14334                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14335                    } else {
14336                        window.defer(cx, move |window, cx| {
14337                            let target_editor: Entity<Self> =
14338                                workspace.update(cx, |workspace, cx| {
14339                                    let pane = if split {
14340                                        workspace.adjacent_pane(window, cx)
14341                                    } else {
14342                                        workspace.active_pane().clone()
14343                                    };
14344
14345                                    workspace.open_project_item(
14346                                        pane,
14347                                        target.buffer.clone(),
14348                                        true,
14349                                        true,
14350                                        window,
14351                                        cx,
14352                                    )
14353                                });
14354                            target_editor.update(cx, |target_editor, cx| {
14355                                // When selecting a definition in a different buffer, disable the nav history
14356                                // to avoid creating a history entry at the previous cursor location.
14357                                pane.update(cx, |pane, _| pane.disable_history());
14358                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14359                                pane.update(cx, |pane, _| pane.enable_history());
14360                            });
14361                        });
14362                    }
14363                    Navigated::Yes
14364                })
14365            })
14366        } else if !definitions.is_empty() {
14367            cx.spawn_in(window, async move |editor, cx| {
14368                let (title, location_tasks, workspace) = editor
14369                    .update_in(cx, |editor, window, cx| {
14370                        let tab_kind = match kind {
14371                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14372                            _ => "Definitions",
14373                        };
14374                        let title = definitions
14375                            .iter()
14376                            .find_map(|definition| match definition {
14377                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14378                                    let buffer = origin.buffer.read(cx);
14379                                    format!(
14380                                        "{} for {}",
14381                                        tab_kind,
14382                                        buffer
14383                                            .text_for_range(origin.range.clone())
14384                                            .collect::<String>()
14385                                    )
14386                                }),
14387                                HoverLink::InlayHint(_, _) => None,
14388                                HoverLink::Url(_) => None,
14389                                HoverLink::File(_) => None,
14390                            })
14391                            .unwrap_or(tab_kind.to_string());
14392                        let location_tasks = definitions
14393                            .into_iter()
14394                            .map(|definition| match definition {
14395                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14396                                HoverLink::InlayHint(lsp_location, server_id) => editor
14397                                    .compute_target_location(lsp_location, server_id, window, cx),
14398                                HoverLink::Url(_) => Task::ready(Ok(None)),
14399                                HoverLink::File(_) => Task::ready(Ok(None)),
14400                            })
14401                            .collect::<Vec<_>>();
14402                        (title, location_tasks, editor.workspace().clone())
14403                    })
14404                    .context("location tasks preparation")?;
14405
14406                let locations = future::join_all(location_tasks)
14407                    .await
14408                    .into_iter()
14409                    .filter_map(|location| location.transpose())
14410                    .collect::<Result<_>>()
14411                    .context("location tasks")?;
14412
14413                let Some(workspace) = workspace else {
14414                    return Ok(Navigated::No);
14415                };
14416                let opened = workspace
14417                    .update_in(cx, |workspace, window, cx| {
14418                        Self::open_locations_in_multibuffer(
14419                            workspace,
14420                            locations,
14421                            title,
14422                            split,
14423                            MultibufferSelectionMode::First,
14424                            window,
14425                            cx,
14426                        )
14427                    })
14428                    .ok();
14429
14430                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14431            })
14432        } else {
14433            Task::ready(Ok(Navigated::No))
14434        }
14435    }
14436
14437    fn compute_target_location(
14438        &self,
14439        lsp_location: lsp::Location,
14440        server_id: LanguageServerId,
14441        window: &mut Window,
14442        cx: &mut Context<Self>,
14443    ) -> Task<anyhow::Result<Option<Location>>> {
14444        let Some(project) = self.project.clone() else {
14445            return Task::ready(Ok(None));
14446        };
14447
14448        cx.spawn_in(window, async move |editor, cx| {
14449            let location_task = editor.update(cx, |_, cx| {
14450                project.update(cx, |project, cx| {
14451                    let language_server_name = project
14452                        .language_server_statuses(cx)
14453                        .find(|(id, _)| server_id == *id)
14454                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14455                    language_server_name.map(|language_server_name| {
14456                        project.open_local_buffer_via_lsp(
14457                            lsp_location.uri.clone(),
14458                            server_id,
14459                            language_server_name,
14460                            cx,
14461                        )
14462                    })
14463                })
14464            })?;
14465            let location = match location_task {
14466                Some(task) => Some({
14467                    let target_buffer_handle = task.await.context("open local buffer")?;
14468                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14469                        let target_start = target_buffer
14470                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14471                        let target_end = target_buffer
14472                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14473                        target_buffer.anchor_after(target_start)
14474                            ..target_buffer.anchor_before(target_end)
14475                    })?;
14476                    Location {
14477                        buffer: target_buffer_handle,
14478                        range,
14479                    }
14480                }),
14481                None => None,
14482            };
14483            Ok(location)
14484        })
14485    }
14486
14487    pub fn find_all_references(
14488        &mut self,
14489        _: &FindAllReferences,
14490        window: &mut Window,
14491        cx: &mut Context<Self>,
14492    ) -> Option<Task<Result<Navigated>>> {
14493        let selection = self.selections.newest::<usize>(cx);
14494        let multi_buffer = self.buffer.read(cx);
14495        let head = selection.head();
14496
14497        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14498        let head_anchor = multi_buffer_snapshot.anchor_at(
14499            head,
14500            if head < selection.tail() {
14501                Bias::Right
14502            } else {
14503                Bias::Left
14504            },
14505        );
14506
14507        match self
14508            .find_all_references_task_sources
14509            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14510        {
14511            Ok(_) => {
14512                log::info!(
14513                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14514                );
14515                return None;
14516            }
14517            Err(i) => {
14518                self.find_all_references_task_sources.insert(i, head_anchor);
14519            }
14520        }
14521
14522        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14523        let workspace = self.workspace()?;
14524        let project = workspace.read(cx).project().clone();
14525        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14526        Some(cx.spawn_in(window, async move |editor, cx| {
14527            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14528                if let Ok(i) = editor
14529                    .find_all_references_task_sources
14530                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14531                {
14532                    editor.find_all_references_task_sources.remove(i);
14533                }
14534            });
14535
14536            let locations = references.await?;
14537            if locations.is_empty() {
14538                return anyhow::Ok(Navigated::No);
14539            }
14540
14541            workspace.update_in(cx, |workspace, window, cx| {
14542                let title = locations
14543                    .first()
14544                    .as_ref()
14545                    .map(|location| {
14546                        let buffer = location.buffer.read(cx);
14547                        format!(
14548                            "References to `{}`",
14549                            buffer
14550                                .text_for_range(location.range.clone())
14551                                .collect::<String>()
14552                        )
14553                    })
14554                    .unwrap();
14555                Self::open_locations_in_multibuffer(
14556                    workspace,
14557                    locations,
14558                    title,
14559                    false,
14560                    MultibufferSelectionMode::First,
14561                    window,
14562                    cx,
14563                );
14564                Navigated::Yes
14565            })
14566        }))
14567    }
14568
14569    /// Opens a multibuffer with the given project locations in it
14570    pub fn open_locations_in_multibuffer(
14571        workspace: &mut Workspace,
14572        mut locations: Vec<Location>,
14573        title: String,
14574        split: bool,
14575        multibuffer_selection_mode: MultibufferSelectionMode,
14576        window: &mut Window,
14577        cx: &mut Context<Workspace>,
14578    ) {
14579        // If there are multiple definitions, open them in a multibuffer
14580        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14581        let mut locations = locations.into_iter().peekable();
14582        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14583        let capability = workspace.project().read(cx).capability();
14584
14585        let excerpt_buffer = cx.new(|cx| {
14586            let mut multibuffer = MultiBuffer::new(capability);
14587            while let Some(location) = locations.next() {
14588                let buffer = location.buffer.read(cx);
14589                let mut ranges_for_buffer = Vec::new();
14590                let range = location.range.to_point(buffer);
14591                ranges_for_buffer.push(range.clone());
14592
14593                while let Some(next_location) = locations.peek() {
14594                    if next_location.buffer == location.buffer {
14595                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14596                        locations.next();
14597                    } else {
14598                        break;
14599                    }
14600                }
14601
14602                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14603                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14604                    PathKey::for_buffer(&location.buffer, cx),
14605                    location.buffer.clone(),
14606                    ranges_for_buffer,
14607                    DEFAULT_MULTIBUFFER_CONTEXT,
14608                    cx,
14609                );
14610                ranges.extend(new_ranges)
14611            }
14612
14613            multibuffer.with_title(title)
14614        });
14615
14616        let editor = cx.new(|cx| {
14617            Editor::for_multibuffer(
14618                excerpt_buffer,
14619                Some(workspace.project().clone()),
14620                window,
14621                cx,
14622            )
14623        });
14624        editor.update(cx, |editor, cx| {
14625            match multibuffer_selection_mode {
14626                MultibufferSelectionMode::First => {
14627                    if let Some(first_range) = ranges.first() {
14628                        editor.change_selections(None, window, cx, |selections| {
14629                            selections.clear_disjoint();
14630                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14631                        });
14632                    }
14633                    editor.highlight_background::<Self>(
14634                        &ranges,
14635                        |theme| theme.editor_highlighted_line_background,
14636                        cx,
14637                    );
14638                }
14639                MultibufferSelectionMode::All => {
14640                    editor.change_selections(None, window, cx, |selections| {
14641                        selections.clear_disjoint();
14642                        selections.select_anchor_ranges(ranges);
14643                    });
14644                }
14645            }
14646            editor.register_buffers_with_language_servers(cx);
14647        });
14648
14649        let item = Box::new(editor);
14650        let item_id = item.item_id();
14651
14652        if split {
14653            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14654        } else {
14655            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14656                let (preview_item_id, preview_item_idx) =
14657                    workspace.active_pane().update(cx, |pane, _| {
14658                        (pane.preview_item_id(), pane.preview_item_idx())
14659                    });
14660
14661                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14662
14663                if let Some(preview_item_id) = preview_item_id {
14664                    workspace.active_pane().update(cx, |pane, cx| {
14665                        pane.remove_item(preview_item_id, false, false, window, cx);
14666                    });
14667                }
14668            } else {
14669                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14670            }
14671        }
14672        workspace.active_pane().update(cx, |pane, cx| {
14673            pane.set_preview_item_id(Some(item_id), cx);
14674        });
14675    }
14676
14677    pub fn rename(
14678        &mut self,
14679        _: &Rename,
14680        window: &mut Window,
14681        cx: &mut Context<Self>,
14682    ) -> Option<Task<Result<()>>> {
14683        use language::ToOffset as _;
14684
14685        let provider = self.semantics_provider.clone()?;
14686        let selection = self.selections.newest_anchor().clone();
14687        let (cursor_buffer, cursor_buffer_position) = self
14688            .buffer
14689            .read(cx)
14690            .text_anchor_for_position(selection.head(), cx)?;
14691        let (tail_buffer, cursor_buffer_position_end) = self
14692            .buffer
14693            .read(cx)
14694            .text_anchor_for_position(selection.tail(), cx)?;
14695        if tail_buffer != cursor_buffer {
14696            return None;
14697        }
14698
14699        let snapshot = cursor_buffer.read(cx).snapshot();
14700        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14701        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14702        let prepare_rename = provider
14703            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14704            .unwrap_or_else(|| Task::ready(Ok(None)));
14705        drop(snapshot);
14706
14707        Some(cx.spawn_in(window, async move |this, cx| {
14708            let rename_range = if let Some(range) = prepare_rename.await? {
14709                Some(range)
14710            } else {
14711                this.update(cx, |this, cx| {
14712                    let buffer = this.buffer.read(cx).snapshot(cx);
14713                    let mut buffer_highlights = this
14714                        .document_highlights_for_position(selection.head(), &buffer)
14715                        .filter(|highlight| {
14716                            highlight.start.excerpt_id == selection.head().excerpt_id
14717                                && highlight.end.excerpt_id == selection.head().excerpt_id
14718                        });
14719                    buffer_highlights
14720                        .next()
14721                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14722                })?
14723            };
14724            if let Some(rename_range) = rename_range {
14725                this.update_in(cx, |this, window, cx| {
14726                    let snapshot = cursor_buffer.read(cx).snapshot();
14727                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14728                    let cursor_offset_in_rename_range =
14729                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14730                    let cursor_offset_in_rename_range_end =
14731                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14732
14733                    this.take_rename(false, window, cx);
14734                    let buffer = this.buffer.read(cx).read(cx);
14735                    let cursor_offset = selection.head().to_offset(&buffer);
14736                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14737                    let rename_end = rename_start + rename_buffer_range.len();
14738                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14739                    let mut old_highlight_id = None;
14740                    let old_name: Arc<str> = buffer
14741                        .chunks(rename_start..rename_end, true)
14742                        .map(|chunk| {
14743                            if old_highlight_id.is_none() {
14744                                old_highlight_id = chunk.syntax_highlight_id;
14745                            }
14746                            chunk.text
14747                        })
14748                        .collect::<String>()
14749                        .into();
14750
14751                    drop(buffer);
14752
14753                    // Position the selection in the rename editor so that it matches the current selection.
14754                    this.show_local_selections = false;
14755                    let rename_editor = cx.new(|cx| {
14756                        let mut editor = Editor::single_line(window, cx);
14757                        editor.buffer.update(cx, |buffer, cx| {
14758                            buffer.edit([(0..0, old_name.clone())], None, cx)
14759                        });
14760                        let rename_selection_range = match cursor_offset_in_rename_range
14761                            .cmp(&cursor_offset_in_rename_range_end)
14762                        {
14763                            Ordering::Equal => {
14764                                editor.select_all(&SelectAll, window, cx);
14765                                return editor;
14766                            }
14767                            Ordering::Less => {
14768                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14769                            }
14770                            Ordering::Greater => {
14771                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14772                            }
14773                        };
14774                        if rename_selection_range.end > old_name.len() {
14775                            editor.select_all(&SelectAll, window, cx);
14776                        } else {
14777                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14778                                s.select_ranges([rename_selection_range]);
14779                            });
14780                        }
14781                        editor
14782                    });
14783                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14784                        if e == &EditorEvent::Focused {
14785                            cx.emit(EditorEvent::FocusedIn)
14786                        }
14787                    })
14788                    .detach();
14789
14790                    let write_highlights =
14791                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14792                    let read_highlights =
14793                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14794                    let ranges = write_highlights
14795                        .iter()
14796                        .flat_map(|(_, ranges)| ranges.iter())
14797                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14798                        .cloned()
14799                        .collect();
14800
14801                    this.highlight_text::<Rename>(
14802                        ranges,
14803                        HighlightStyle {
14804                            fade_out: Some(0.6),
14805                            ..Default::default()
14806                        },
14807                        cx,
14808                    );
14809                    let rename_focus_handle = rename_editor.focus_handle(cx);
14810                    window.focus(&rename_focus_handle);
14811                    let block_id = this.insert_blocks(
14812                        [BlockProperties {
14813                            style: BlockStyle::Flex,
14814                            placement: BlockPlacement::Below(range.start),
14815                            height: Some(1),
14816                            render: Arc::new({
14817                                let rename_editor = rename_editor.clone();
14818                                move |cx: &mut BlockContext| {
14819                                    let mut text_style = cx.editor_style.text.clone();
14820                                    if let Some(highlight_style) = old_highlight_id
14821                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14822                                    {
14823                                        text_style = text_style.highlight(highlight_style);
14824                                    }
14825                                    div()
14826                                        .block_mouse_down()
14827                                        .pl(cx.anchor_x)
14828                                        .child(EditorElement::new(
14829                                            &rename_editor,
14830                                            EditorStyle {
14831                                                background: cx.theme().system().transparent,
14832                                                local_player: cx.editor_style.local_player,
14833                                                text: text_style,
14834                                                scrollbar_width: cx.editor_style.scrollbar_width,
14835                                                syntax: cx.editor_style.syntax.clone(),
14836                                                status: cx.editor_style.status.clone(),
14837                                                inlay_hints_style: HighlightStyle {
14838                                                    font_weight: Some(FontWeight::BOLD),
14839                                                    ..make_inlay_hints_style(cx.app)
14840                                                },
14841                                                inline_completion_styles: make_suggestion_styles(
14842                                                    cx.app,
14843                                                ),
14844                                                ..EditorStyle::default()
14845                                            },
14846                                        ))
14847                                        .into_any_element()
14848                                }
14849                            }),
14850                            priority: 0,
14851                            render_in_minimap: true,
14852                        }],
14853                        Some(Autoscroll::fit()),
14854                        cx,
14855                    )[0];
14856                    this.pending_rename = Some(RenameState {
14857                        range,
14858                        old_name,
14859                        editor: rename_editor,
14860                        block_id,
14861                    });
14862                })?;
14863            }
14864
14865            Ok(())
14866        }))
14867    }
14868
14869    pub fn confirm_rename(
14870        &mut self,
14871        _: &ConfirmRename,
14872        window: &mut Window,
14873        cx: &mut Context<Self>,
14874    ) -> Option<Task<Result<()>>> {
14875        let rename = self.take_rename(false, window, cx)?;
14876        let workspace = self.workspace()?.downgrade();
14877        let (buffer, start) = self
14878            .buffer
14879            .read(cx)
14880            .text_anchor_for_position(rename.range.start, cx)?;
14881        let (end_buffer, _) = self
14882            .buffer
14883            .read(cx)
14884            .text_anchor_for_position(rename.range.end, cx)?;
14885        if buffer != end_buffer {
14886            return None;
14887        }
14888
14889        let old_name = rename.old_name;
14890        let new_name = rename.editor.read(cx).text(cx);
14891
14892        let rename = self.semantics_provider.as_ref()?.perform_rename(
14893            &buffer,
14894            start,
14895            new_name.clone(),
14896            cx,
14897        )?;
14898
14899        Some(cx.spawn_in(window, async move |editor, cx| {
14900            let project_transaction = rename.await?;
14901            Self::open_project_transaction(
14902                &editor,
14903                workspace,
14904                project_transaction,
14905                format!("Rename: {}{}", old_name, new_name),
14906                cx,
14907            )
14908            .await?;
14909
14910            editor.update(cx, |editor, cx| {
14911                editor.refresh_document_highlights(cx);
14912            })?;
14913            Ok(())
14914        }))
14915    }
14916
14917    fn take_rename(
14918        &mut self,
14919        moving_cursor: bool,
14920        window: &mut Window,
14921        cx: &mut Context<Self>,
14922    ) -> Option<RenameState> {
14923        let rename = self.pending_rename.take()?;
14924        if rename.editor.focus_handle(cx).is_focused(window) {
14925            window.focus(&self.focus_handle);
14926        }
14927
14928        self.remove_blocks(
14929            [rename.block_id].into_iter().collect(),
14930            Some(Autoscroll::fit()),
14931            cx,
14932        );
14933        self.clear_highlights::<Rename>(cx);
14934        self.show_local_selections = true;
14935
14936        if moving_cursor {
14937            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14938                editor.selections.newest::<usize>(cx).head()
14939            });
14940
14941            // Update the selection to match the position of the selection inside
14942            // the rename editor.
14943            let snapshot = self.buffer.read(cx).read(cx);
14944            let rename_range = rename.range.to_offset(&snapshot);
14945            let cursor_in_editor = snapshot
14946                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14947                .min(rename_range.end);
14948            drop(snapshot);
14949
14950            self.change_selections(None, window, cx, |s| {
14951                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14952            });
14953        } else {
14954            self.refresh_document_highlights(cx);
14955        }
14956
14957        Some(rename)
14958    }
14959
14960    pub fn pending_rename(&self) -> Option<&RenameState> {
14961        self.pending_rename.as_ref()
14962    }
14963
14964    fn format(
14965        &mut self,
14966        _: &Format,
14967        window: &mut Window,
14968        cx: &mut Context<Self>,
14969    ) -> Option<Task<Result<()>>> {
14970        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14971
14972        let project = match &self.project {
14973            Some(project) => project.clone(),
14974            None => return None,
14975        };
14976
14977        Some(self.perform_format(
14978            project,
14979            FormatTrigger::Manual,
14980            FormatTarget::Buffers,
14981            window,
14982            cx,
14983        ))
14984    }
14985
14986    fn format_selections(
14987        &mut self,
14988        _: &FormatSelections,
14989        window: &mut Window,
14990        cx: &mut Context<Self>,
14991    ) -> Option<Task<Result<()>>> {
14992        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14993
14994        let project = match &self.project {
14995            Some(project) => project.clone(),
14996            None => return None,
14997        };
14998
14999        let ranges = self
15000            .selections
15001            .all_adjusted(cx)
15002            .into_iter()
15003            .map(|selection| selection.range())
15004            .collect_vec();
15005
15006        Some(self.perform_format(
15007            project,
15008            FormatTrigger::Manual,
15009            FormatTarget::Ranges(ranges),
15010            window,
15011            cx,
15012        ))
15013    }
15014
15015    fn perform_format(
15016        &mut self,
15017        project: Entity<Project>,
15018        trigger: FormatTrigger,
15019        target: FormatTarget,
15020        window: &mut Window,
15021        cx: &mut Context<Self>,
15022    ) -> Task<Result<()>> {
15023        let buffer = self.buffer.clone();
15024        let (buffers, target) = match target {
15025            FormatTarget::Buffers => {
15026                let mut buffers = buffer.read(cx).all_buffers();
15027                if trigger == FormatTrigger::Save {
15028                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15029                }
15030                (buffers, LspFormatTarget::Buffers)
15031            }
15032            FormatTarget::Ranges(selection_ranges) => {
15033                let multi_buffer = buffer.read(cx);
15034                let snapshot = multi_buffer.read(cx);
15035                let mut buffers = HashSet::default();
15036                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15037                    BTreeMap::new();
15038                for selection_range in selection_ranges {
15039                    for (buffer, buffer_range, _) in
15040                        snapshot.range_to_buffer_ranges(selection_range)
15041                    {
15042                        let buffer_id = buffer.remote_id();
15043                        let start = buffer.anchor_before(buffer_range.start);
15044                        let end = buffer.anchor_after(buffer_range.end);
15045                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15046                        buffer_id_to_ranges
15047                            .entry(buffer_id)
15048                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15049                            .or_insert_with(|| vec![start..end]);
15050                    }
15051                }
15052                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15053            }
15054        };
15055
15056        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15057        let selections_prev = transaction_id_prev
15058            .and_then(|transaction_id_prev| {
15059                // default to selections as they were after the last edit, if we have them,
15060                // instead of how they are now.
15061                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15062                // will take you back to where you made the last edit, instead of staying where you scrolled
15063                self.selection_history
15064                    .transaction(transaction_id_prev)
15065                    .map(|t| t.0.clone())
15066            })
15067            .unwrap_or_else(|| {
15068                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15069                self.selections.disjoint_anchors()
15070            });
15071
15072        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15073        let format = project.update(cx, |project, cx| {
15074            project.format(buffers, target, true, trigger, cx)
15075        });
15076
15077        cx.spawn_in(window, async move |editor, cx| {
15078            let transaction = futures::select_biased! {
15079                transaction = format.log_err().fuse() => transaction,
15080                () = timeout => {
15081                    log::warn!("timed out waiting for formatting");
15082                    None
15083                }
15084            };
15085
15086            buffer
15087                .update(cx, |buffer, cx| {
15088                    if let Some(transaction) = transaction {
15089                        if !buffer.is_singleton() {
15090                            buffer.push_transaction(&transaction.0, cx);
15091                        }
15092                    }
15093                    cx.notify();
15094                })
15095                .ok();
15096
15097            if let Some(transaction_id_now) =
15098                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15099            {
15100                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15101                if has_new_transaction {
15102                    _ = editor.update(cx, |editor, _| {
15103                        editor
15104                            .selection_history
15105                            .insert_transaction(transaction_id_now, selections_prev);
15106                    });
15107                }
15108            }
15109
15110            Ok(())
15111        })
15112    }
15113
15114    fn organize_imports(
15115        &mut self,
15116        _: &OrganizeImports,
15117        window: &mut Window,
15118        cx: &mut Context<Self>,
15119    ) -> Option<Task<Result<()>>> {
15120        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15121        let project = match &self.project {
15122            Some(project) => project.clone(),
15123            None => return None,
15124        };
15125        Some(self.perform_code_action_kind(
15126            project,
15127            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15128            window,
15129            cx,
15130        ))
15131    }
15132
15133    fn perform_code_action_kind(
15134        &mut self,
15135        project: Entity<Project>,
15136        kind: CodeActionKind,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) -> Task<Result<()>> {
15140        let buffer = self.buffer.clone();
15141        let buffers = buffer.read(cx).all_buffers();
15142        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15143        let apply_action = project.update(cx, |project, cx| {
15144            project.apply_code_action_kind(buffers, kind, true, cx)
15145        });
15146        cx.spawn_in(window, async move |_, cx| {
15147            let transaction = futures::select_biased! {
15148                () = timeout => {
15149                    log::warn!("timed out waiting for executing code action");
15150                    None
15151                }
15152                transaction = apply_action.log_err().fuse() => transaction,
15153            };
15154            buffer
15155                .update(cx, |buffer, cx| {
15156                    // check if we need this
15157                    if let Some(transaction) = transaction {
15158                        if !buffer.is_singleton() {
15159                            buffer.push_transaction(&transaction.0, cx);
15160                        }
15161                    }
15162                    cx.notify();
15163                })
15164                .ok();
15165            Ok(())
15166        })
15167    }
15168
15169    fn restart_language_server(
15170        &mut self,
15171        _: &RestartLanguageServer,
15172        _: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        if let Some(project) = self.project.clone() {
15176            self.buffer.update(cx, |multi_buffer, cx| {
15177                project.update(cx, |project, cx| {
15178                    project.restart_language_servers_for_buffers(
15179                        multi_buffer.all_buffers().into_iter().collect(),
15180                        cx,
15181                    );
15182                });
15183            })
15184        }
15185    }
15186
15187    fn stop_language_server(
15188        &mut self,
15189        _: &StopLanguageServer,
15190        _: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        if let Some(project) = self.project.clone() {
15194            self.buffer.update(cx, |multi_buffer, cx| {
15195                project.update(cx, |project, cx| {
15196                    project.stop_language_servers_for_buffers(
15197                        multi_buffer.all_buffers().into_iter().collect(),
15198                        cx,
15199                    );
15200                    cx.emit(project::Event::RefreshInlayHints);
15201                });
15202            });
15203        }
15204    }
15205
15206    fn cancel_language_server_work(
15207        workspace: &mut Workspace,
15208        _: &actions::CancelLanguageServerWork,
15209        _: &mut Window,
15210        cx: &mut Context<Workspace>,
15211    ) {
15212        let project = workspace.project();
15213        let buffers = workspace
15214            .active_item(cx)
15215            .and_then(|item| item.act_as::<Editor>(cx))
15216            .map_or(HashSet::default(), |editor| {
15217                editor.read(cx).buffer.read(cx).all_buffers()
15218            });
15219        project.update(cx, |project, cx| {
15220            project.cancel_language_server_work_for_buffers(buffers, cx);
15221        });
15222    }
15223
15224    fn show_character_palette(
15225        &mut self,
15226        _: &ShowCharacterPalette,
15227        window: &mut Window,
15228        _: &mut Context<Self>,
15229    ) {
15230        window.show_character_palette();
15231    }
15232
15233    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15234        if self.mode.is_minimap() {
15235            return;
15236        }
15237
15238        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15239            let buffer = self.buffer.read(cx).snapshot(cx);
15240            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15241            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15242            let is_valid = buffer
15243                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15244                .any(|entry| {
15245                    entry.diagnostic.is_primary
15246                        && !entry.range.is_empty()
15247                        && entry.range.start == primary_range_start
15248                        && entry.diagnostic.message == active_diagnostics.active_message
15249                });
15250
15251            if !is_valid {
15252                self.dismiss_diagnostics(cx);
15253            }
15254        }
15255    }
15256
15257    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15258        match &self.active_diagnostics {
15259            ActiveDiagnostic::Group(group) => Some(group),
15260            _ => None,
15261        }
15262    }
15263
15264    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15265        self.dismiss_diagnostics(cx);
15266        self.active_diagnostics = ActiveDiagnostic::All;
15267    }
15268
15269    fn activate_diagnostics(
15270        &mut self,
15271        buffer_id: BufferId,
15272        diagnostic: DiagnosticEntry<usize>,
15273        window: &mut Window,
15274        cx: &mut Context<Self>,
15275    ) {
15276        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15277            return;
15278        }
15279        self.dismiss_diagnostics(cx);
15280        let snapshot = self.snapshot(window, cx);
15281        let buffer = self.buffer.read(cx).snapshot(cx);
15282        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15283            return;
15284        };
15285
15286        let diagnostic_group = buffer
15287            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15288            .collect::<Vec<_>>();
15289
15290        let blocks =
15291            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15292
15293        let blocks = self.display_map.update(cx, |display_map, cx| {
15294            display_map.insert_blocks(blocks, cx).into_iter().collect()
15295        });
15296        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15297            active_range: buffer.anchor_before(diagnostic.range.start)
15298                ..buffer.anchor_after(diagnostic.range.end),
15299            active_message: diagnostic.diagnostic.message.clone(),
15300            group_id: diagnostic.diagnostic.group_id,
15301            blocks,
15302        });
15303        cx.notify();
15304    }
15305
15306    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15307        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15308            return;
15309        };
15310
15311        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15312        if let ActiveDiagnostic::Group(group) = prev {
15313            self.display_map.update(cx, |display_map, cx| {
15314                display_map.remove_blocks(group.blocks, cx);
15315            });
15316            cx.notify();
15317        }
15318    }
15319
15320    /// Disable inline diagnostics rendering for this editor.
15321    pub fn disable_inline_diagnostics(&mut self) {
15322        self.inline_diagnostics_enabled = false;
15323        self.inline_diagnostics_update = Task::ready(());
15324        self.inline_diagnostics.clear();
15325    }
15326
15327    pub fn diagnostics_enabled(&self) -> bool {
15328        self.mode.is_full()
15329    }
15330
15331    pub fn inline_diagnostics_enabled(&self) -> bool {
15332        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15333    }
15334
15335    pub fn show_inline_diagnostics(&self) -> bool {
15336        self.show_inline_diagnostics
15337    }
15338
15339    pub fn toggle_inline_diagnostics(
15340        &mut self,
15341        _: &ToggleInlineDiagnostics,
15342        window: &mut Window,
15343        cx: &mut Context<Editor>,
15344    ) {
15345        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15346        self.refresh_inline_diagnostics(false, window, cx);
15347    }
15348
15349    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15350        self.diagnostics_max_severity = severity;
15351        self.display_map.update(cx, |display_map, _| {
15352            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15353        });
15354    }
15355
15356    pub fn toggle_diagnostics(
15357        &mut self,
15358        _: &ToggleDiagnostics,
15359        window: &mut Window,
15360        cx: &mut Context<Editor>,
15361    ) {
15362        if !self.diagnostics_enabled() {
15363            return;
15364        }
15365
15366        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15367            EditorSettings::get_global(cx)
15368                .diagnostics_max_severity
15369                .filter(|severity| severity != &DiagnosticSeverity::Off)
15370                .unwrap_or(DiagnosticSeverity::Hint)
15371        } else {
15372            DiagnosticSeverity::Off
15373        };
15374        self.set_max_diagnostics_severity(new_severity, cx);
15375        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15376            self.active_diagnostics = ActiveDiagnostic::None;
15377            self.inline_diagnostics_update = Task::ready(());
15378            self.inline_diagnostics.clear();
15379        } else {
15380            self.refresh_inline_diagnostics(false, window, cx);
15381        }
15382
15383        cx.notify();
15384    }
15385
15386    pub fn toggle_minimap(
15387        &mut self,
15388        _: &ToggleMinimap,
15389        window: &mut Window,
15390        cx: &mut Context<Editor>,
15391    ) {
15392        if self.supports_minimap(cx) {
15393            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15394        }
15395    }
15396
15397    fn refresh_inline_diagnostics(
15398        &mut self,
15399        debounce: bool,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        let max_severity = ProjectSettings::get_global(cx)
15404            .diagnostics
15405            .inline
15406            .max_severity
15407            .unwrap_or(self.diagnostics_max_severity);
15408
15409        if self.mode.is_minimap()
15410            || !self.inline_diagnostics_enabled()
15411            || !self.show_inline_diagnostics
15412            || max_severity == DiagnosticSeverity::Off
15413        {
15414            self.inline_diagnostics_update = Task::ready(());
15415            self.inline_diagnostics.clear();
15416            return;
15417        }
15418
15419        let debounce_ms = ProjectSettings::get_global(cx)
15420            .diagnostics
15421            .inline
15422            .update_debounce_ms;
15423        let debounce = if debounce && debounce_ms > 0 {
15424            Some(Duration::from_millis(debounce_ms))
15425        } else {
15426            None
15427        };
15428        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15429            let editor = editor.upgrade().unwrap();
15430
15431            if let Some(debounce) = debounce {
15432                cx.background_executor().timer(debounce).await;
15433            }
15434            let Some(snapshot) = editor
15435                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15436                .ok()
15437            else {
15438                return;
15439            };
15440
15441            let new_inline_diagnostics = cx
15442                .background_spawn(async move {
15443                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15444                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15445                        let message = diagnostic_entry
15446                            .diagnostic
15447                            .message
15448                            .split_once('\n')
15449                            .map(|(line, _)| line)
15450                            .map(SharedString::new)
15451                            .unwrap_or_else(|| {
15452                                SharedString::from(diagnostic_entry.diagnostic.message)
15453                            });
15454                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15455                        let (Ok(i) | Err(i)) = inline_diagnostics
15456                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15457                        inline_diagnostics.insert(
15458                            i,
15459                            (
15460                                start_anchor,
15461                                InlineDiagnostic {
15462                                    message,
15463                                    group_id: diagnostic_entry.diagnostic.group_id,
15464                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15465                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15466                                    severity: diagnostic_entry.diagnostic.severity,
15467                                },
15468                            ),
15469                        );
15470                    }
15471                    inline_diagnostics
15472                })
15473                .await;
15474
15475            editor
15476                .update(cx, |editor, cx| {
15477                    editor.inline_diagnostics = new_inline_diagnostics;
15478                    cx.notify();
15479                })
15480                .ok();
15481        });
15482    }
15483
15484    pub fn set_selections_from_remote(
15485        &mut self,
15486        selections: Vec<Selection<Anchor>>,
15487        pending_selection: Option<Selection<Anchor>>,
15488        window: &mut Window,
15489        cx: &mut Context<Self>,
15490    ) {
15491        let old_cursor_position = self.selections.newest_anchor().head();
15492        self.selections.change_with(cx, |s| {
15493            s.select_anchors(selections);
15494            if let Some(pending_selection) = pending_selection {
15495                s.set_pending(pending_selection, SelectMode::Character);
15496            } else {
15497                s.clear_pending();
15498            }
15499        });
15500        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15501    }
15502
15503    fn push_to_selection_history(&mut self) {
15504        self.selection_history.push(SelectionHistoryEntry {
15505            selections: self.selections.disjoint_anchors(),
15506            select_next_state: self.select_next_state.clone(),
15507            select_prev_state: self.select_prev_state.clone(),
15508            add_selections_state: self.add_selections_state.clone(),
15509        });
15510    }
15511
15512    pub fn transact(
15513        &mut self,
15514        window: &mut Window,
15515        cx: &mut Context<Self>,
15516        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15517    ) -> Option<TransactionId> {
15518        self.start_transaction_at(Instant::now(), window, cx);
15519        update(self, window, cx);
15520        self.end_transaction_at(Instant::now(), cx)
15521    }
15522
15523    pub fn start_transaction_at(
15524        &mut self,
15525        now: Instant,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) {
15529        self.end_selection(window, cx);
15530        if let Some(tx_id) = self
15531            .buffer
15532            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15533        {
15534            self.selection_history
15535                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15536            cx.emit(EditorEvent::TransactionBegun {
15537                transaction_id: tx_id,
15538            })
15539        }
15540    }
15541
15542    pub fn end_transaction_at(
15543        &mut self,
15544        now: Instant,
15545        cx: &mut Context<Self>,
15546    ) -> Option<TransactionId> {
15547        if let Some(transaction_id) = self
15548            .buffer
15549            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15550        {
15551            if let Some((_, end_selections)) =
15552                self.selection_history.transaction_mut(transaction_id)
15553            {
15554                *end_selections = Some(self.selections.disjoint_anchors());
15555            } else {
15556                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15557            }
15558
15559            cx.emit(EditorEvent::Edited { transaction_id });
15560            Some(transaction_id)
15561        } else {
15562            None
15563        }
15564    }
15565
15566    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15567        if self.selection_mark_mode {
15568            self.change_selections(None, window, cx, |s| {
15569                s.move_with(|_, sel| {
15570                    sel.collapse_to(sel.head(), SelectionGoal::None);
15571                });
15572            })
15573        }
15574        self.selection_mark_mode = true;
15575        cx.notify();
15576    }
15577
15578    pub fn swap_selection_ends(
15579        &mut self,
15580        _: &actions::SwapSelectionEnds,
15581        window: &mut Window,
15582        cx: &mut Context<Self>,
15583    ) {
15584        self.change_selections(None, window, cx, |s| {
15585            s.move_with(|_, sel| {
15586                if sel.start != sel.end {
15587                    sel.reversed = !sel.reversed
15588                }
15589            });
15590        });
15591        self.request_autoscroll(Autoscroll::newest(), cx);
15592        cx.notify();
15593    }
15594
15595    pub fn toggle_fold(
15596        &mut self,
15597        _: &actions::ToggleFold,
15598        window: &mut Window,
15599        cx: &mut Context<Self>,
15600    ) {
15601        if self.is_singleton(cx) {
15602            let selection = self.selections.newest::<Point>(cx);
15603
15604            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15605            let range = if selection.is_empty() {
15606                let point = selection.head().to_display_point(&display_map);
15607                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15608                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15609                    .to_point(&display_map);
15610                start..end
15611            } else {
15612                selection.range()
15613            };
15614            if display_map.folds_in_range(range).next().is_some() {
15615                self.unfold_lines(&Default::default(), window, cx)
15616            } else {
15617                self.fold(&Default::default(), window, cx)
15618            }
15619        } else {
15620            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15621            let buffer_ids: HashSet<_> = self
15622                .selections
15623                .disjoint_anchor_ranges()
15624                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15625                .collect();
15626
15627            let should_unfold = buffer_ids
15628                .iter()
15629                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15630
15631            for buffer_id in buffer_ids {
15632                if should_unfold {
15633                    self.unfold_buffer(buffer_id, cx);
15634                } else {
15635                    self.fold_buffer(buffer_id, cx);
15636                }
15637            }
15638        }
15639    }
15640
15641    pub fn toggle_fold_recursive(
15642        &mut self,
15643        _: &actions::ToggleFoldRecursive,
15644        window: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) {
15647        let selection = self.selections.newest::<Point>(cx);
15648
15649        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15650        let range = if selection.is_empty() {
15651            let point = selection.head().to_display_point(&display_map);
15652            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15653            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15654                .to_point(&display_map);
15655            start..end
15656        } else {
15657            selection.range()
15658        };
15659        if display_map.folds_in_range(range).next().is_some() {
15660            self.unfold_recursive(&Default::default(), window, cx)
15661        } else {
15662            self.fold_recursive(&Default::default(), window, cx)
15663        }
15664    }
15665
15666    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15667        if self.is_singleton(cx) {
15668            let mut to_fold = Vec::new();
15669            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15670            let selections = self.selections.all_adjusted(cx);
15671
15672            for selection in selections {
15673                let range = selection.range().sorted();
15674                let buffer_start_row = range.start.row;
15675
15676                if range.start.row != range.end.row {
15677                    let mut found = false;
15678                    let mut row = range.start.row;
15679                    while row <= range.end.row {
15680                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15681                        {
15682                            found = true;
15683                            row = crease.range().end.row + 1;
15684                            to_fold.push(crease);
15685                        } else {
15686                            row += 1
15687                        }
15688                    }
15689                    if found {
15690                        continue;
15691                    }
15692                }
15693
15694                for row in (0..=range.start.row).rev() {
15695                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15696                        if crease.range().end.row >= buffer_start_row {
15697                            to_fold.push(crease);
15698                            if row <= range.start.row {
15699                                break;
15700                            }
15701                        }
15702                    }
15703                }
15704            }
15705
15706            self.fold_creases(to_fold, true, window, cx);
15707        } else {
15708            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15709            let buffer_ids = self
15710                .selections
15711                .disjoint_anchor_ranges()
15712                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15713                .collect::<HashSet<_>>();
15714            for buffer_id in buffer_ids {
15715                self.fold_buffer(buffer_id, cx);
15716            }
15717        }
15718    }
15719
15720    fn fold_at_level(
15721        &mut self,
15722        fold_at: &FoldAtLevel,
15723        window: &mut Window,
15724        cx: &mut Context<Self>,
15725    ) {
15726        if !self.buffer.read(cx).is_singleton() {
15727            return;
15728        }
15729
15730        let fold_at_level = fold_at.0;
15731        let snapshot = self.buffer.read(cx).snapshot(cx);
15732        let mut to_fold = Vec::new();
15733        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15734
15735        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15736            while start_row < end_row {
15737                match self
15738                    .snapshot(window, cx)
15739                    .crease_for_buffer_row(MultiBufferRow(start_row))
15740                {
15741                    Some(crease) => {
15742                        let nested_start_row = crease.range().start.row + 1;
15743                        let nested_end_row = crease.range().end.row;
15744
15745                        if current_level < fold_at_level {
15746                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15747                        } else if current_level == fold_at_level {
15748                            to_fold.push(crease);
15749                        }
15750
15751                        start_row = nested_end_row + 1;
15752                    }
15753                    None => start_row += 1,
15754                }
15755            }
15756        }
15757
15758        self.fold_creases(to_fold, true, window, cx);
15759    }
15760
15761    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15762        if self.buffer.read(cx).is_singleton() {
15763            let mut fold_ranges = Vec::new();
15764            let snapshot = self.buffer.read(cx).snapshot(cx);
15765
15766            for row in 0..snapshot.max_row().0 {
15767                if let Some(foldable_range) = self
15768                    .snapshot(window, cx)
15769                    .crease_for_buffer_row(MultiBufferRow(row))
15770                {
15771                    fold_ranges.push(foldable_range);
15772                }
15773            }
15774
15775            self.fold_creases(fold_ranges, true, window, cx);
15776        } else {
15777            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15778                editor
15779                    .update_in(cx, |editor, _, cx| {
15780                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15781                            editor.fold_buffer(buffer_id, cx);
15782                        }
15783                    })
15784                    .ok();
15785            });
15786        }
15787    }
15788
15789    pub fn fold_function_bodies(
15790        &mut self,
15791        _: &actions::FoldFunctionBodies,
15792        window: &mut Window,
15793        cx: &mut Context<Self>,
15794    ) {
15795        let snapshot = self.buffer.read(cx).snapshot(cx);
15796
15797        let ranges = snapshot
15798            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15799            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15800            .collect::<Vec<_>>();
15801
15802        let creases = ranges
15803            .into_iter()
15804            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15805            .collect();
15806
15807        self.fold_creases(creases, true, window, cx);
15808    }
15809
15810    pub fn fold_recursive(
15811        &mut self,
15812        _: &actions::FoldRecursive,
15813        window: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) {
15816        let mut to_fold = Vec::new();
15817        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15818        let selections = self.selections.all_adjusted(cx);
15819
15820        for selection in selections {
15821            let range = selection.range().sorted();
15822            let buffer_start_row = range.start.row;
15823
15824            if range.start.row != range.end.row {
15825                let mut found = false;
15826                for row in range.start.row..=range.end.row {
15827                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15828                        found = true;
15829                        to_fold.push(crease);
15830                    }
15831                }
15832                if found {
15833                    continue;
15834                }
15835            }
15836
15837            for row in (0..=range.start.row).rev() {
15838                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15839                    if crease.range().end.row >= buffer_start_row {
15840                        to_fold.push(crease);
15841                    } else {
15842                        break;
15843                    }
15844                }
15845            }
15846        }
15847
15848        self.fold_creases(to_fold, true, window, cx);
15849    }
15850
15851    pub fn fold_at(
15852        &mut self,
15853        buffer_row: MultiBufferRow,
15854        window: &mut Window,
15855        cx: &mut Context<Self>,
15856    ) {
15857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15858
15859        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15860            let autoscroll = self
15861                .selections
15862                .all::<Point>(cx)
15863                .iter()
15864                .any(|selection| crease.range().overlaps(&selection.range()));
15865
15866            self.fold_creases(vec![crease], autoscroll, window, cx);
15867        }
15868    }
15869
15870    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15871        if self.is_singleton(cx) {
15872            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15873            let buffer = &display_map.buffer_snapshot;
15874            let selections = self.selections.all::<Point>(cx);
15875            let ranges = selections
15876                .iter()
15877                .map(|s| {
15878                    let range = s.display_range(&display_map).sorted();
15879                    let mut start = range.start.to_point(&display_map);
15880                    let mut end = range.end.to_point(&display_map);
15881                    start.column = 0;
15882                    end.column = buffer.line_len(MultiBufferRow(end.row));
15883                    start..end
15884                })
15885                .collect::<Vec<_>>();
15886
15887            self.unfold_ranges(&ranges, true, true, cx);
15888        } else {
15889            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15890            let buffer_ids = self
15891                .selections
15892                .disjoint_anchor_ranges()
15893                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15894                .collect::<HashSet<_>>();
15895            for buffer_id in buffer_ids {
15896                self.unfold_buffer(buffer_id, cx);
15897            }
15898        }
15899    }
15900
15901    pub fn unfold_recursive(
15902        &mut self,
15903        _: &UnfoldRecursive,
15904        _window: &mut Window,
15905        cx: &mut Context<Self>,
15906    ) {
15907        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15908        let selections = self.selections.all::<Point>(cx);
15909        let ranges = selections
15910            .iter()
15911            .map(|s| {
15912                let mut range = s.display_range(&display_map).sorted();
15913                *range.start.column_mut() = 0;
15914                *range.end.column_mut() = display_map.line_len(range.end.row());
15915                let start = range.start.to_point(&display_map);
15916                let end = range.end.to_point(&display_map);
15917                start..end
15918            })
15919            .collect::<Vec<_>>();
15920
15921        self.unfold_ranges(&ranges, true, true, cx);
15922    }
15923
15924    pub fn unfold_at(
15925        &mut self,
15926        buffer_row: MultiBufferRow,
15927        _window: &mut Window,
15928        cx: &mut Context<Self>,
15929    ) {
15930        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15931
15932        let intersection_range = Point::new(buffer_row.0, 0)
15933            ..Point::new(
15934                buffer_row.0,
15935                display_map.buffer_snapshot.line_len(buffer_row),
15936            );
15937
15938        let autoscroll = self
15939            .selections
15940            .all::<Point>(cx)
15941            .iter()
15942            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15943
15944        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15945    }
15946
15947    pub fn unfold_all(
15948        &mut self,
15949        _: &actions::UnfoldAll,
15950        _window: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        if self.buffer.read(cx).is_singleton() {
15954            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15955            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15956        } else {
15957            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15958                editor
15959                    .update(cx, |editor, cx| {
15960                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15961                            editor.unfold_buffer(buffer_id, cx);
15962                        }
15963                    })
15964                    .ok();
15965            });
15966        }
15967    }
15968
15969    pub fn fold_selected_ranges(
15970        &mut self,
15971        _: &FoldSelectedRanges,
15972        window: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) {
15975        let selections = self.selections.all_adjusted(cx);
15976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15977        let ranges = selections
15978            .into_iter()
15979            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15980            .collect::<Vec<_>>();
15981        self.fold_creases(ranges, true, window, cx);
15982    }
15983
15984    pub fn fold_ranges<T: ToOffset + Clone>(
15985        &mut self,
15986        ranges: Vec<Range<T>>,
15987        auto_scroll: bool,
15988        window: &mut Window,
15989        cx: &mut Context<Self>,
15990    ) {
15991        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15992        let ranges = ranges
15993            .into_iter()
15994            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15995            .collect::<Vec<_>>();
15996        self.fold_creases(ranges, auto_scroll, window, cx);
15997    }
15998
15999    pub fn fold_creases<T: ToOffset + Clone>(
16000        &mut self,
16001        creases: Vec<Crease<T>>,
16002        auto_scroll: bool,
16003        _window: &mut Window,
16004        cx: &mut Context<Self>,
16005    ) {
16006        if creases.is_empty() {
16007            return;
16008        }
16009
16010        let mut buffers_affected = HashSet::default();
16011        let multi_buffer = self.buffer().read(cx);
16012        for crease in &creases {
16013            if let Some((_, buffer, _)) =
16014                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16015            {
16016                buffers_affected.insert(buffer.read(cx).remote_id());
16017            };
16018        }
16019
16020        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16021
16022        if auto_scroll {
16023            self.request_autoscroll(Autoscroll::fit(), cx);
16024        }
16025
16026        cx.notify();
16027
16028        self.scrollbar_marker_state.dirty = true;
16029        self.folds_did_change(cx);
16030    }
16031
16032    /// Removes any folds whose ranges intersect any of the given ranges.
16033    pub fn unfold_ranges<T: ToOffset + Clone>(
16034        &mut self,
16035        ranges: &[Range<T>],
16036        inclusive: bool,
16037        auto_scroll: bool,
16038        cx: &mut Context<Self>,
16039    ) {
16040        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16041            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16042        });
16043        self.folds_did_change(cx);
16044    }
16045
16046    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16047        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16048            return;
16049        }
16050        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16051        self.display_map.update(cx, |display_map, cx| {
16052            display_map.fold_buffers([buffer_id], cx)
16053        });
16054        cx.emit(EditorEvent::BufferFoldToggled {
16055            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16056            folded: true,
16057        });
16058        cx.notify();
16059    }
16060
16061    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16062        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16063            return;
16064        }
16065        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16066        self.display_map.update(cx, |display_map, cx| {
16067            display_map.unfold_buffers([buffer_id], cx);
16068        });
16069        cx.emit(EditorEvent::BufferFoldToggled {
16070            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16071            folded: false,
16072        });
16073        cx.notify();
16074    }
16075
16076    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16077        self.display_map.read(cx).is_buffer_folded(buffer)
16078    }
16079
16080    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16081        self.display_map.read(cx).folded_buffers()
16082    }
16083
16084    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16085        self.display_map.update(cx, |display_map, cx| {
16086            display_map.disable_header_for_buffer(buffer_id, cx);
16087        });
16088        cx.notify();
16089    }
16090
16091    /// Removes any folds with the given ranges.
16092    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16093        &mut self,
16094        ranges: &[Range<T>],
16095        type_id: TypeId,
16096        auto_scroll: bool,
16097        cx: &mut Context<Self>,
16098    ) {
16099        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16100            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16101        });
16102        self.folds_did_change(cx);
16103    }
16104
16105    fn remove_folds_with<T: ToOffset + Clone>(
16106        &mut self,
16107        ranges: &[Range<T>],
16108        auto_scroll: bool,
16109        cx: &mut Context<Self>,
16110        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16111    ) {
16112        if ranges.is_empty() {
16113            return;
16114        }
16115
16116        let mut buffers_affected = HashSet::default();
16117        let multi_buffer = self.buffer().read(cx);
16118        for range in ranges {
16119            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16120                buffers_affected.insert(buffer.read(cx).remote_id());
16121            };
16122        }
16123
16124        self.display_map.update(cx, update);
16125
16126        if auto_scroll {
16127            self.request_autoscroll(Autoscroll::fit(), cx);
16128        }
16129
16130        cx.notify();
16131        self.scrollbar_marker_state.dirty = true;
16132        self.active_indent_guides_state.dirty = true;
16133    }
16134
16135    pub fn update_fold_widths(
16136        &mut self,
16137        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16138        cx: &mut Context<Self>,
16139    ) -> bool {
16140        self.display_map
16141            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16142    }
16143
16144    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16145        self.display_map.read(cx).fold_placeholder.clone()
16146    }
16147
16148    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16149        self.buffer.update(cx, |buffer, cx| {
16150            buffer.set_all_diff_hunks_expanded(cx);
16151        });
16152    }
16153
16154    pub fn expand_all_diff_hunks(
16155        &mut self,
16156        _: &ExpandAllDiffHunks,
16157        _window: &mut Window,
16158        cx: &mut Context<Self>,
16159    ) {
16160        self.buffer.update(cx, |buffer, cx| {
16161            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16162        });
16163    }
16164
16165    pub fn toggle_selected_diff_hunks(
16166        &mut self,
16167        _: &ToggleSelectedDiffHunks,
16168        _window: &mut Window,
16169        cx: &mut Context<Self>,
16170    ) {
16171        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16172        self.toggle_diff_hunks_in_ranges(ranges, cx);
16173    }
16174
16175    pub fn diff_hunks_in_ranges<'a>(
16176        &'a self,
16177        ranges: &'a [Range<Anchor>],
16178        buffer: &'a MultiBufferSnapshot,
16179    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16180        ranges.iter().flat_map(move |range| {
16181            let end_excerpt_id = range.end.excerpt_id;
16182            let range = range.to_point(buffer);
16183            let mut peek_end = range.end;
16184            if range.end.row < buffer.max_row().0 {
16185                peek_end = Point::new(range.end.row + 1, 0);
16186            }
16187            buffer
16188                .diff_hunks_in_range(range.start..peek_end)
16189                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16190        })
16191    }
16192
16193    pub fn has_stageable_diff_hunks_in_ranges(
16194        &self,
16195        ranges: &[Range<Anchor>],
16196        snapshot: &MultiBufferSnapshot,
16197    ) -> bool {
16198        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16199        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16200    }
16201
16202    pub fn toggle_staged_selected_diff_hunks(
16203        &mut self,
16204        _: &::git::ToggleStaged,
16205        _: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) {
16208        let snapshot = self.buffer.read(cx).snapshot(cx);
16209        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16210        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16211        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16212    }
16213
16214    pub fn set_render_diff_hunk_controls(
16215        &mut self,
16216        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16217        cx: &mut Context<Self>,
16218    ) {
16219        self.render_diff_hunk_controls = render_diff_hunk_controls;
16220        cx.notify();
16221    }
16222
16223    pub fn stage_and_next(
16224        &mut self,
16225        _: &::git::StageAndNext,
16226        window: &mut Window,
16227        cx: &mut Context<Self>,
16228    ) {
16229        self.do_stage_or_unstage_and_next(true, window, cx);
16230    }
16231
16232    pub fn unstage_and_next(
16233        &mut self,
16234        _: &::git::UnstageAndNext,
16235        window: &mut Window,
16236        cx: &mut Context<Self>,
16237    ) {
16238        self.do_stage_or_unstage_and_next(false, window, cx);
16239    }
16240
16241    pub fn stage_or_unstage_diff_hunks(
16242        &mut self,
16243        stage: bool,
16244        ranges: Vec<Range<Anchor>>,
16245        cx: &mut Context<Self>,
16246    ) {
16247        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16248        cx.spawn(async move |this, cx| {
16249            task.await?;
16250            this.update(cx, |this, cx| {
16251                let snapshot = this.buffer.read(cx).snapshot(cx);
16252                let chunk_by = this
16253                    .diff_hunks_in_ranges(&ranges, &snapshot)
16254                    .chunk_by(|hunk| hunk.buffer_id);
16255                for (buffer_id, hunks) in &chunk_by {
16256                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16257                }
16258            })
16259        })
16260        .detach_and_log_err(cx);
16261    }
16262
16263    fn save_buffers_for_ranges_if_needed(
16264        &mut self,
16265        ranges: &[Range<Anchor>],
16266        cx: &mut Context<Editor>,
16267    ) -> Task<Result<()>> {
16268        let multibuffer = self.buffer.read(cx);
16269        let snapshot = multibuffer.read(cx);
16270        let buffer_ids: HashSet<_> = ranges
16271            .iter()
16272            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16273            .collect();
16274        drop(snapshot);
16275
16276        let mut buffers = HashSet::default();
16277        for buffer_id in buffer_ids {
16278            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16279                let buffer = buffer_entity.read(cx);
16280                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16281                {
16282                    buffers.insert(buffer_entity);
16283                }
16284            }
16285        }
16286
16287        if let Some(project) = &self.project {
16288            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16289        } else {
16290            Task::ready(Ok(()))
16291        }
16292    }
16293
16294    fn do_stage_or_unstage_and_next(
16295        &mut self,
16296        stage: bool,
16297        window: &mut Window,
16298        cx: &mut Context<Self>,
16299    ) {
16300        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16301
16302        if ranges.iter().any(|range| range.start != range.end) {
16303            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16304            return;
16305        }
16306
16307        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16308        let snapshot = self.snapshot(window, cx);
16309        let position = self.selections.newest::<Point>(cx).head();
16310        let mut row = snapshot
16311            .buffer_snapshot
16312            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16313            .find(|hunk| hunk.row_range.start.0 > position.row)
16314            .map(|hunk| hunk.row_range.start);
16315
16316        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16317        // Outside of the project diff editor, wrap around to the beginning.
16318        if !all_diff_hunks_expanded {
16319            row = row.or_else(|| {
16320                snapshot
16321                    .buffer_snapshot
16322                    .diff_hunks_in_range(Point::zero()..position)
16323                    .find(|hunk| hunk.row_range.end.0 < position.row)
16324                    .map(|hunk| hunk.row_range.start)
16325            });
16326        }
16327
16328        if let Some(row) = row {
16329            let destination = Point::new(row.0, 0);
16330            let autoscroll = Autoscroll::center();
16331
16332            self.unfold_ranges(&[destination..destination], false, false, cx);
16333            self.change_selections(Some(autoscroll), window, cx, |s| {
16334                s.select_ranges([destination..destination]);
16335            });
16336        }
16337    }
16338
16339    fn do_stage_or_unstage(
16340        &self,
16341        stage: bool,
16342        buffer_id: BufferId,
16343        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16344        cx: &mut App,
16345    ) -> Option<()> {
16346        let project = self.project.as_ref()?;
16347        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16348        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16349        let buffer_snapshot = buffer.read(cx).snapshot();
16350        let file_exists = buffer_snapshot
16351            .file()
16352            .is_some_and(|file| file.disk_state().exists());
16353        diff.update(cx, |diff, cx| {
16354            diff.stage_or_unstage_hunks(
16355                stage,
16356                &hunks
16357                    .map(|hunk| buffer_diff::DiffHunk {
16358                        buffer_range: hunk.buffer_range,
16359                        diff_base_byte_range: hunk.diff_base_byte_range,
16360                        secondary_status: hunk.secondary_status,
16361                        range: Point::zero()..Point::zero(), // unused
16362                    })
16363                    .collect::<Vec<_>>(),
16364                &buffer_snapshot,
16365                file_exists,
16366                cx,
16367            )
16368        });
16369        None
16370    }
16371
16372    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16373        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16374        self.buffer
16375            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16376    }
16377
16378    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16379        self.buffer.update(cx, |buffer, cx| {
16380            let ranges = vec![Anchor::min()..Anchor::max()];
16381            if !buffer.all_diff_hunks_expanded()
16382                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16383            {
16384                buffer.collapse_diff_hunks(ranges, cx);
16385                true
16386            } else {
16387                false
16388            }
16389        })
16390    }
16391
16392    fn toggle_diff_hunks_in_ranges(
16393        &mut self,
16394        ranges: Vec<Range<Anchor>>,
16395        cx: &mut Context<Editor>,
16396    ) {
16397        self.buffer.update(cx, |buffer, cx| {
16398            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16399            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16400        })
16401    }
16402
16403    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16404        self.buffer.update(cx, |buffer, cx| {
16405            let snapshot = buffer.snapshot(cx);
16406            let excerpt_id = range.end.excerpt_id;
16407            let point_range = range.to_point(&snapshot);
16408            let expand = !buffer.single_hunk_is_expanded(range, cx);
16409            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16410        })
16411    }
16412
16413    pub(crate) fn apply_all_diff_hunks(
16414        &mut self,
16415        _: &ApplyAllDiffHunks,
16416        window: &mut Window,
16417        cx: &mut Context<Self>,
16418    ) {
16419        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16420
16421        let buffers = self.buffer.read(cx).all_buffers();
16422        for branch_buffer in buffers {
16423            branch_buffer.update(cx, |branch_buffer, cx| {
16424                branch_buffer.merge_into_base(Vec::new(), cx);
16425            });
16426        }
16427
16428        if let Some(project) = self.project.clone() {
16429            self.save(true, project, window, cx).detach_and_log_err(cx);
16430        }
16431    }
16432
16433    pub(crate) fn apply_selected_diff_hunks(
16434        &mut self,
16435        _: &ApplyDiffHunk,
16436        window: &mut Window,
16437        cx: &mut Context<Self>,
16438    ) {
16439        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16440        let snapshot = self.snapshot(window, cx);
16441        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16442        let mut ranges_by_buffer = HashMap::default();
16443        self.transact(window, cx, |editor, _window, cx| {
16444            for hunk in hunks {
16445                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16446                    ranges_by_buffer
16447                        .entry(buffer.clone())
16448                        .or_insert_with(Vec::new)
16449                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16450                }
16451            }
16452
16453            for (buffer, ranges) in ranges_by_buffer {
16454                buffer.update(cx, |buffer, cx| {
16455                    buffer.merge_into_base(ranges, cx);
16456                });
16457            }
16458        });
16459
16460        if let Some(project) = self.project.clone() {
16461            self.save(true, project, window, cx).detach_and_log_err(cx);
16462        }
16463    }
16464
16465    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16466        if hovered != self.gutter_hovered {
16467            self.gutter_hovered = hovered;
16468            cx.notify();
16469        }
16470    }
16471
16472    pub fn insert_blocks(
16473        &mut self,
16474        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16475        autoscroll: Option<Autoscroll>,
16476        cx: &mut Context<Self>,
16477    ) -> Vec<CustomBlockId> {
16478        let blocks = self
16479            .display_map
16480            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16481        if let Some(autoscroll) = autoscroll {
16482            self.request_autoscroll(autoscroll, cx);
16483        }
16484        cx.notify();
16485        blocks
16486    }
16487
16488    pub fn resize_blocks(
16489        &mut self,
16490        heights: HashMap<CustomBlockId, u32>,
16491        autoscroll: Option<Autoscroll>,
16492        cx: &mut Context<Self>,
16493    ) {
16494        self.display_map
16495            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16496        if let Some(autoscroll) = autoscroll {
16497            self.request_autoscroll(autoscroll, cx);
16498        }
16499        cx.notify();
16500    }
16501
16502    pub fn replace_blocks(
16503        &mut self,
16504        renderers: HashMap<CustomBlockId, RenderBlock>,
16505        autoscroll: Option<Autoscroll>,
16506        cx: &mut Context<Self>,
16507    ) {
16508        self.display_map
16509            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16510        if let Some(autoscroll) = autoscroll {
16511            self.request_autoscroll(autoscroll, cx);
16512        }
16513        cx.notify();
16514    }
16515
16516    pub fn remove_blocks(
16517        &mut self,
16518        block_ids: HashSet<CustomBlockId>,
16519        autoscroll: Option<Autoscroll>,
16520        cx: &mut Context<Self>,
16521    ) {
16522        self.display_map.update(cx, |display_map, cx| {
16523            display_map.remove_blocks(block_ids, cx)
16524        });
16525        if let Some(autoscroll) = autoscroll {
16526            self.request_autoscroll(autoscroll, cx);
16527        }
16528        cx.notify();
16529    }
16530
16531    pub fn row_for_block(
16532        &self,
16533        block_id: CustomBlockId,
16534        cx: &mut Context<Self>,
16535    ) -> Option<DisplayRow> {
16536        self.display_map
16537            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16538    }
16539
16540    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16541        self.focused_block = Some(focused_block);
16542    }
16543
16544    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16545        self.focused_block.take()
16546    }
16547
16548    pub fn insert_creases(
16549        &mut self,
16550        creases: impl IntoIterator<Item = Crease<Anchor>>,
16551        cx: &mut Context<Self>,
16552    ) -> Vec<CreaseId> {
16553        self.display_map
16554            .update(cx, |map, cx| map.insert_creases(creases, cx))
16555    }
16556
16557    pub fn remove_creases(
16558        &mut self,
16559        ids: impl IntoIterator<Item = CreaseId>,
16560        cx: &mut Context<Self>,
16561    ) -> Vec<(CreaseId, Range<Anchor>)> {
16562        self.display_map
16563            .update(cx, |map, cx| map.remove_creases(ids, cx))
16564    }
16565
16566    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16567        self.display_map
16568            .update(cx, |map, cx| map.snapshot(cx))
16569            .longest_row()
16570    }
16571
16572    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16573        self.display_map
16574            .update(cx, |map, cx| map.snapshot(cx))
16575            .max_point()
16576    }
16577
16578    pub fn text(&self, cx: &App) -> String {
16579        self.buffer.read(cx).read(cx).text()
16580    }
16581
16582    pub fn is_empty(&self, cx: &App) -> bool {
16583        self.buffer.read(cx).read(cx).is_empty()
16584    }
16585
16586    pub fn text_option(&self, cx: &App) -> Option<String> {
16587        let text = self.text(cx);
16588        let text = text.trim();
16589
16590        if text.is_empty() {
16591            return None;
16592        }
16593
16594        Some(text.to_string())
16595    }
16596
16597    pub fn set_text(
16598        &mut self,
16599        text: impl Into<Arc<str>>,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        self.transact(window, cx, |this, _, cx| {
16604            this.buffer
16605                .read(cx)
16606                .as_singleton()
16607                .expect("you can only call set_text on editors for singleton buffers")
16608                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16609        });
16610    }
16611
16612    pub fn display_text(&self, cx: &mut App) -> String {
16613        self.display_map
16614            .update(cx, |map, cx| map.snapshot(cx))
16615            .text()
16616    }
16617
16618    fn create_minimap(
16619        &self,
16620        minimap_settings: MinimapSettings,
16621        window: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) -> Option<Entity<Self>> {
16624        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16625            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16626    }
16627
16628    fn initialize_new_minimap(
16629        &self,
16630        minimap_settings: MinimapSettings,
16631        window: &mut Window,
16632        cx: &mut Context<Self>,
16633    ) -> Entity<Self> {
16634        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16635
16636        let mut minimap = Editor::new_internal(
16637            EditorMode::Minimap {
16638                parent: cx.weak_entity(),
16639            },
16640            self.buffer.clone(),
16641            self.project.clone(),
16642            Some(self.display_map.clone()),
16643            window,
16644            cx,
16645        );
16646        minimap.scroll_manager.clone_state(&self.scroll_manager);
16647        minimap.set_text_style_refinement(TextStyleRefinement {
16648            font_size: Some(MINIMAP_FONT_SIZE),
16649            font_weight: Some(MINIMAP_FONT_WEIGHT),
16650            ..Default::default()
16651        });
16652        minimap.update_minimap_configuration(minimap_settings, cx);
16653        cx.new(|_| minimap)
16654    }
16655
16656    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16657        let current_line_highlight = minimap_settings
16658            .current_line_highlight
16659            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16660        self.set_current_line_highlight(Some(current_line_highlight));
16661    }
16662
16663    pub fn minimap(&self) -> Option<&Entity<Self>> {
16664        self.minimap
16665            .as_ref()
16666            .filter(|_| self.minimap_visibility.visible())
16667    }
16668
16669    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16670        let mut wrap_guides = smallvec::smallvec![];
16671
16672        if self.show_wrap_guides == Some(false) {
16673            return wrap_guides;
16674        }
16675
16676        let settings = self.buffer.read(cx).language_settings(cx);
16677        if settings.show_wrap_guides {
16678            match self.soft_wrap_mode(cx) {
16679                SoftWrap::Column(soft_wrap) => {
16680                    wrap_guides.push((soft_wrap as usize, true));
16681                }
16682                SoftWrap::Bounded(soft_wrap) => {
16683                    wrap_guides.push((soft_wrap as usize, true));
16684                }
16685                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16686            }
16687            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16688        }
16689
16690        wrap_guides
16691    }
16692
16693    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16694        let settings = self.buffer.read(cx).language_settings(cx);
16695        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16696        match mode {
16697            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16698                SoftWrap::None
16699            }
16700            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16701            language_settings::SoftWrap::PreferredLineLength => {
16702                SoftWrap::Column(settings.preferred_line_length)
16703            }
16704            language_settings::SoftWrap::Bounded => {
16705                SoftWrap::Bounded(settings.preferred_line_length)
16706            }
16707        }
16708    }
16709
16710    pub fn set_soft_wrap_mode(
16711        &mut self,
16712        mode: language_settings::SoftWrap,
16713
16714        cx: &mut Context<Self>,
16715    ) {
16716        self.soft_wrap_mode_override = Some(mode);
16717        cx.notify();
16718    }
16719
16720    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16721        self.hard_wrap = hard_wrap;
16722        cx.notify();
16723    }
16724
16725    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16726        self.text_style_refinement = Some(style);
16727    }
16728
16729    /// called by the Element so we know what style we were most recently rendered with.
16730    pub(crate) fn set_style(
16731        &mut self,
16732        style: EditorStyle,
16733        window: &mut Window,
16734        cx: &mut Context<Self>,
16735    ) {
16736        // We intentionally do not inform the display map about the minimap style
16737        // so that wrapping is not recalculated and stays consistent for the editor
16738        // and its linked minimap.
16739        if !self.mode.is_minimap() {
16740            let rem_size = window.rem_size();
16741            self.display_map.update(cx, |map, cx| {
16742                map.set_font(
16743                    style.text.font(),
16744                    style.text.font_size.to_pixels(rem_size),
16745                    cx,
16746                )
16747            });
16748        }
16749        self.style = Some(style);
16750    }
16751
16752    pub fn style(&self) -> Option<&EditorStyle> {
16753        self.style.as_ref()
16754    }
16755
16756    // Called by the element. This method is not designed to be called outside of the editor
16757    // element's layout code because it does not notify when rewrapping is computed synchronously.
16758    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16759        self.display_map
16760            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16761    }
16762
16763    pub fn set_soft_wrap(&mut self) {
16764        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16765    }
16766
16767    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16768        if self.soft_wrap_mode_override.is_some() {
16769            self.soft_wrap_mode_override.take();
16770        } else {
16771            let soft_wrap = match self.soft_wrap_mode(cx) {
16772                SoftWrap::GitDiff => return,
16773                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16774                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16775                    language_settings::SoftWrap::None
16776                }
16777            };
16778            self.soft_wrap_mode_override = Some(soft_wrap);
16779        }
16780        cx.notify();
16781    }
16782
16783    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16784        let Some(workspace) = self.workspace() else {
16785            return;
16786        };
16787        let fs = workspace.read(cx).app_state().fs.clone();
16788        let current_show = TabBarSettings::get_global(cx).show;
16789        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16790            setting.show = Some(!current_show);
16791        });
16792    }
16793
16794    pub fn toggle_indent_guides(
16795        &mut self,
16796        _: &ToggleIndentGuides,
16797        _: &mut Window,
16798        cx: &mut Context<Self>,
16799    ) {
16800        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16801            self.buffer
16802                .read(cx)
16803                .language_settings(cx)
16804                .indent_guides
16805                .enabled
16806        });
16807        self.show_indent_guides = Some(!currently_enabled);
16808        cx.notify();
16809    }
16810
16811    fn should_show_indent_guides(&self) -> Option<bool> {
16812        self.show_indent_guides
16813    }
16814
16815    pub fn toggle_line_numbers(
16816        &mut self,
16817        _: &ToggleLineNumbers,
16818        _: &mut Window,
16819        cx: &mut Context<Self>,
16820    ) {
16821        let mut editor_settings = EditorSettings::get_global(cx).clone();
16822        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16823        EditorSettings::override_global(editor_settings, cx);
16824    }
16825
16826    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16827        if let Some(show_line_numbers) = self.show_line_numbers {
16828            return show_line_numbers;
16829        }
16830        EditorSettings::get_global(cx).gutter.line_numbers
16831    }
16832
16833    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16834        self.use_relative_line_numbers
16835            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16836    }
16837
16838    pub fn toggle_relative_line_numbers(
16839        &mut self,
16840        _: &ToggleRelativeLineNumbers,
16841        _: &mut Window,
16842        cx: &mut Context<Self>,
16843    ) {
16844        let is_relative = self.should_use_relative_line_numbers(cx);
16845        self.set_relative_line_number(Some(!is_relative), cx)
16846    }
16847
16848    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16849        self.use_relative_line_numbers = is_relative;
16850        cx.notify();
16851    }
16852
16853    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16854        self.show_gutter = show_gutter;
16855        cx.notify();
16856    }
16857
16858    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16859        self.show_scrollbars = show_scrollbars;
16860        cx.notify();
16861    }
16862
16863    pub fn set_minimap_visibility(
16864        &mut self,
16865        minimap_visibility: MinimapVisibility,
16866        window: &mut Window,
16867        cx: &mut Context<Self>,
16868    ) {
16869        if self.minimap_visibility != minimap_visibility {
16870            if minimap_visibility.visible() && self.minimap.is_none() {
16871                let minimap_settings = EditorSettings::get_global(cx).minimap;
16872                self.minimap =
16873                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16874            }
16875            self.minimap_visibility = minimap_visibility;
16876            cx.notify();
16877        }
16878    }
16879
16880    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16881        self.set_show_scrollbars(false, cx);
16882        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16883    }
16884
16885    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16886        self.show_line_numbers = Some(show_line_numbers);
16887        cx.notify();
16888    }
16889
16890    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16891        self.disable_expand_excerpt_buttons = true;
16892        cx.notify();
16893    }
16894
16895    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16896        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16897        cx.notify();
16898    }
16899
16900    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16901        self.show_code_actions = Some(show_code_actions);
16902        cx.notify();
16903    }
16904
16905    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16906        self.show_runnables = Some(show_runnables);
16907        cx.notify();
16908    }
16909
16910    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16911        self.show_breakpoints = Some(show_breakpoints);
16912        cx.notify();
16913    }
16914
16915    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16916        if self.display_map.read(cx).masked != masked {
16917            self.display_map.update(cx, |map, _| map.masked = masked);
16918        }
16919        cx.notify()
16920    }
16921
16922    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16923        self.show_wrap_guides = Some(show_wrap_guides);
16924        cx.notify();
16925    }
16926
16927    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16928        self.show_indent_guides = Some(show_indent_guides);
16929        cx.notify();
16930    }
16931
16932    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16933        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16934            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16935                if let Some(dir) = file.abs_path(cx).parent() {
16936                    return Some(dir.to_owned());
16937                }
16938            }
16939
16940            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16941                return Some(project_path.path.to_path_buf());
16942            }
16943        }
16944
16945        None
16946    }
16947
16948    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16949        self.active_excerpt(cx)?
16950            .1
16951            .read(cx)
16952            .file()
16953            .and_then(|f| f.as_local())
16954    }
16955
16956    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16957        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16958            let buffer = buffer.read(cx);
16959            if let Some(project_path) = buffer.project_path(cx) {
16960                let project = self.project.as_ref()?.read(cx);
16961                project.absolute_path(&project_path, cx)
16962            } else {
16963                buffer
16964                    .file()
16965                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16966            }
16967        })
16968    }
16969
16970    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16971        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16972            let project_path = buffer.read(cx).project_path(cx)?;
16973            let project = self.project.as_ref()?.read(cx);
16974            let entry = project.entry_for_path(&project_path, cx)?;
16975            let path = entry.path.to_path_buf();
16976            Some(path)
16977        })
16978    }
16979
16980    pub fn reveal_in_finder(
16981        &mut self,
16982        _: &RevealInFileManager,
16983        _window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) {
16986        if let Some(target) = self.target_file(cx) {
16987            cx.reveal_path(&target.abs_path(cx));
16988        }
16989    }
16990
16991    pub fn copy_path(
16992        &mut self,
16993        _: &zed_actions::workspace::CopyPath,
16994        _window: &mut Window,
16995        cx: &mut Context<Self>,
16996    ) {
16997        if let Some(path) = self.target_file_abs_path(cx) {
16998            if let Some(path) = path.to_str() {
16999                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17000            }
17001        }
17002    }
17003
17004    pub fn copy_relative_path(
17005        &mut self,
17006        _: &zed_actions::workspace::CopyRelativePath,
17007        _window: &mut Window,
17008        cx: &mut Context<Self>,
17009    ) {
17010        if let Some(path) = self.target_file_path(cx) {
17011            if let Some(path) = path.to_str() {
17012                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17013            }
17014        }
17015    }
17016
17017    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17018        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17019            buffer.read(cx).project_path(cx)
17020        } else {
17021            None
17022        }
17023    }
17024
17025    // Returns true if the editor handled a go-to-line request
17026    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17027        maybe!({
17028            let breakpoint_store = self.breakpoint_store.as_ref()?;
17029
17030            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17031            else {
17032                self.clear_row_highlights::<ActiveDebugLine>();
17033                return None;
17034            };
17035
17036            let position = active_stack_frame.position;
17037            let buffer_id = position.buffer_id?;
17038            let snapshot = self
17039                .project
17040                .as_ref()?
17041                .read(cx)
17042                .buffer_for_id(buffer_id, cx)?
17043                .read(cx)
17044                .snapshot();
17045
17046            let mut handled = false;
17047            for (id, ExcerptRange { context, .. }) in
17048                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17049            {
17050                if context.start.cmp(&position, &snapshot).is_ge()
17051                    || context.end.cmp(&position, &snapshot).is_lt()
17052                {
17053                    continue;
17054                }
17055                let snapshot = self.buffer.read(cx).snapshot(cx);
17056                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17057
17058                handled = true;
17059                self.clear_row_highlights::<ActiveDebugLine>();
17060
17061                self.go_to_line::<ActiveDebugLine>(
17062                    multibuffer_anchor,
17063                    Some(cx.theme().colors().editor_debugger_active_line_background),
17064                    window,
17065                    cx,
17066                );
17067
17068                cx.notify();
17069            }
17070
17071            handled.then_some(())
17072        })
17073        .is_some()
17074    }
17075
17076    pub fn copy_file_name_without_extension(
17077        &mut self,
17078        _: &CopyFileNameWithoutExtension,
17079        _: &mut Window,
17080        cx: &mut Context<Self>,
17081    ) {
17082        if let Some(file) = self.target_file(cx) {
17083            if let Some(file_stem) = file.path().file_stem() {
17084                if let Some(name) = file_stem.to_str() {
17085                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17086                }
17087            }
17088        }
17089    }
17090
17091    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17092        if let Some(file) = self.target_file(cx) {
17093            if let Some(file_name) = file.path().file_name() {
17094                if let Some(name) = file_name.to_str() {
17095                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17096                }
17097            }
17098        }
17099    }
17100
17101    pub fn toggle_git_blame(
17102        &mut self,
17103        _: &::git::Blame,
17104        window: &mut Window,
17105        cx: &mut Context<Self>,
17106    ) {
17107        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17108
17109        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17110            self.start_git_blame(true, window, cx);
17111        }
17112
17113        cx.notify();
17114    }
17115
17116    pub fn toggle_git_blame_inline(
17117        &mut self,
17118        _: &ToggleGitBlameInline,
17119        window: &mut Window,
17120        cx: &mut Context<Self>,
17121    ) {
17122        self.toggle_git_blame_inline_internal(true, window, cx);
17123        cx.notify();
17124    }
17125
17126    pub fn open_git_blame_commit(
17127        &mut self,
17128        _: &OpenGitBlameCommit,
17129        window: &mut Window,
17130        cx: &mut Context<Self>,
17131    ) {
17132        self.open_git_blame_commit_internal(window, cx);
17133    }
17134
17135    fn open_git_blame_commit_internal(
17136        &mut self,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) -> Option<()> {
17140        let blame = self.blame.as_ref()?;
17141        let snapshot = self.snapshot(window, cx);
17142        let cursor = self.selections.newest::<Point>(cx).head();
17143        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17144        let blame_entry = blame
17145            .update(cx, |blame, cx| {
17146                blame
17147                    .blame_for_rows(
17148                        &[RowInfo {
17149                            buffer_id: Some(buffer.remote_id()),
17150                            buffer_row: Some(point.row),
17151                            ..Default::default()
17152                        }],
17153                        cx,
17154                    )
17155                    .next()
17156            })
17157            .flatten()?;
17158        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17159        let repo = blame.read(cx).repository(cx)?;
17160        let workspace = self.workspace()?.downgrade();
17161        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17162        None
17163    }
17164
17165    pub fn git_blame_inline_enabled(&self) -> bool {
17166        self.git_blame_inline_enabled
17167    }
17168
17169    pub fn toggle_selection_menu(
17170        &mut self,
17171        _: &ToggleSelectionMenu,
17172        _: &mut Window,
17173        cx: &mut Context<Self>,
17174    ) {
17175        self.show_selection_menu = self
17176            .show_selection_menu
17177            .map(|show_selections_menu| !show_selections_menu)
17178            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17179
17180        cx.notify();
17181    }
17182
17183    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17184        self.show_selection_menu
17185            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17186    }
17187
17188    fn start_git_blame(
17189        &mut self,
17190        user_triggered: bool,
17191        window: &mut Window,
17192        cx: &mut Context<Self>,
17193    ) {
17194        if let Some(project) = self.project.as_ref() {
17195            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17196                return;
17197            };
17198
17199            if buffer.read(cx).file().is_none() {
17200                return;
17201            }
17202
17203            let focused = self.focus_handle(cx).contains_focused(window, cx);
17204
17205            let project = project.clone();
17206            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17207            self.blame_subscription =
17208                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17209            self.blame = Some(blame);
17210        }
17211    }
17212
17213    fn toggle_git_blame_inline_internal(
17214        &mut self,
17215        user_triggered: bool,
17216        window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) {
17219        if self.git_blame_inline_enabled {
17220            self.git_blame_inline_enabled = false;
17221            self.show_git_blame_inline = false;
17222            self.show_git_blame_inline_delay_task.take();
17223        } else {
17224            self.git_blame_inline_enabled = true;
17225            self.start_git_blame_inline(user_triggered, window, cx);
17226        }
17227
17228        cx.notify();
17229    }
17230
17231    fn start_git_blame_inline(
17232        &mut self,
17233        user_triggered: bool,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) {
17237        self.start_git_blame(user_triggered, window, cx);
17238
17239        if ProjectSettings::get_global(cx)
17240            .git
17241            .inline_blame_delay()
17242            .is_some()
17243        {
17244            self.start_inline_blame_timer(window, cx);
17245        } else {
17246            self.show_git_blame_inline = true
17247        }
17248    }
17249
17250    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17251        self.blame.as_ref()
17252    }
17253
17254    pub fn show_git_blame_gutter(&self) -> bool {
17255        self.show_git_blame_gutter
17256    }
17257
17258    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17259        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17260    }
17261
17262    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17263        self.show_git_blame_inline
17264            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17265            && !self.newest_selection_head_on_empty_line(cx)
17266            && self.has_blame_entries(cx)
17267    }
17268
17269    fn has_blame_entries(&self, cx: &App) -> bool {
17270        self.blame()
17271            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17272    }
17273
17274    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17275        let cursor_anchor = self.selections.newest_anchor().head();
17276
17277        let snapshot = self.buffer.read(cx).snapshot(cx);
17278        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17279
17280        snapshot.line_len(buffer_row) == 0
17281    }
17282
17283    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17284        let buffer_and_selection = maybe!({
17285            let selection = self.selections.newest::<Point>(cx);
17286            let selection_range = selection.range();
17287
17288            let multi_buffer = self.buffer().read(cx);
17289            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17290            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17291
17292            let (buffer, range, _) = if selection.reversed {
17293                buffer_ranges.first()
17294            } else {
17295                buffer_ranges.last()
17296            }?;
17297
17298            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17299                ..text::ToPoint::to_point(&range.end, &buffer).row;
17300            Some((
17301                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17302                selection,
17303            ))
17304        });
17305
17306        let Some((buffer, selection)) = buffer_and_selection else {
17307            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17308        };
17309
17310        let Some(project) = self.project.as_ref() else {
17311            return Task::ready(Err(anyhow!("editor does not have project")));
17312        };
17313
17314        project.update(cx, |project, cx| {
17315            project.get_permalink_to_line(&buffer, selection, cx)
17316        })
17317    }
17318
17319    pub fn copy_permalink_to_line(
17320        &mut self,
17321        _: &CopyPermalinkToLine,
17322        window: &mut Window,
17323        cx: &mut Context<Self>,
17324    ) {
17325        let permalink_task = self.get_permalink_to_line(cx);
17326        let workspace = self.workspace();
17327
17328        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17329            Ok(permalink) => {
17330                cx.update(|_, cx| {
17331                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17332                })
17333                .ok();
17334            }
17335            Err(err) => {
17336                let message = format!("Failed to copy permalink: {err}");
17337
17338                anyhow::Result::<()>::Err(err).log_err();
17339
17340                if let Some(workspace) = workspace {
17341                    workspace
17342                        .update_in(cx, |workspace, _, cx| {
17343                            struct CopyPermalinkToLine;
17344
17345                            workspace.show_toast(
17346                                Toast::new(
17347                                    NotificationId::unique::<CopyPermalinkToLine>(),
17348                                    message,
17349                                ),
17350                                cx,
17351                            )
17352                        })
17353                        .ok();
17354                }
17355            }
17356        })
17357        .detach();
17358    }
17359
17360    pub fn copy_file_location(
17361        &mut self,
17362        _: &CopyFileLocation,
17363        _: &mut Window,
17364        cx: &mut Context<Self>,
17365    ) {
17366        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17367        if let Some(file) = self.target_file(cx) {
17368            if let Some(path) = file.path().to_str() {
17369                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17370            }
17371        }
17372    }
17373
17374    pub fn open_permalink_to_line(
17375        &mut self,
17376        _: &OpenPermalinkToLine,
17377        window: &mut Window,
17378        cx: &mut Context<Self>,
17379    ) {
17380        let permalink_task = self.get_permalink_to_line(cx);
17381        let workspace = self.workspace();
17382
17383        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17384            Ok(permalink) => {
17385                cx.update(|_, cx| {
17386                    cx.open_url(permalink.as_ref());
17387                })
17388                .ok();
17389            }
17390            Err(err) => {
17391                let message = format!("Failed to open permalink: {err}");
17392
17393                anyhow::Result::<()>::Err(err).log_err();
17394
17395                if let Some(workspace) = workspace {
17396                    workspace
17397                        .update(cx, |workspace, cx| {
17398                            struct OpenPermalinkToLine;
17399
17400                            workspace.show_toast(
17401                                Toast::new(
17402                                    NotificationId::unique::<OpenPermalinkToLine>(),
17403                                    message,
17404                                ),
17405                                cx,
17406                            )
17407                        })
17408                        .ok();
17409                }
17410            }
17411        })
17412        .detach();
17413    }
17414
17415    pub fn insert_uuid_v4(
17416        &mut self,
17417        _: &InsertUuidV4,
17418        window: &mut Window,
17419        cx: &mut Context<Self>,
17420    ) {
17421        self.insert_uuid(UuidVersion::V4, window, cx);
17422    }
17423
17424    pub fn insert_uuid_v7(
17425        &mut self,
17426        _: &InsertUuidV7,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        self.insert_uuid(UuidVersion::V7, window, cx);
17431    }
17432
17433    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17434        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17435        self.transact(window, cx, |this, window, cx| {
17436            let edits = this
17437                .selections
17438                .all::<Point>(cx)
17439                .into_iter()
17440                .map(|selection| {
17441                    let uuid = match version {
17442                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17443                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17444                    };
17445
17446                    (selection.range(), uuid.to_string())
17447                });
17448            this.edit(edits, cx);
17449            this.refresh_inline_completion(true, false, window, cx);
17450        });
17451    }
17452
17453    pub fn open_selections_in_multibuffer(
17454        &mut self,
17455        _: &OpenSelectionsInMultibuffer,
17456        window: &mut Window,
17457        cx: &mut Context<Self>,
17458    ) {
17459        let multibuffer = self.buffer.read(cx);
17460
17461        let Some(buffer) = multibuffer.as_singleton() else {
17462            return;
17463        };
17464
17465        let Some(workspace) = self.workspace() else {
17466            return;
17467        };
17468
17469        let locations = self
17470            .selections
17471            .disjoint_anchors()
17472            .iter()
17473            .map(|range| Location {
17474                buffer: buffer.clone(),
17475                range: range.start.text_anchor..range.end.text_anchor,
17476            })
17477            .collect::<Vec<_>>();
17478
17479        let title = multibuffer.title(cx).to_string();
17480
17481        cx.spawn_in(window, async move |_, cx| {
17482            workspace.update_in(cx, |workspace, window, cx| {
17483                Self::open_locations_in_multibuffer(
17484                    workspace,
17485                    locations,
17486                    format!("Selections for '{title}'"),
17487                    false,
17488                    MultibufferSelectionMode::All,
17489                    window,
17490                    cx,
17491                );
17492            })
17493        })
17494        .detach();
17495    }
17496
17497    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17498    /// last highlight added will be used.
17499    ///
17500    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17501    pub fn highlight_rows<T: 'static>(
17502        &mut self,
17503        range: Range<Anchor>,
17504        color: Hsla,
17505        options: RowHighlightOptions,
17506        cx: &mut Context<Self>,
17507    ) {
17508        let snapshot = self.buffer().read(cx).snapshot(cx);
17509        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17510        let ix = row_highlights.binary_search_by(|highlight| {
17511            Ordering::Equal
17512                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17513                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17514        });
17515
17516        if let Err(mut ix) = ix {
17517            let index = post_inc(&mut self.highlight_order);
17518
17519            // If this range intersects with the preceding highlight, then merge it with
17520            // the preceding highlight. Otherwise insert a new highlight.
17521            let mut merged = false;
17522            if ix > 0 {
17523                let prev_highlight = &mut row_highlights[ix - 1];
17524                if prev_highlight
17525                    .range
17526                    .end
17527                    .cmp(&range.start, &snapshot)
17528                    .is_ge()
17529                {
17530                    ix -= 1;
17531                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17532                        prev_highlight.range.end = range.end;
17533                    }
17534                    merged = true;
17535                    prev_highlight.index = index;
17536                    prev_highlight.color = color;
17537                    prev_highlight.options = options;
17538                }
17539            }
17540
17541            if !merged {
17542                row_highlights.insert(
17543                    ix,
17544                    RowHighlight {
17545                        range: range.clone(),
17546                        index,
17547                        color,
17548                        options,
17549                        type_id: TypeId::of::<T>(),
17550                    },
17551                );
17552            }
17553
17554            // If any of the following highlights intersect with this one, merge them.
17555            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17556                let highlight = &row_highlights[ix];
17557                if next_highlight
17558                    .range
17559                    .start
17560                    .cmp(&highlight.range.end, &snapshot)
17561                    .is_le()
17562                {
17563                    if next_highlight
17564                        .range
17565                        .end
17566                        .cmp(&highlight.range.end, &snapshot)
17567                        .is_gt()
17568                    {
17569                        row_highlights[ix].range.end = next_highlight.range.end;
17570                    }
17571                    row_highlights.remove(ix + 1);
17572                } else {
17573                    break;
17574                }
17575            }
17576        }
17577    }
17578
17579    /// Remove any highlighted row ranges of the given type that intersect the
17580    /// given ranges.
17581    pub fn remove_highlighted_rows<T: 'static>(
17582        &mut self,
17583        ranges_to_remove: Vec<Range<Anchor>>,
17584        cx: &mut Context<Self>,
17585    ) {
17586        let snapshot = self.buffer().read(cx).snapshot(cx);
17587        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17588        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17589        row_highlights.retain(|highlight| {
17590            while let Some(range_to_remove) = ranges_to_remove.peek() {
17591                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17592                    Ordering::Less | Ordering::Equal => {
17593                        ranges_to_remove.next();
17594                    }
17595                    Ordering::Greater => {
17596                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17597                            Ordering::Less | Ordering::Equal => {
17598                                return false;
17599                            }
17600                            Ordering::Greater => break,
17601                        }
17602                    }
17603                }
17604            }
17605
17606            true
17607        })
17608    }
17609
17610    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17611    pub fn clear_row_highlights<T: 'static>(&mut self) {
17612        self.highlighted_rows.remove(&TypeId::of::<T>());
17613    }
17614
17615    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17616    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17617        self.highlighted_rows
17618            .get(&TypeId::of::<T>())
17619            .map_or(&[] as &[_], |vec| vec.as_slice())
17620            .iter()
17621            .map(|highlight| (highlight.range.clone(), highlight.color))
17622    }
17623
17624    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17625    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17626    /// Allows to ignore certain kinds of highlights.
17627    pub fn highlighted_display_rows(
17628        &self,
17629        window: &mut Window,
17630        cx: &mut App,
17631    ) -> BTreeMap<DisplayRow, LineHighlight> {
17632        let snapshot = self.snapshot(window, cx);
17633        let mut used_highlight_orders = HashMap::default();
17634        self.highlighted_rows
17635            .iter()
17636            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17637            .fold(
17638                BTreeMap::<DisplayRow, LineHighlight>::new(),
17639                |mut unique_rows, highlight| {
17640                    let start = highlight.range.start.to_display_point(&snapshot);
17641                    let end = highlight.range.end.to_display_point(&snapshot);
17642                    let start_row = start.row().0;
17643                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17644                        && end.column() == 0
17645                    {
17646                        end.row().0.saturating_sub(1)
17647                    } else {
17648                        end.row().0
17649                    };
17650                    for row in start_row..=end_row {
17651                        let used_index =
17652                            used_highlight_orders.entry(row).or_insert(highlight.index);
17653                        if highlight.index >= *used_index {
17654                            *used_index = highlight.index;
17655                            unique_rows.insert(
17656                                DisplayRow(row),
17657                                LineHighlight {
17658                                    include_gutter: highlight.options.include_gutter,
17659                                    border: None,
17660                                    background: highlight.color.into(),
17661                                    type_id: Some(highlight.type_id),
17662                                },
17663                            );
17664                        }
17665                    }
17666                    unique_rows
17667                },
17668            )
17669    }
17670
17671    pub fn highlighted_display_row_for_autoscroll(
17672        &self,
17673        snapshot: &DisplaySnapshot,
17674    ) -> Option<DisplayRow> {
17675        self.highlighted_rows
17676            .values()
17677            .flat_map(|highlighted_rows| highlighted_rows.iter())
17678            .filter_map(|highlight| {
17679                if highlight.options.autoscroll {
17680                    Some(highlight.range.start.to_display_point(snapshot).row())
17681                } else {
17682                    None
17683                }
17684            })
17685            .min()
17686    }
17687
17688    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17689        self.highlight_background::<SearchWithinRange>(
17690            ranges,
17691            |colors| colors.editor_document_highlight_read_background,
17692            cx,
17693        )
17694    }
17695
17696    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17697        self.breadcrumb_header = Some(new_header);
17698    }
17699
17700    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17701        self.clear_background_highlights::<SearchWithinRange>(cx);
17702    }
17703
17704    pub fn highlight_background<T: 'static>(
17705        &mut self,
17706        ranges: &[Range<Anchor>],
17707        color_fetcher: fn(&ThemeColors) -> Hsla,
17708        cx: &mut Context<Self>,
17709    ) {
17710        self.background_highlights
17711            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17712        self.scrollbar_marker_state.dirty = true;
17713        cx.notify();
17714    }
17715
17716    pub fn clear_background_highlights<T: 'static>(
17717        &mut self,
17718        cx: &mut Context<Self>,
17719    ) -> Option<BackgroundHighlight> {
17720        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17721        if !text_highlights.1.is_empty() {
17722            self.scrollbar_marker_state.dirty = true;
17723            cx.notify();
17724        }
17725        Some(text_highlights)
17726    }
17727
17728    pub fn highlight_gutter<T: 'static>(
17729        &mut self,
17730        ranges: &[Range<Anchor>],
17731        color_fetcher: fn(&App) -> Hsla,
17732        cx: &mut Context<Self>,
17733    ) {
17734        self.gutter_highlights
17735            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17736        cx.notify();
17737    }
17738
17739    pub fn clear_gutter_highlights<T: 'static>(
17740        &mut self,
17741        cx: &mut Context<Self>,
17742    ) -> Option<GutterHighlight> {
17743        cx.notify();
17744        self.gutter_highlights.remove(&TypeId::of::<T>())
17745    }
17746
17747    #[cfg(feature = "test-support")]
17748    pub fn all_text_background_highlights(
17749        &self,
17750        window: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17753        let snapshot = self.snapshot(window, cx);
17754        let buffer = &snapshot.buffer_snapshot;
17755        let start = buffer.anchor_before(0);
17756        let end = buffer.anchor_after(buffer.len());
17757        let theme = cx.theme().colors();
17758        self.background_highlights_in_range(start..end, &snapshot, theme)
17759    }
17760
17761    #[cfg(feature = "test-support")]
17762    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17763        let snapshot = self.buffer().read(cx).snapshot(cx);
17764
17765        let highlights = self
17766            .background_highlights
17767            .get(&TypeId::of::<items::BufferSearchHighlights>());
17768
17769        if let Some((_color, ranges)) = highlights {
17770            ranges
17771                .iter()
17772                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17773                .collect_vec()
17774        } else {
17775            vec![]
17776        }
17777    }
17778
17779    fn document_highlights_for_position<'a>(
17780        &'a self,
17781        position: Anchor,
17782        buffer: &'a MultiBufferSnapshot,
17783    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17784        let read_highlights = self
17785            .background_highlights
17786            .get(&TypeId::of::<DocumentHighlightRead>())
17787            .map(|h| &h.1);
17788        let write_highlights = self
17789            .background_highlights
17790            .get(&TypeId::of::<DocumentHighlightWrite>())
17791            .map(|h| &h.1);
17792        let left_position = position.bias_left(buffer);
17793        let right_position = position.bias_right(buffer);
17794        read_highlights
17795            .into_iter()
17796            .chain(write_highlights)
17797            .flat_map(move |ranges| {
17798                let start_ix = match ranges.binary_search_by(|probe| {
17799                    let cmp = probe.end.cmp(&left_position, buffer);
17800                    if cmp.is_ge() {
17801                        Ordering::Greater
17802                    } else {
17803                        Ordering::Less
17804                    }
17805                }) {
17806                    Ok(i) | Err(i) => i,
17807                };
17808
17809                ranges[start_ix..]
17810                    .iter()
17811                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17812            })
17813    }
17814
17815    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17816        self.background_highlights
17817            .get(&TypeId::of::<T>())
17818            .map_or(false, |(_, highlights)| !highlights.is_empty())
17819    }
17820
17821    pub fn background_highlights_in_range(
17822        &self,
17823        search_range: Range<Anchor>,
17824        display_snapshot: &DisplaySnapshot,
17825        theme: &ThemeColors,
17826    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17827        let mut results = Vec::new();
17828        for (color_fetcher, ranges) in self.background_highlights.values() {
17829            let color = color_fetcher(theme);
17830            let start_ix = match ranges.binary_search_by(|probe| {
17831                let cmp = probe
17832                    .end
17833                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17834                if cmp.is_gt() {
17835                    Ordering::Greater
17836                } else {
17837                    Ordering::Less
17838                }
17839            }) {
17840                Ok(i) | Err(i) => i,
17841            };
17842            for range in &ranges[start_ix..] {
17843                if range
17844                    .start
17845                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17846                    .is_ge()
17847                {
17848                    break;
17849                }
17850
17851                let start = range.start.to_display_point(display_snapshot);
17852                let end = range.end.to_display_point(display_snapshot);
17853                results.push((start..end, color))
17854            }
17855        }
17856        results
17857    }
17858
17859    pub fn background_highlight_row_ranges<T: 'static>(
17860        &self,
17861        search_range: Range<Anchor>,
17862        display_snapshot: &DisplaySnapshot,
17863        count: usize,
17864    ) -> Vec<RangeInclusive<DisplayPoint>> {
17865        let mut results = Vec::new();
17866        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17867            return vec![];
17868        };
17869
17870        let start_ix = match ranges.binary_search_by(|probe| {
17871            let cmp = probe
17872                .end
17873                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17874            if cmp.is_gt() {
17875                Ordering::Greater
17876            } else {
17877                Ordering::Less
17878            }
17879        }) {
17880            Ok(i) | Err(i) => i,
17881        };
17882        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17883            if let (Some(start_display), Some(end_display)) = (start, end) {
17884                results.push(
17885                    start_display.to_display_point(display_snapshot)
17886                        ..=end_display.to_display_point(display_snapshot),
17887                );
17888            }
17889        };
17890        let mut start_row: Option<Point> = None;
17891        let mut end_row: Option<Point> = None;
17892        if ranges.len() > count {
17893            return Vec::new();
17894        }
17895        for range in &ranges[start_ix..] {
17896            if range
17897                .start
17898                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17899                .is_ge()
17900            {
17901                break;
17902            }
17903            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17904            if let Some(current_row) = &end_row {
17905                if end.row == current_row.row {
17906                    continue;
17907                }
17908            }
17909            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17910            if start_row.is_none() {
17911                assert_eq!(end_row, None);
17912                start_row = Some(start);
17913                end_row = Some(end);
17914                continue;
17915            }
17916            if let Some(current_end) = end_row.as_mut() {
17917                if start.row > current_end.row + 1 {
17918                    push_region(start_row, end_row);
17919                    start_row = Some(start);
17920                    end_row = Some(end);
17921                } else {
17922                    // Merge two hunks.
17923                    *current_end = end;
17924                }
17925            } else {
17926                unreachable!();
17927            }
17928        }
17929        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17930        push_region(start_row, end_row);
17931        results
17932    }
17933
17934    pub fn gutter_highlights_in_range(
17935        &self,
17936        search_range: Range<Anchor>,
17937        display_snapshot: &DisplaySnapshot,
17938        cx: &App,
17939    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17940        let mut results = Vec::new();
17941        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17942            let color = color_fetcher(cx);
17943            let start_ix = match ranges.binary_search_by(|probe| {
17944                let cmp = probe
17945                    .end
17946                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17947                if cmp.is_gt() {
17948                    Ordering::Greater
17949                } else {
17950                    Ordering::Less
17951                }
17952            }) {
17953                Ok(i) | Err(i) => i,
17954            };
17955            for range in &ranges[start_ix..] {
17956                if range
17957                    .start
17958                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17959                    .is_ge()
17960                {
17961                    break;
17962                }
17963
17964                let start = range.start.to_display_point(display_snapshot);
17965                let end = range.end.to_display_point(display_snapshot);
17966                results.push((start..end, color))
17967            }
17968        }
17969        results
17970    }
17971
17972    /// Get the text ranges corresponding to the redaction query
17973    pub fn redacted_ranges(
17974        &self,
17975        search_range: Range<Anchor>,
17976        display_snapshot: &DisplaySnapshot,
17977        cx: &App,
17978    ) -> Vec<Range<DisplayPoint>> {
17979        display_snapshot
17980            .buffer_snapshot
17981            .redacted_ranges(search_range, |file| {
17982                if let Some(file) = file {
17983                    file.is_private()
17984                        && EditorSettings::get(
17985                            Some(SettingsLocation {
17986                                worktree_id: file.worktree_id(cx),
17987                                path: file.path().as_ref(),
17988                            }),
17989                            cx,
17990                        )
17991                        .redact_private_values
17992                } else {
17993                    false
17994                }
17995            })
17996            .map(|range| {
17997                range.start.to_display_point(display_snapshot)
17998                    ..range.end.to_display_point(display_snapshot)
17999            })
18000            .collect()
18001    }
18002
18003    pub fn highlight_text<T: 'static>(
18004        &mut self,
18005        ranges: Vec<Range<Anchor>>,
18006        style: HighlightStyle,
18007        cx: &mut Context<Self>,
18008    ) {
18009        self.display_map.update(cx, |map, _| {
18010            map.highlight_text(TypeId::of::<T>(), ranges, style)
18011        });
18012        cx.notify();
18013    }
18014
18015    pub(crate) fn highlight_inlays<T: 'static>(
18016        &mut self,
18017        highlights: Vec<InlayHighlight>,
18018        style: HighlightStyle,
18019        cx: &mut Context<Self>,
18020    ) {
18021        self.display_map.update(cx, |map, _| {
18022            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18023        });
18024        cx.notify();
18025    }
18026
18027    pub fn text_highlights<'a, T: 'static>(
18028        &'a self,
18029        cx: &'a App,
18030    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18031        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18032    }
18033
18034    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18035        let cleared = self
18036            .display_map
18037            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18038        if cleared {
18039            cx.notify();
18040        }
18041    }
18042
18043    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18044        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18045            && self.focus_handle.is_focused(window)
18046    }
18047
18048    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18049        self.show_cursor_when_unfocused = is_enabled;
18050        cx.notify();
18051    }
18052
18053    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18054        cx.notify();
18055    }
18056
18057    fn on_debug_session_event(
18058        &mut self,
18059        _session: Entity<Session>,
18060        event: &SessionEvent,
18061        cx: &mut Context<Self>,
18062    ) {
18063        match event {
18064            SessionEvent::InvalidateInlineValue => {
18065                self.refresh_inline_values(cx);
18066            }
18067            _ => {}
18068        }
18069    }
18070
18071    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18072        let Some(project) = self.project.clone() else {
18073            return;
18074        };
18075
18076        if !self.inline_value_cache.enabled {
18077            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18078            self.splice_inlays(&inlays, Vec::new(), cx);
18079            return;
18080        }
18081
18082        let current_execution_position = self
18083            .highlighted_rows
18084            .get(&TypeId::of::<ActiveDebugLine>())
18085            .and_then(|lines| lines.last().map(|line| line.range.start));
18086
18087        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18088            let inline_values = editor
18089                .update(cx, |editor, cx| {
18090                    let Some(current_execution_position) = current_execution_position else {
18091                        return Some(Task::ready(Ok(Vec::new())));
18092                    };
18093
18094                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18095                        let snapshot = buffer.snapshot(cx);
18096
18097                        let excerpt = snapshot.excerpt_containing(
18098                            current_execution_position..current_execution_position,
18099                        )?;
18100
18101                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18102                    })?;
18103
18104                    let range =
18105                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18106
18107                    project.inline_values(buffer, range, cx)
18108                })
18109                .ok()
18110                .flatten()?
18111                .await
18112                .context("refreshing debugger inlays")
18113                .log_err()?;
18114
18115            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18116
18117            for (buffer_id, inline_value) in inline_values
18118                .into_iter()
18119                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18120            {
18121                buffer_inline_values
18122                    .entry(buffer_id)
18123                    .or_default()
18124                    .push(inline_value);
18125            }
18126
18127            editor
18128                .update(cx, |editor, cx| {
18129                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18130                    let mut new_inlays = Vec::default();
18131
18132                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18133                        let buffer_id = buffer_snapshot.remote_id();
18134                        buffer_inline_values
18135                            .get(&buffer_id)
18136                            .into_iter()
18137                            .flatten()
18138                            .for_each(|hint| {
18139                                let inlay = Inlay::debugger_hint(
18140                                    post_inc(&mut editor.next_inlay_id),
18141                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18142                                    hint.text(),
18143                                );
18144
18145                                new_inlays.push(inlay);
18146                            });
18147                    }
18148
18149                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18150                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18151
18152                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18153                })
18154                .ok()?;
18155            Some(())
18156        });
18157    }
18158
18159    fn on_buffer_event(
18160        &mut self,
18161        multibuffer: &Entity<MultiBuffer>,
18162        event: &multi_buffer::Event,
18163        window: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) {
18166        match event {
18167            multi_buffer::Event::Edited {
18168                singleton_buffer_edited,
18169                edited_buffer: buffer_edited,
18170            } => {
18171                self.scrollbar_marker_state.dirty = true;
18172                self.active_indent_guides_state.dirty = true;
18173                self.refresh_active_diagnostics(cx);
18174                self.refresh_code_actions(window, cx);
18175                self.refresh_selected_text_highlights(true, window, cx);
18176                refresh_matching_bracket_highlights(self, window, cx);
18177                if self.has_active_inline_completion() {
18178                    self.update_visible_inline_completion(window, cx);
18179                }
18180                if let Some(buffer) = buffer_edited {
18181                    let buffer_id = buffer.read(cx).remote_id();
18182                    if !self.registered_buffers.contains_key(&buffer_id) {
18183                        if let Some(project) = self.project.as_ref() {
18184                            project.update(cx, |project, cx| {
18185                                self.registered_buffers.insert(
18186                                    buffer_id,
18187                                    project.register_buffer_with_language_servers(&buffer, cx),
18188                                );
18189                            })
18190                        }
18191                    }
18192                }
18193                cx.emit(EditorEvent::BufferEdited);
18194                cx.emit(SearchEvent::MatchesInvalidated);
18195                if *singleton_buffer_edited {
18196                    if let Some(project) = &self.project {
18197                        #[allow(clippy::mutable_key_type)]
18198                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18199                            multibuffer
18200                                .all_buffers()
18201                                .into_iter()
18202                                .filter_map(|buffer| {
18203                                    buffer.update(cx, |buffer, cx| {
18204                                        let language = buffer.language()?;
18205                                        let should_discard = project.update(cx, |project, cx| {
18206                                            project.is_local()
18207                                                && !project.has_language_servers_for(buffer, cx)
18208                                        });
18209                                        should_discard.not().then_some(language.clone())
18210                                    })
18211                                })
18212                                .collect::<HashSet<_>>()
18213                        });
18214                        if !languages_affected.is_empty() {
18215                            self.refresh_inlay_hints(
18216                                InlayHintRefreshReason::BufferEdited(languages_affected),
18217                                cx,
18218                            );
18219                        }
18220                    }
18221                }
18222
18223                let Some(project) = &self.project else { return };
18224                let (telemetry, is_via_ssh) = {
18225                    let project = project.read(cx);
18226                    let telemetry = project.client().telemetry().clone();
18227                    let is_via_ssh = project.is_via_ssh();
18228                    (telemetry, is_via_ssh)
18229                };
18230                refresh_linked_ranges(self, window, cx);
18231                telemetry.log_edit_event("editor", is_via_ssh);
18232            }
18233            multi_buffer::Event::ExcerptsAdded {
18234                buffer,
18235                predecessor,
18236                excerpts,
18237            } => {
18238                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18239                let buffer_id = buffer.read(cx).remote_id();
18240                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18241                    if let Some(project) = &self.project {
18242                        update_uncommitted_diff_for_buffer(
18243                            cx.entity(),
18244                            project,
18245                            [buffer.clone()],
18246                            self.buffer.clone(),
18247                            cx,
18248                        )
18249                        .detach();
18250                    }
18251                }
18252                cx.emit(EditorEvent::ExcerptsAdded {
18253                    buffer: buffer.clone(),
18254                    predecessor: *predecessor,
18255                    excerpts: excerpts.clone(),
18256                });
18257                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18258            }
18259            multi_buffer::Event::ExcerptsRemoved {
18260                ids,
18261                removed_buffer_ids,
18262            } => {
18263                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18264                let buffer = self.buffer.read(cx);
18265                self.registered_buffers
18266                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18267                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18268                cx.emit(EditorEvent::ExcerptsRemoved {
18269                    ids: ids.clone(),
18270                    removed_buffer_ids: removed_buffer_ids.clone(),
18271                })
18272            }
18273            multi_buffer::Event::ExcerptsEdited {
18274                excerpt_ids,
18275                buffer_ids,
18276            } => {
18277                self.display_map.update(cx, |map, cx| {
18278                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18279                });
18280                cx.emit(EditorEvent::ExcerptsEdited {
18281                    ids: excerpt_ids.clone(),
18282                })
18283            }
18284            multi_buffer::Event::ExcerptsExpanded { ids } => {
18285                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18286                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18287            }
18288            multi_buffer::Event::Reparsed(buffer_id) => {
18289                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18290                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18291
18292                cx.emit(EditorEvent::Reparsed(*buffer_id));
18293            }
18294            multi_buffer::Event::DiffHunksToggled => {
18295                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18296            }
18297            multi_buffer::Event::LanguageChanged(buffer_id) => {
18298                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18299                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18300                cx.emit(EditorEvent::Reparsed(*buffer_id));
18301                cx.notify();
18302            }
18303            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18304            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18305            multi_buffer::Event::FileHandleChanged
18306            | multi_buffer::Event::Reloaded
18307            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18308            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18309            multi_buffer::Event::DiagnosticsUpdated => {
18310                self.refresh_active_diagnostics(cx);
18311                self.refresh_inline_diagnostics(true, window, cx);
18312                self.scrollbar_marker_state.dirty = true;
18313                cx.notify();
18314            }
18315            _ => {}
18316        };
18317    }
18318
18319    pub fn start_temporary_diff_override(&mut self) {
18320        self.load_diff_task.take();
18321        self.temporary_diff_override = true;
18322    }
18323
18324    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18325        self.temporary_diff_override = false;
18326        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18327        self.buffer.update(cx, |buffer, cx| {
18328            buffer.set_all_diff_hunks_collapsed(cx);
18329        });
18330
18331        if let Some(project) = self.project.clone() {
18332            self.load_diff_task = Some(
18333                update_uncommitted_diff_for_buffer(
18334                    cx.entity(),
18335                    &project,
18336                    self.buffer.read(cx).all_buffers(),
18337                    self.buffer.clone(),
18338                    cx,
18339                )
18340                .shared(),
18341            );
18342        }
18343    }
18344
18345    fn on_display_map_changed(
18346        &mut self,
18347        _: Entity<DisplayMap>,
18348        _: &mut Window,
18349        cx: &mut Context<Self>,
18350    ) {
18351        cx.notify();
18352    }
18353
18354    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18355        let new_severity = if self.diagnostics_enabled() {
18356            EditorSettings::get_global(cx)
18357                .diagnostics_max_severity
18358                .unwrap_or(DiagnosticSeverity::Hint)
18359        } else {
18360            DiagnosticSeverity::Off
18361        };
18362        self.set_max_diagnostics_severity(new_severity, cx);
18363        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18364        self.update_edit_prediction_settings(cx);
18365        self.refresh_inline_completion(true, false, window, cx);
18366        self.refresh_inlay_hints(
18367            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18368                self.selections.newest_anchor().head(),
18369                &self.buffer.read(cx).snapshot(cx),
18370                cx,
18371            )),
18372            cx,
18373        );
18374
18375        let old_cursor_shape = self.cursor_shape;
18376
18377        {
18378            let editor_settings = EditorSettings::get_global(cx);
18379            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18380            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18381            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18382            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18383        }
18384
18385        if old_cursor_shape != self.cursor_shape {
18386            cx.emit(EditorEvent::CursorShapeChanged);
18387        }
18388
18389        let project_settings = ProjectSettings::get_global(cx);
18390        self.serialize_dirty_buffers =
18391            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18392
18393        if self.mode.is_full() {
18394            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18395            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18396            if self.show_inline_diagnostics != show_inline_diagnostics {
18397                self.show_inline_diagnostics = show_inline_diagnostics;
18398                self.refresh_inline_diagnostics(false, window, cx);
18399            }
18400
18401            if self.git_blame_inline_enabled != inline_blame_enabled {
18402                self.toggle_git_blame_inline_internal(false, window, cx);
18403            }
18404
18405            let minimap_settings = EditorSettings::get_global(cx).minimap;
18406            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18407                self.set_minimap_visibility(
18408                    self.minimap_visibility.toggle_visibility(),
18409                    window,
18410                    cx,
18411                );
18412            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18413                minimap_entity.update(cx, |minimap_editor, cx| {
18414                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18415                })
18416            }
18417        }
18418
18419        cx.notify();
18420    }
18421
18422    pub fn set_searchable(&mut self, searchable: bool) {
18423        self.searchable = searchable;
18424    }
18425
18426    pub fn searchable(&self) -> bool {
18427        self.searchable
18428    }
18429
18430    fn open_proposed_changes_editor(
18431        &mut self,
18432        _: &OpenProposedChangesEditor,
18433        window: &mut Window,
18434        cx: &mut Context<Self>,
18435    ) {
18436        let Some(workspace) = self.workspace() else {
18437            cx.propagate();
18438            return;
18439        };
18440
18441        let selections = self.selections.all::<usize>(cx);
18442        let multi_buffer = self.buffer.read(cx);
18443        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18444        let mut new_selections_by_buffer = HashMap::default();
18445        for selection in selections {
18446            for (buffer, range, _) in
18447                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18448            {
18449                let mut range = range.to_point(buffer);
18450                range.start.column = 0;
18451                range.end.column = buffer.line_len(range.end.row);
18452                new_selections_by_buffer
18453                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18454                    .or_insert(Vec::new())
18455                    .push(range)
18456            }
18457        }
18458
18459        let proposed_changes_buffers = new_selections_by_buffer
18460            .into_iter()
18461            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18462            .collect::<Vec<_>>();
18463        let proposed_changes_editor = cx.new(|cx| {
18464            ProposedChangesEditor::new(
18465                "Proposed changes",
18466                proposed_changes_buffers,
18467                self.project.clone(),
18468                window,
18469                cx,
18470            )
18471        });
18472
18473        window.defer(cx, move |window, cx| {
18474            workspace.update(cx, |workspace, cx| {
18475                workspace.active_pane().update(cx, |pane, cx| {
18476                    pane.add_item(
18477                        Box::new(proposed_changes_editor),
18478                        true,
18479                        true,
18480                        None,
18481                        window,
18482                        cx,
18483                    );
18484                });
18485            });
18486        });
18487    }
18488
18489    pub fn open_excerpts_in_split(
18490        &mut self,
18491        _: &OpenExcerptsSplit,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) {
18495        self.open_excerpts_common(None, true, window, cx)
18496    }
18497
18498    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18499        self.open_excerpts_common(None, false, window, cx)
18500    }
18501
18502    fn open_excerpts_common(
18503        &mut self,
18504        jump_data: Option<JumpData>,
18505        split: bool,
18506        window: &mut Window,
18507        cx: &mut Context<Self>,
18508    ) {
18509        let Some(workspace) = self.workspace() else {
18510            cx.propagate();
18511            return;
18512        };
18513
18514        if self.buffer.read(cx).is_singleton() {
18515            cx.propagate();
18516            return;
18517        }
18518
18519        let mut new_selections_by_buffer = HashMap::default();
18520        match &jump_data {
18521            Some(JumpData::MultiBufferPoint {
18522                excerpt_id,
18523                position,
18524                anchor,
18525                line_offset_from_top,
18526            }) => {
18527                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18528                if let Some(buffer) = multi_buffer_snapshot
18529                    .buffer_id_for_excerpt(*excerpt_id)
18530                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18531                {
18532                    let buffer_snapshot = buffer.read(cx).snapshot();
18533                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18534                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18535                    } else {
18536                        buffer_snapshot.clip_point(*position, Bias::Left)
18537                    };
18538                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18539                    new_selections_by_buffer.insert(
18540                        buffer,
18541                        (
18542                            vec![jump_to_offset..jump_to_offset],
18543                            Some(*line_offset_from_top),
18544                        ),
18545                    );
18546                }
18547            }
18548            Some(JumpData::MultiBufferRow {
18549                row,
18550                line_offset_from_top,
18551            }) => {
18552                let point = MultiBufferPoint::new(row.0, 0);
18553                if let Some((buffer, buffer_point, _)) =
18554                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18555                {
18556                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18557                    new_selections_by_buffer
18558                        .entry(buffer)
18559                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18560                        .0
18561                        .push(buffer_offset..buffer_offset)
18562                }
18563            }
18564            None => {
18565                let selections = self.selections.all::<usize>(cx);
18566                let multi_buffer = self.buffer.read(cx);
18567                for selection in selections {
18568                    for (snapshot, range, _, anchor) in multi_buffer
18569                        .snapshot(cx)
18570                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18571                    {
18572                        if let Some(anchor) = anchor {
18573                            // selection is in a deleted hunk
18574                            let Some(buffer_id) = anchor.buffer_id else {
18575                                continue;
18576                            };
18577                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18578                                continue;
18579                            };
18580                            let offset = text::ToOffset::to_offset(
18581                                &anchor.text_anchor,
18582                                &buffer_handle.read(cx).snapshot(),
18583                            );
18584                            let range = offset..offset;
18585                            new_selections_by_buffer
18586                                .entry(buffer_handle)
18587                                .or_insert((Vec::new(), None))
18588                                .0
18589                                .push(range)
18590                        } else {
18591                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18592                            else {
18593                                continue;
18594                            };
18595                            new_selections_by_buffer
18596                                .entry(buffer_handle)
18597                                .or_insert((Vec::new(), None))
18598                                .0
18599                                .push(range)
18600                        }
18601                    }
18602                }
18603            }
18604        }
18605
18606        new_selections_by_buffer
18607            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18608
18609        if new_selections_by_buffer.is_empty() {
18610            return;
18611        }
18612
18613        // We defer the pane interaction because we ourselves are a workspace item
18614        // and activating a new item causes the pane to call a method on us reentrantly,
18615        // which panics if we're on the stack.
18616        window.defer(cx, move |window, cx| {
18617            workspace.update(cx, |workspace, cx| {
18618                let pane = if split {
18619                    workspace.adjacent_pane(window, cx)
18620                } else {
18621                    workspace.active_pane().clone()
18622                };
18623
18624                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18625                    let editor = buffer
18626                        .read(cx)
18627                        .file()
18628                        .is_none()
18629                        .then(|| {
18630                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18631                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18632                            // Instead, we try to activate the existing editor in the pane first.
18633                            let (editor, pane_item_index) =
18634                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18635                                    let editor = item.downcast::<Editor>()?;
18636                                    let singleton_buffer =
18637                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18638                                    if singleton_buffer == buffer {
18639                                        Some((editor, i))
18640                                    } else {
18641                                        None
18642                                    }
18643                                })?;
18644                            pane.update(cx, |pane, cx| {
18645                                pane.activate_item(pane_item_index, true, true, window, cx)
18646                            });
18647                            Some(editor)
18648                        })
18649                        .flatten()
18650                        .unwrap_or_else(|| {
18651                            workspace.open_project_item::<Self>(
18652                                pane.clone(),
18653                                buffer,
18654                                true,
18655                                true,
18656                                window,
18657                                cx,
18658                            )
18659                        });
18660
18661                    editor.update(cx, |editor, cx| {
18662                        let autoscroll = match scroll_offset {
18663                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18664                            None => Autoscroll::newest(),
18665                        };
18666                        let nav_history = editor.nav_history.take();
18667                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18668                            s.select_ranges(ranges);
18669                        });
18670                        editor.nav_history = nav_history;
18671                    });
18672                }
18673            })
18674        });
18675    }
18676
18677    // For now, don't allow opening excerpts in buffers that aren't backed by
18678    // regular project files.
18679    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18680        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18681    }
18682
18683    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18684        let snapshot = self.buffer.read(cx).read(cx);
18685        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18686        Some(
18687            ranges
18688                .iter()
18689                .map(move |range| {
18690                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18691                })
18692                .collect(),
18693        )
18694    }
18695
18696    fn selection_replacement_ranges(
18697        &self,
18698        range: Range<OffsetUtf16>,
18699        cx: &mut App,
18700    ) -> Vec<Range<OffsetUtf16>> {
18701        let selections = self.selections.all::<OffsetUtf16>(cx);
18702        let newest_selection = selections
18703            .iter()
18704            .max_by_key(|selection| selection.id)
18705            .unwrap();
18706        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18707        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18708        let snapshot = self.buffer.read(cx).read(cx);
18709        selections
18710            .into_iter()
18711            .map(|mut selection| {
18712                selection.start.0 =
18713                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18714                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18715                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18716                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18717            })
18718            .collect()
18719    }
18720
18721    fn report_editor_event(
18722        &self,
18723        event_type: &'static str,
18724        file_extension: Option<String>,
18725        cx: &App,
18726    ) {
18727        if cfg!(any(test, feature = "test-support")) {
18728            return;
18729        }
18730
18731        let Some(project) = &self.project else { return };
18732
18733        // If None, we are in a file without an extension
18734        let file = self
18735            .buffer
18736            .read(cx)
18737            .as_singleton()
18738            .and_then(|b| b.read(cx).file());
18739        let file_extension = file_extension.or(file
18740            .as_ref()
18741            .and_then(|file| Path::new(file.file_name(cx)).extension())
18742            .and_then(|e| e.to_str())
18743            .map(|a| a.to_string()));
18744
18745        let vim_mode = vim_enabled(cx);
18746
18747        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18748        let copilot_enabled = edit_predictions_provider
18749            == language::language_settings::EditPredictionProvider::Copilot;
18750        let copilot_enabled_for_language = self
18751            .buffer
18752            .read(cx)
18753            .language_settings(cx)
18754            .show_edit_predictions;
18755
18756        let project = project.read(cx);
18757        telemetry::event!(
18758            event_type,
18759            file_extension,
18760            vim_mode,
18761            copilot_enabled,
18762            copilot_enabled_for_language,
18763            edit_predictions_provider,
18764            is_via_ssh = project.is_via_ssh(),
18765        );
18766    }
18767
18768    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18769    /// with each line being an array of {text, highlight} objects.
18770    fn copy_highlight_json(
18771        &mut self,
18772        _: &CopyHighlightJson,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        #[derive(Serialize)]
18777        struct Chunk<'a> {
18778            text: String,
18779            highlight: Option<&'a str>,
18780        }
18781
18782        let snapshot = self.buffer.read(cx).snapshot(cx);
18783        let range = self
18784            .selected_text_range(false, window, cx)
18785            .and_then(|selection| {
18786                if selection.range.is_empty() {
18787                    None
18788                } else {
18789                    Some(selection.range)
18790                }
18791            })
18792            .unwrap_or_else(|| 0..snapshot.len());
18793
18794        let chunks = snapshot.chunks(range, true);
18795        let mut lines = Vec::new();
18796        let mut line: VecDeque<Chunk> = VecDeque::new();
18797
18798        let Some(style) = self.style.as_ref() else {
18799            return;
18800        };
18801
18802        for chunk in chunks {
18803            let highlight = chunk
18804                .syntax_highlight_id
18805                .and_then(|id| id.name(&style.syntax));
18806            let mut chunk_lines = chunk.text.split('\n').peekable();
18807            while let Some(text) = chunk_lines.next() {
18808                let mut merged_with_last_token = false;
18809                if let Some(last_token) = line.back_mut() {
18810                    if last_token.highlight == highlight {
18811                        last_token.text.push_str(text);
18812                        merged_with_last_token = true;
18813                    }
18814                }
18815
18816                if !merged_with_last_token {
18817                    line.push_back(Chunk {
18818                        text: text.into(),
18819                        highlight,
18820                    });
18821                }
18822
18823                if chunk_lines.peek().is_some() {
18824                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18825                        line.pop_front();
18826                    }
18827                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18828                        line.pop_back();
18829                    }
18830
18831                    lines.push(mem::take(&mut line));
18832                }
18833            }
18834        }
18835
18836        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18837            return;
18838        };
18839        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18840    }
18841
18842    pub fn open_context_menu(
18843        &mut self,
18844        _: &OpenContextMenu,
18845        window: &mut Window,
18846        cx: &mut Context<Self>,
18847    ) {
18848        self.request_autoscroll(Autoscroll::newest(), cx);
18849        let position = self.selections.newest_display(cx).start;
18850        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18851    }
18852
18853    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18854        &self.inlay_hint_cache
18855    }
18856
18857    pub fn replay_insert_event(
18858        &mut self,
18859        text: &str,
18860        relative_utf16_range: Option<Range<isize>>,
18861        window: &mut Window,
18862        cx: &mut Context<Self>,
18863    ) {
18864        if !self.input_enabled {
18865            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18866            return;
18867        }
18868        if let Some(relative_utf16_range) = relative_utf16_range {
18869            let selections = self.selections.all::<OffsetUtf16>(cx);
18870            self.change_selections(None, window, cx, |s| {
18871                let new_ranges = selections.into_iter().map(|range| {
18872                    let start = OffsetUtf16(
18873                        range
18874                            .head()
18875                            .0
18876                            .saturating_add_signed(relative_utf16_range.start),
18877                    );
18878                    let end = OffsetUtf16(
18879                        range
18880                            .head()
18881                            .0
18882                            .saturating_add_signed(relative_utf16_range.end),
18883                    );
18884                    start..end
18885                });
18886                s.select_ranges(new_ranges);
18887            });
18888        }
18889
18890        self.handle_input(text, window, cx);
18891    }
18892
18893    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18894        let Some(provider) = self.semantics_provider.as_ref() else {
18895            return false;
18896        };
18897
18898        let mut supports = false;
18899        self.buffer().update(cx, |this, cx| {
18900            this.for_each_buffer(|buffer| {
18901                supports |= provider.supports_inlay_hints(buffer, cx);
18902            });
18903        });
18904
18905        supports
18906    }
18907
18908    pub fn is_focused(&self, window: &Window) -> bool {
18909        self.focus_handle.is_focused(window)
18910    }
18911
18912    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18913        cx.emit(EditorEvent::Focused);
18914
18915        if let Some(descendant) = self
18916            .last_focused_descendant
18917            .take()
18918            .and_then(|descendant| descendant.upgrade())
18919        {
18920            window.focus(&descendant);
18921        } else {
18922            if let Some(blame) = self.blame.as_ref() {
18923                blame.update(cx, GitBlame::focus)
18924            }
18925
18926            self.blink_manager.update(cx, BlinkManager::enable);
18927            self.show_cursor_names(window, cx);
18928            self.buffer.update(cx, |buffer, cx| {
18929                buffer.finalize_last_transaction(cx);
18930                if self.leader_id.is_none() {
18931                    buffer.set_active_selections(
18932                        &self.selections.disjoint_anchors(),
18933                        self.selections.line_mode,
18934                        self.cursor_shape,
18935                        cx,
18936                    );
18937                }
18938            });
18939        }
18940    }
18941
18942    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18943        cx.emit(EditorEvent::FocusedIn)
18944    }
18945
18946    fn handle_focus_out(
18947        &mut self,
18948        event: FocusOutEvent,
18949        _window: &mut Window,
18950        cx: &mut Context<Self>,
18951    ) {
18952        if event.blurred != self.focus_handle {
18953            self.last_focused_descendant = Some(event.blurred);
18954        }
18955        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18956    }
18957
18958    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18959        self.blink_manager.update(cx, BlinkManager::disable);
18960        self.buffer
18961            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18962
18963        if let Some(blame) = self.blame.as_ref() {
18964            blame.update(cx, GitBlame::blur)
18965        }
18966        if !self.hover_state.focused(window, cx) {
18967            hide_hover(self, cx);
18968        }
18969        if !self
18970            .context_menu
18971            .borrow()
18972            .as_ref()
18973            .is_some_and(|context_menu| context_menu.focused(window, cx))
18974        {
18975            self.hide_context_menu(window, cx);
18976        }
18977        self.discard_inline_completion(false, cx);
18978        cx.emit(EditorEvent::Blurred);
18979        cx.notify();
18980    }
18981
18982    pub fn register_action<A: Action>(
18983        &mut self,
18984        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18985    ) -> Subscription {
18986        let id = self.next_editor_action_id.post_inc();
18987        let listener = Arc::new(listener);
18988        self.editor_actions.borrow_mut().insert(
18989            id,
18990            Box::new(move |window, _| {
18991                let listener = listener.clone();
18992                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18993                    let action = action.downcast_ref().unwrap();
18994                    if phase == DispatchPhase::Bubble {
18995                        listener(action, window, cx)
18996                    }
18997                })
18998            }),
18999        );
19000
19001        let editor_actions = self.editor_actions.clone();
19002        Subscription::new(move || {
19003            editor_actions.borrow_mut().remove(&id);
19004        })
19005    }
19006
19007    pub fn file_header_size(&self) -> u32 {
19008        FILE_HEADER_HEIGHT
19009    }
19010
19011    pub fn restore(
19012        &mut self,
19013        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19014        window: &mut Window,
19015        cx: &mut Context<Self>,
19016    ) {
19017        let workspace = self.workspace();
19018        let project = self.project.as_ref();
19019        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19020            let mut tasks = Vec::new();
19021            for (buffer_id, changes) in revert_changes {
19022                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19023                    buffer.update(cx, |buffer, cx| {
19024                        buffer.edit(
19025                            changes
19026                                .into_iter()
19027                                .map(|(range, text)| (range, text.to_string())),
19028                            None,
19029                            cx,
19030                        );
19031                    });
19032
19033                    if let Some(project) =
19034                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19035                    {
19036                        project.update(cx, |project, cx| {
19037                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19038                        })
19039                    }
19040                }
19041            }
19042            tasks
19043        });
19044        cx.spawn_in(window, async move |_, cx| {
19045            for (buffer, task) in save_tasks {
19046                let result = task.await;
19047                if result.is_err() {
19048                    let Some(path) = buffer
19049                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19050                        .ok()
19051                    else {
19052                        continue;
19053                    };
19054                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19055                        let Some(task) = cx
19056                            .update_window_entity(&workspace, |workspace, window, cx| {
19057                                workspace
19058                                    .open_path_preview(path, None, false, false, false, window, cx)
19059                            })
19060                            .ok()
19061                        else {
19062                            continue;
19063                        };
19064                        task.await.log_err();
19065                    }
19066                }
19067            }
19068        })
19069        .detach();
19070        self.change_selections(None, window, cx, |selections| selections.refresh());
19071    }
19072
19073    pub fn to_pixel_point(
19074        &self,
19075        source: multi_buffer::Anchor,
19076        editor_snapshot: &EditorSnapshot,
19077        window: &mut Window,
19078    ) -> Option<gpui::Point<Pixels>> {
19079        let source_point = source.to_display_point(editor_snapshot);
19080        self.display_to_pixel_point(source_point, editor_snapshot, window)
19081    }
19082
19083    pub fn display_to_pixel_point(
19084        &self,
19085        source: DisplayPoint,
19086        editor_snapshot: &EditorSnapshot,
19087        window: &mut Window,
19088    ) -> Option<gpui::Point<Pixels>> {
19089        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19090        let text_layout_details = self.text_layout_details(window);
19091        let scroll_top = text_layout_details
19092            .scroll_anchor
19093            .scroll_position(editor_snapshot)
19094            .y;
19095
19096        if source.row().as_f32() < scroll_top.floor() {
19097            return None;
19098        }
19099        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19100        let source_y = line_height * (source.row().as_f32() - scroll_top);
19101        Some(gpui::Point::new(source_x, source_y))
19102    }
19103
19104    pub fn has_visible_completions_menu(&self) -> bool {
19105        !self.edit_prediction_preview_is_active()
19106            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19107                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19108            })
19109    }
19110
19111    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19112        if self.mode.is_minimap() {
19113            return;
19114        }
19115        self.addons
19116            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19117    }
19118
19119    pub fn unregister_addon<T: Addon>(&mut self) {
19120        self.addons.remove(&std::any::TypeId::of::<T>());
19121    }
19122
19123    pub fn addon<T: Addon>(&self) -> Option<&T> {
19124        let type_id = std::any::TypeId::of::<T>();
19125        self.addons
19126            .get(&type_id)
19127            .and_then(|item| item.to_any().downcast_ref::<T>())
19128    }
19129
19130    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19131        let type_id = std::any::TypeId::of::<T>();
19132        self.addons
19133            .get_mut(&type_id)
19134            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19135    }
19136
19137    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19138        let text_layout_details = self.text_layout_details(window);
19139        let style = &text_layout_details.editor_style;
19140        let font_id = window.text_system().resolve_font(&style.text.font());
19141        let font_size = style.text.font_size.to_pixels(window.rem_size());
19142        let line_height = style.text.line_height_in_pixels(window.rem_size());
19143        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19144
19145        gpui::Size::new(em_width, line_height)
19146    }
19147
19148    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19149        self.load_diff_task.clone()
19150    }
19151
19152    fn read_metadata_from_db(
19153        &mut self,
19154        item_id: u64,
19155        workspace_id: WorkspaceId,
19156        window: &mut Window,
19157        cx: &mut Context<Editor>,
19158    ) {
19159        if self.is_singleton(cx)
19160            && !self.mode.is_minimap()
19161            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19162        {
19163            let buffer_snapshot = OnceCell::new();
19164
19165            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19166                if !folds.is_empty() {
19167                    let snapshot =
19168                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19169                    self.fold_ranges(
19170                        folds
19171                            .into_iter()
19172                            .map(|(start, end)| {
19173                                snapshot.clip_offset(start, Bias::Left)
19174                                    ..snapshot.clip_offset(end, Bias::Right)
19175                            })
19176                            .collect(),
19177                        false,
19178                        window,
19179                        cx,
19180                    );
19181                }
19182            }
19183
19184            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19185                if !selections.is_empty() {
19186                    let snapshot =
19187                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19188                    self.change_selections(None, window, cx, |s| {
19189                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19190                            snapshot.clip_offset(start, Bias::Left)
19191                                ..snapshot.clip_offset(end, Bias::Right)
19192                        }));
19193                    });
19194                }
19195            };
19196        }
19197
19198        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19199    }
19200}
19201
19202fn vim_enabled(cx: &App) -> bool {
19203    cx.global::<SettingsStore>()
19204        .raw_user_settings()
19205        .get("vim_mode")
19206        == Some(&serde_json::Value::Bool(true))
19207}
19208
19209// Consider user intent and default settings
19210fn choose_completion_range(
19211    completion: &Completion,
19212    intent: CompletionIntent,
19213    buffer: &Entity<Buffer>,
19214    cx: &mut Context<Editor>,
19215) -> Range<usize> {
19216    fn should_replace(
19217        completion: &Completion,
19218        insert_range: &Range<text::Anchor>,
19219        intent: CompletionIntent,
19220        completion_mode_setting: LspInsertMode,
19221        buffer: &Buffer,
19222    ) -> bool {
19223        // specific actions take precedence over settings
19224        match intent {
19225            CompletionIntent::CompleteWithInsert => return false,
19226            CompletionIntent::CompleteWithReplace => return true,
19227            CompletionIntent::Complete | CompletionIntent::Compose => {}
19228        }
19229
19230        match completion_mode_setting {
19231            LspInsertMode::Insert => false,
19232            LspInsertMode::Replace => true,
19233            LspInsertMode::ReplaceSubsequence => {
19234                let mut text_to_replace = buffer.chars_for_range(
19235                    buffer.anchor_before(completion.replace_range.start)
19236                        ..buffer.anchor_after(completion.replace_range.end),
19237                );
19238                let mut completion_text = completion.new_text.chars();
19239
19240                // is `text_to_replace` a subsequence of `completion_text`
19241                text_to_replace
19242                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19243            }
19244            LspInsertMode::ReplaceSuffix => {
19245                let range_after_cursor = insert_range.end..completion.replace_range.end;
19246
19247                let text_after_cursor = buffer
19248                    .text_for_range(
19249                        buffer.anchor_before(range_after_cursor.start)
19250                            ..buffer.anchor_after(range_after_cursor.end),
19251                    )
19252                    .collect::<String>();
19253                completion.new_text.ends_with(&text_after_cursor)
19254            }
19255        }
19256    }
19257
19258    let buffer = buffer.read(cx);
19259
19260    if let CompletionSource::Lsp {
19261        insert_range: Some(insert_range),
19262        ..
19263    } = &completion.source
19264    {
19265        let completion_mode_setting =
19266            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19267                .completions
19268                .lsp_insert_mode;
19269
19270        if !should_replace(
19271            completion,
19272            &insert_range,
19273            intent,
19274            completion_mode_setting,
19275            buffer,
19276        ) {
19277            return insert_range.to_offset(buffer);
19278        }
19279    }
19280
19281    completion.replace_range.to_offset(buffer)
19282}
19283
19284fn insert_extra_newline_brackets(
19285    buffer: &MultiBufferSnapshot,
19286    range: Range<usize>,
19287    language: &language::LanguageScope,
19288) -> bool {
19289    let leading_whitespace_len = buffer
19290        .reversed_chars_at(range.start)
19291        .take_while(|c| c.is_whitespace() && *c != '\n')
19292        .map(|c| c.len_utf8())
19293        .sum::<usize>();
19294    let trailing_whitespace_len = buffer
19295        .chars_at(range.end)
19296        .take_while(|c| c.is_whitespace() && *c != '\n')
19297        .map(|c| c.len_utf8())
19298        .sum::<usize>();
19299    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19300
19301    language.brackets().any(|(pair, enabled)| {
19302        let pair_start = pair.start.trim_end();
19303        let pair_end = pair.end.trim_start();
19304
19305        enabled
19306            && pair.newline
19307            && buffer.contains_str_at(range.end, pair_end)
19308            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19309    })
19310}
19311
19312fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19313    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19314        [(buffer, range, _)] => (*buffer, range.clone()),
19315        _ => return false,
19316    };
19317    let pair = {
19318        let mut result: Option<BracketMatch> = None;
19319
19320        for pair in buffer
19321            .all_bracket_ranges(range.clone())
19322            .filter(move |pair| {
19323                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19324            })
19325        {
19326            let len = pair.close_range.end - pair.open_range.start;
19327
19328            if let Some(existing) = &result {
19329                let existing_len = existing.close_range.end - existing.open_range.start;
19330                if len > existing_len {
19331                    continue;
19332                }
19333            }
19334
19335            result = Some(pair);
19336        }
19337
19338        result
19339    };
19340    let Some(pair) = pair else {
19341        return false;
19342    };
19343    pair.newline_only
19344        && buffer
19345            .chars_for_range(pair.open_range.end..range.start)
19346            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19347            .all(|c| c.is_whitespace() && c != '\n')
19348}
19349
19350fn update_uncommitted_diff_for_buffer(
19351    editor: Entity<Editor>,
19352    project: &Entity<Project>,
19353    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19354    buffer: Entity<MultiBuffer>,
19355    cx: &mut App,
19356) -> Task<()> {
19357    let mut tasks = Vec::new();
19358    project.update(cx, |project, cx| {
19359        for buffer in buffers {
19360            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19361                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19362            }
19363        }
19364    });
19365    cx.spawn(async move |cx| {
19366        let diffs = future::join_all(tasks).await;
19367        if editor
19368            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19369            .unwrap_or(false)
19370        {
19371            return;
19372        }
19373
19374        buffer
19375            .update(cx, |buffer, cx| {
19376                for diff in diffs.into_iter().flatten() {
19377                    buffer.add_diff(diff, cx);
19378                }
19379            })
19380            .ok();
19381    })
19382}
19383
19384fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19385    let tab_size = tab_size.get() as usize;
19386    let mut width = offset;
19387
19388    for ch in text.chars() {
19389        width += if ch == '\t' {
19390            tab_size - (width % tab_size)
19391        } else {
19392            1
19393        };
19394    }
19395
19396    width - offset
19397}
19398
19399#[cfg(test)]
19400mod tests {
19401    use super::*;
19402
19403    #[test]
19404    fn test_string_size_with_expanded_tabs() {
19405        let nz = |val| NonZeroU32::new(val).unwrap();
19406        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19407        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19408        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19409        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19410        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19411        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19412        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19413        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19414    }
19415}
19416
19417/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19418struct WordBreakingTokenizer<'a> {
19419    input: &'a str,
19420}
19421
19422impl<'a> WordBreakingTokenizer<'a> {
19423    fn new(input: &'a str) -> Self {
19424        Self { input }
19425    }
19426}
19427
19428fn is_char_ideographic(ch: char) -> bool {
19429    use unicode_script::Script::*;
19430    use unicode_script::UnicodeScript;
19431    matches!(ch.script(), Han | Tangut | Yi)
19432}
19433
19434fn is_grapheme_ideographic(text: &str) -> bool {
19435    text.chars().any(is_char_ideographic)
19436}
19437
19438fn is_grapheme_whitespace(text: &str) -> bool {
19439    text.chars().any(|x| x.is_whitespace())
19440}
19441
19442fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19443    text.chars().next().map_or(false, |ch| {
19444        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19445    })
19446}
19447
19448#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19449enum WordBreakToken<'a> {
19450    Word { token: &'a str, grapheme_len: usize },
19451    InlineWhitespace { token: &'a str, grapheme_len: usize },
19452    Newline,
19453}
19454
19455impl<'a> Iterator for WordBreakingTokenizer<'a> {
19456    /// Yields a span, the count of graphemes in the token, and whether it was
19457    /// whitespace. Note that it also breaks at word boundaries.
19458    type Item = WordBreakToken<'a>;
19459
19460    fn next(&mut self) -> Option<Self::Item> {
19461        use unicode_segmentation::UnicodeSegmentation;
19462        if self.input.is_empty() {
19463            return None;
19464        }
19465
19466        let mut iter = self.input.graphemes(true).peekable();
19467        let mut offset = 0;
19468        let mut grapheme_len = 0;
19469        if let Some(first_grapheme) = iter.next() {
19470            let is_newline = first_grapheme == "\n";
19471            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19472            offset += first_grapheme.len();
19473            grapheme_len += 1;
19474            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19475                if let Some(grapheme) = iter.peek().copied() {
19476                    if should_stay_with_preceding_ideograph(grapheme) {
19477                        offset += grapheme.len();
19478                        grapheme_len += 1;
19479                    }
19480                }
19481            } else {
19482                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19483                let mut next_word_bound = words.peek().copied();
19484                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19485                    next_word_bound = words.next();
19486                }
19487                while let Some(grapheme) = iter.peek().copied() {
19488                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19489                        break;
19490                    };
19491                    if is_grapheme_whitespace(grapheme) != is_whitespace
19492                        || (grapheme == "\n") != is_newline
19493                    {
19494                        break;
19495                    };
19496                    offset += grapheme.len();
19497                    grapheme_len += 1;
19498                    iter.next();
19499                }
19500            }
19501            let token = &self.input[..offset];
19502            self.input = &self.input[offset..];
19503            if token == "\n" {
19504                Some(WordBreakToken::Newline)
19505            } else if is_whitespace {
19506                Some(WordBreakToken::InlineWhitespace {
19507                    token,
19508                    grapheme_len,
19509                })
19510            } else {
19511                Some(WordBreakToken::Word {
19512                    token,
19513                    grapheme_len,
19514                })
19515            }
19516        } else {
19517            None
19518        }
19519    }
19520}
19521
19522#[test]
19523fn test_word_breaking_tokenizer() {
19524    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19525        ("", &[]),
19526        ("  ", &[whitespace("  ", 2)]),
19527        ("Ʒ", &[word("Ʒ", 1)]),
19528        ("Ǽ", &[word("Ǽ", 1)]),
19529        ("", &[word("", 1)]),
19530        ("⋑⋑", &[word("⋑⋑", 2)]),
19531        (
19532            "原理,进而",
19533            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19534        ),
19535        (
19536            "hello world",
19537            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19538        ),
19539        (
19540            "hello, world",
19541            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19542        ),
19543        (
19544            "  hello world",
19545            &[
19546                whitespace("  ", 2),
19547                word("hello", 5),
19548                whitespace(" ", 1),
19549                word("world", 5),
19550            ],
19551        ),
19552        (
19553            "这是什么 \n 钢笔",
19554            &[
19555                word("", 1),
19556                word("", 1),
19557                word("", 1),
19558                word("", 1),
19559                whitespace(" ", 1),
19560                newline(),
19561                whitespace(" ", 1),
19562                word("", 1),
19563                word("", 1),
19564            ],
19565        ),
19566        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19567    ];
19568
19569    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19570        WordBreakToken::Word {
19571            token,
19572            grapheme_len,
19573        }
19574    }
19575
19576    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19577        WordBreakToken::InlineWhitespace {
19578            token,
19579            grapheme_len,
19580        }
19581    }
19582
19583    fn newline() -> WordBreakToken<'static> {
19584        WordBreakToken::Newline
19585    }
19586
19587    for (input, result) in tests {
19588        assert_eq!(
19589            WordBreakingTokenizer::new(input)
19590                .collect::<Vec<_>>()
19591                .as_slice(),
19592            *result,
19593        );
19594    }
19595}
19596
19597fn wrap_with_prefix(
19598    line_prefix: String,
19599    unwrapped_text: String,
19600    wrap_column: usize,
19601    tab_size: NonZeroU32,
19602    preserve_existing_whitespace: bool,
19603) -> String {
19604    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19605    let mut wrapped_text = String::new();
19606    let mut current_line = line_prefix.clone();
19607
19608    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19609    let mut current_line_len = line_prefix_len;
19610    let mut in_whitespace = false;
19611    for token in tokenizer {
19612        let have_preceding_whitespace = in_whitespace;
19613        match token {
19614            WordBreakToken::Word {
19615                token,
19616                grapheme_len,
19617            } => {
19618                in_whitespace = false;
19619                if current_line_len + grapheme_len > wrap_column
19620                    && current_line_len != line_prefix_len
19621                {
19622                    wrapped_text.push_str(current_line.trim_end());
19623                    wrapped_text.push('\n');
19624                    current_line.truncate(line_prefix.len());
19625                    current_line_len = line_prefix_len;
19626                }
19627                current_line.push_str(token);
19628                current_line_len += grapheme_len;
19629            }
19630            WordBreakToken::InlineWhitespace {
19631                mut token,
19632                mut grapheme_len,
19633            } => {
19634                in_whitespace = true;
19635                if have_preceding_whitespace && !preserve_existing_whitespace {
19636                    continue;
19637                }
19638                if !preserve_existing_whitespace {
19639                    token = " ";
19640                    grapheme_len = 1;
19641                }
19642                if current_line_len + grapheme_len > wrap_column {
19643                    wrapped_text.push_str(current_line.trim_end());
19644                    wrapped_text.push('\n');
19645                    current_line.truncate(line_prefix.len());
19646                    current_line_len = line_prefix_len;
19647                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19648                    current_line.push_str(token);
19649                    current_line_len += grapheme_len;
19650                }
19651            }
19652            WordBreakToken::Newline => {
19653                in_whitespace = true;
19654                if preserve_existing_whitespace {
19655                    wrapped_text.push_str(current_line.trim_end());
19656                    wrapped_text.push('\n');
19657                    current_line.truncate(line_prefix.len());
19658                    current_line_len = line_prefix_len;
19659                } else if have_preceding_whitespace {
19660                    continue;
19661                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19662                {
19663                    wrapped_text.push_str(current_line.trim_end());
19664                    wrapped_text.push('\n');
19665                    current_line.truncate(line_prefix.len());
19666                    current_line_len = line_prefix_len;
19667                } else if current_line_len != line_prefix_len {
19668                    current_line.push(' ');
19669                    current_line_len += 1;
19670                }
19671            }
19672        }
19673    }
19674
19675    if !current_line.is_empty() {
19676        wrapped_text.push_str(&current_line);
19677    }
19678    wrapped_text
19679}
19680
19681#[test]
19682fn test_wrap_with_prefix() {
19683    assert_eq!(
19684        wrap_with_prefix(
19685            "# ".to_string(),
19686            "abcdefg".to_string(),
19687            4,
19688            NonZeroU32::new(4).unwrap(),
19689            false,
19690        ),
19691        "# abcdefg"
19692    );
19693    assert_eq!(
19694        wrap_with_prefix(
19695            "".to_string(),
19696            "\thello world".to_string(),
19697            8,
19698            NonZeroU32::new(4).unwrap(),
19699            false,
19700        ),
19701        "hello\nworld"
19702    );
19703    assert_eq!(
19704        wrap_with_prefix(
19705            "// ".to_string(),
19706            "xx \nyy zz aa bb cc".to_string(),
19707            12,
19708            NonZeroU32::new(4).unwrap(),
19709            false,
19710        ),
19711        "// xx yy zz\n// aa bb cc"
19712    );
19713    assert_eq!(
19714        wrap_with_prefix(
19715            String::new(),
19716            "这是什么 \n 钢笔".to_string(),
19717            3,
19718            NonZeroU32::new(4).unwrap(),
19719            false,
19720        ),
19721        "这是什\n么 钢\n"
19722    );
19723}
19724
19725pub trait CollaborationHub {
19726    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19727    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19728    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19729}
19730
19731impl CollaborationHub for Entity<Project> {
19732    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19733        self.read(cx).collaborators()
19734    }
19735
19736    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19737        self.read(cx).user_store().read(cx).participant_indices()
19738    }
19739
19740    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19741        let this = self.read(cx);
19742        let user_ids = this.collaborators().values().map(|c| c.user_id);
19743        this.user_store().read_with(cx, |user_store, cx| {
19744            user_store.participant_names(user_ids, cx)
19745        })
19746    }
19747}
19748
19749pub trait SemanticsProvider {
19750    fn hover(
19751        &self,
19752        buffer: &Entity<Buffer>,
19753        position: text::Anchor,
19754        cx: &mut App,
19755    ) -> Option<Task<Vec<project::Hover>>>;
19756
19757    fn inline_values(
19758        &self,
19759        buffer_handle: Entity<Buffer>,
19760        range: Range<text::Anchor>,
19761        cx: &mut App,
19762    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19763
19764    fn inlay_hints(
19765        &self,
19766        buffer_handle: Entity<Buffer>,
19767        range: Range<text::Anchor>,
19768        cx: &mut App,
19769    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19770
19771    fn resolve_inlay_hint(
19772        &self,
19773        hint: InlayHint,
19774        buffer_handle: Entity<Buffer>,
19775        server_id: LanguageServerId,
19776        cx: &mut App,
19777    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19778
19779    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19780
19781    fn document_highlights(
19782        &self,
19783        buffer: &Entity<Buffer>,
19784        position: text::Anchor,
19785        cx: &mut App,
19786    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19787
19788    fn definitions(
19789        &self,
19790        buffer: &Entity<Buffer>,
19791        position: text::Anchor,
19792        kind: GotoDefinitionKind,
19793        cx: &mut App,
19794    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19795
19796    fn range_for_rename(
19797        &self,
19798        buffer: &Entity<Buffer>,
19799        position: text::Anchor,
19800        cx: &mut App,
19801    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19802
19803    fn perform_rename(
19804        &self,
19805        buffer: &Entity<Buffer>,
19806        position: text::Anchor,
19807        new_name: String,
19808        cx: &mut App,
19809    ) -> Option<Task<Result<ProjectTransaction>>>;
19810}
19811
19812pub trait CompletionProvider {
19813    fn completions(
19814        &self,
19815        excerpt_id: ExcerptId,
19816        buffer: &Entity<Buffer>,
19817        buffer_position: text::Anchor,
19818        trigger: CompletionContext,
19819        window: &mut Window,
19820        cx: &mut Context<Editor>,
19821    ) -> Task<Result<Option<Vec<Completion>>>>;
19822
19823    fn resolve_completions(
19824        &self,
19825        buffer: Entity<Buffer>,
19826        completion_indices: Vec<usize>,
19827        completions: Rc<RefCell<Box<[Completion]>>>,
19828        cx: &mut Context<Editor>,
19829    ) -> Task<Result<bool>>;
19830
19831    fn apply_additional_edits_for_completion(
19832        &self,
19833        _buffer: Entity<Buffer>,
19834        _completions: Rc<RefCell<Box<[Completion]>>>,
19835        _completion_index: usize,
19836        _push_to_history: bool,
19837        _cx: &mut Context<Editor>,
19838    ) -> Task<Result<Option<language::Transaction>>> {
19839        Task::ready(Ok(None))
19840    }
19841
19842    fn is_completion_trigger(
19843        &self,
19844        buffer: &Entity<Buffer>,
19845        position: language::Anchor,
19846        text: &str,
19847        trigger_in_words: bool,
19848        cx: &mut Context<Editor>,
19849    ) -> bool;
19850
19851    fn sort_completions(&self) -> bool {
19852        true
19853    }
19854
19855    fn filter_completions(&self) -> bool {
19856        true
19857    }
19858}
19859
19860pub trait CodeActionProvider {
19861    fn id(&self) -> Arc<str>;
19862
19863    fn code_actions(
19864        &self,
19865        buffer: &Entity<Buffer>,
19866        range: Range<text::Anchor>,
19867        window: &mut Window,
19868        cx: &mut App,
19869    ) -> Task<Result<Vec<CodeAction>>>;
19870
19871    fn apply_code_action(
19872        &self,
19873        buffer_handle: Entity<Buffer>,
19874        action: CodeAction,
19875        excerpt_id: ExcerptId,
19876        push_to_history: bool,
19877        window: &mut Window,
19878        cx: &mut App,
19879    ) -> Task<Result<ProjectTransaction>>;
19880}
19881
19882impl CodeActionProvider for Entity<Project> {
19883    fn id(&self) -> Arc<str> {
19884        "project".into()
19885    }
19886
19887    fn code_actions(
19888        &self,
19889        buffer: &Entity<Buffer>,
19890        range: Range<text::Anchor>,
19891        _window: &mut Window,
19892        cx: &mut App,
19893    ) -> Task<Result<Vec<CodeAction>>> {
19894        self.update(cx, |project, cx| {
19895            let code_lens = project.code_lens(buffer, range.clone(), cx);
19896            let code_actions = project.code_actions(buffer, range, None, cx);
19897            cx.background_spawn(async move {
19898                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19899                Ok(code_lens
19900                    .context("code lens fetch")?
19901                    .into_iter()
19902                    .chain(code_actions.context("code action fetch")?)
19903                    .collect())
19904            })
19905        })
19906    }
19907
19908    fn apply_code_action(
19909        &self,
19910        buffer_handle: Entity<Buffer>,
19911        action: CodeAction,
19912        _excerpt_id: ExcerptId,
19913        push_to_history: bool,
19914        _window: &mut Window,
19915        cx: &mut App,
19916    ) -> Task<Result<ProjectTransaction>> {
19917        self.update(cx, |project, cx| {
19918            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19919        })
19920    }
19921}
19922
19923fn snippet_completions(
19924    project: &Project,
19925    buffer: &Entity<Buffer>,
19926    buffer_position: text::Anchor,
19927    cx: &mut App,
19928) -> Task<Result<Vec<Completion>>> {
19929    let languages = buffer.read(cx).languages_at(buffer_position);
19930    let snippet_store = project.snippets().read(cx);
19931
19932    let scopes: Vec<_> = languages
19933        .iter()
19934        .filter_map(|language| {
19935            let language_name = language.lsp_id();
19936            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19937
19938            if snippets.is_empty() {
19939                None
19940            } else {
19941                Some((language.default_scope(), snippets))
19942            }
19943        })
19944        .collect();
19945
19946    if scopes.is_empty() {
19947        return Task::ready(Ok(vec![]));
19948    }
19949
19950    let snapshot = buffer.read(cx).text_snapshot();
19951    let chars: String = snapshot
19952        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19953        .collect();
19954    let executor = cx.background_executor().clone();
19955
19956    cx.background_spawn(async move {
19957        let mut all_results: Vec<Completion> = Vec::new();
19958        for (scope, snippets) in scopes.into_iter() {
19959            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19960            let mut last_word = chars
19961                .chars()
19962                .take_while(|c| classifier.is_word(*c))
19963                .collect::<String>();
19964            last_word = last_word.chars().rev().collect();
19965
19966            if last_word.is_empty() {
19967                return Ok(vec![]);
19968            }
19969
19970            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19971            let to_lsp = |point: &text::Anchor| {
19972                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19973                point_to_lsp(end)
19974            };
19975            let lsp_end = to_lsp(&buffer_position);
19976
19977            let candidates = snippets
19978                .iter()
19979                .enumerate()
19980                .flat_map(|(ix, snippet)| {
19981                    snippet
19982                        .prefix
19983                        .iter()
19984                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19985                })
19986                .collect::<Vec<StringMatchCandidate>>();
19987
19988            let mut matches = fuzzy::match_strings(
19989                &candidates,
19990                &last_word,
19991                last_word.chars().any(|c| c.is_uppercase()),
19992                100,
19993                &Default::default(),
19994                executor.clone(),
19995            )
19996            .await;
19997
19998            // Remove all candidates where the query's start does not match the start of any word in the candidate
19999            if let Some(query_start) = last_word.chars().next() {
20000                matches.retain(|string_match| {
20001                    split_words(&string_match.string).any(|word| {
20002                        // Check that the first codepoint of the word as lowercase matches the first
20003                        // codepoint of the query as lowercase
20004                        word.chars()
20005                            .flat_map(|codepoint| codepoint.to_lowercase())
20006                            .zip(query_start.to_lowercase())
20007                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20008                    })
20009                });
20010            }
20011
20012            let matched_strings = matches
20013                .into_iter()
20014                .map(|m| m.string)
20015                .collect::<HashSet<_>>();
20016
20017            let mut result: Vec<Completion> = snippets
20018                .iter()
20019                .filter_map(|snippet| {
20020                    let matching_prefix = snippet
20021                        .prefix
20022                        .iter()
20023                        .find(|prefix| matched_strings.contains(*prefix))?;
20024                    let start = as_offset - last_word.len();
20025                    let start = snapshot.anchor_before(start);
20026                    let range = start..buffer_position;
20027                    let lsp_start = to_lsp(&start);
20028                    let lsp_range = lsp::Range {
20029                        start: lsp_start,
20030                        end: lsp_end,
20031                    };
20032                    Some(Completion {
20033                        replace_range: range,
20034                        new_text: snippet.body.clone(),
20035                        source: CompletionSource::Lsp {
20036                            insert_range: None,
20037                            server_id: LanguageServerId(usize::MAX),
20038                            resolved: true,
20039                            lsp_completion: Box::new(lsp::CompletionItem {
20040                                label: snippet.prefix.first().unwrap().clone(),
20041                                kind: Some(CompletionItemKind::SNIPPET),
20042                                label_details: snippet.description.as_ref().map(|description| {
20043                                    lsp::CompletionItemLabelDetails {
20044                                        detail: Some(description.clone()),
20045                                        description: None,
20046                                    }
20047                                }),
20048                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20049                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20050                                    lsp::InsertReplaceEdit {
20051                                        new_text: snippet.body.clone(),
20052                                        insert: lsp_range,
20053                                        replace: lsp_range,
20054                                    },
20055                                )),
20056                                filter_text: Some(snippet.body.clone()),
20057                                sort_text: Some(char::MAX.to_string()),
20058                                ..lsp::CompletionItem::default()
20059                            }),
20060                            lsp_defaults: None,
20061                        },
20062                        label: CodeLabel {
20063                            text: matching_prefix.clone(),
20064                            runs: Vec::new(),
20065                            filter_range: 0..matching_prefix.len(),
20066                        },
20067                        icon_path: None,
20068                        documentation: Some(
20069                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20070                                single_line: snippet.name.clone().into(),
20071                                plain_text: snippet
20072                                    .description
20073                                    .clone()
20074                                    .map(|description| description.into()),
20075                            },
20076                        ),
20077                        insert_text_mode: None,
20078                        confirm: None,
20079                    })
20080                })
20081                .collect();
20082
20083            all_results.append(&mut result);
20084        }
20085
20086        Ok(all_results)
20087    })
20088}
20089
20090impl CompletionProvider for Entity<Project> {
20091    fn completions(
20092        &self,
20093        _excerpt_id: ExcerptId,
20094        buffer: &Entity<Buffer>,
20095        buffer_position: text::Anchor,
20096        options: CompletionContext,
20097        _window: &mut Window,
20098        cx: &mut Context<Editor>,
20099    ) -> Task<Result<Option<Vec<Completion>>>> {
20100        self.update(cx, |project, cx| {
20101            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20102            let project_completions = project.completions(buffer, buffer_position, options, cx);
20103            cx.background_spawn(async move {
20104                let snippets_completions = snippets.await?;
20105                match project_completions.await? {
20106                    Some(mut completions) => {
20107                        completions.extend(snippets_completions);
20108                        Ok(Some(completions))
20109                    }
20110                    None => {
20111                        if snippets_completions.is_empty() {
20112                            Ok(None)
20113                        } else {
20114                            Ok(Some(snippets_completions))
20115                        }
20116                    }
20117                }
20118            })
20119        })
20120    }
20121
20122    fn resolve_completions(
20123        &self,
20124        buffer: Entity<Buffer>,
20125        completion_indices: Vec<usize>,
20126        completions: Rc<RefCell<Box<[Completion]>>>,
20127        cx: &mut Context<Editor>,
20128    ) -> Task<Result<bool>> {
20129        self.update(cx, |project, cx| {
20130            project.lsp_store().update(cx, |lsp_store, cx| {
20131                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20132            })
20133        })
20134    }
20135
20136    fn apply_additional_edits_for_completion(
20137        &self,
20138        buffer: Entity<Buffer>,
20139        completions: Rc<RefCell<Box<[Completion]>>>,
20140        completion_index: usize,
20141        push_to_history: bool,
20142        cx: &mut Context<Editor>,
20143    ) -> Task<Result<Option<language::Transaction>>> {
20144        self.update(cx, |project, cx| {
20145            project.lsp_store().update(cx, |lsp_store, cx| {
20146                lsp_store.apply_additional_edits_for_completion(
20147                    buffer,
20148                    completions,
20149                    completion_index,
20150                    push_to_history,
20151                    cx,
20152                )
20153            })
20154        })
20155    }
20156
20157    fn is_completion_trigger(
20158        &self,
20159        buffer: &Entity<Buffer>,
20160        position: language::Anchor,
20161        text: &str,
20162        trigger_in_words: bool,
20163        cx: &mut Context<Editor>,
20164    ) -> bool {
20165        let mut chars = text.chars();
20166        let char = if let Some(char) = chars.next() {
20167            char
20168        } else {
20169            return false;
20170        };
20171        if chars.next().is_some() {
20172            return false;
20173        }
20174
20175        let buffer = buffer.read(cx);
20176        let snapshot = buffer.snapshot();
20177        if !snapshot.settings_at(position, cx).show_completions_on_input {
20178            return false;
20179        }
20180        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20181        if trigger_in_words && classifier.is_word(char) {
20182            return true;
20183        }
20184
20185        buffer.completion_triggers().contains(text)
20186    }
20187}
20188
20189impl SemanticsProvider for Entity<Project> {
20190    fn hover(
20191        &self,
20192        buffer: &Entity<Buffer>,
20193        position: text::Anchor,
20194        cx: &mut App,
20195    ) -> Option<Task<Vec<project::Hover>>> {
20196        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20197    }
20198
20199    fn document_highlights(
20200        &self,
20201        buffer: &Entity<Buffer>,
20202        position: text::Anchor,
20203        cx: &mut App,
20204    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20205        Some(self.update(cx, |project, cx| {
20206            project.document_highlights(buffer, position, cx)
20207        }))
20208    }
20209
20210    fn definitions(
20211        &self,
20212        buffer: &Entity<Buffer>,
20213        position: text::Anchor,
20214        kind: GotoDefinitionKind,
20215        cx: &mut App,
20216    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20217        Some(self.update(cx, |project, cx| match kind {
20218            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20219            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20220            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20221            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20222        }))
20223    }
20224
20225    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20226        // TODO: make this work for remote projects
20227        self.update(cx, |project, cx| {
20228            if project
20229                .active_debug_session(cx)
20230                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20231            {
20232                return true;
20233            }
20234
20235            buffer.update(cx, |buffer, cx| {
20236                project.any_language_server_supports_inlay_hints(buffer, cx)
20237            })
20238        })
20239    }
20240
20241    fn inline_values(
20242        &self,
20243        buffer_handle: Entity<Buffer>,
20244
20245        range: Range<text::Anchor>,
20246        cx: &mut App,
20247    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20248        self.update(cx, |project, cx| {
20249            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20250
20251            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20252        })
20253    }
20254
20255    fn inlay_hints(
20256        &self,
20257        buffer_handle: Entity<Buffer>,
20258        range: Range<text::Anchor>,
20259        cx: &mut App,
20260    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20261        Some(self.update(cx, |project, cx| {
20262            project.inlay_hints(buffer_handle, range, cx)
20263        }))
20264    }
20265
20266    fn resolve_inlay_hint(
20267        &self,
20268        hint: InlayHint,
20269        buffer_handle: Entity<Buffer>,
20270        server_id: LanguageServerId,
20271        cx: &mut App,
20272    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20273        Some(self.update(cx, |project, cx| {
20274            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20275        }))
20276    }
20277
20278    fn range_for_rename(
20279        &self,
20280        buffer: &Entity<Buffer>,
20281        position: text::Anchor,
20282        cx: &mut App,
20283    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20284        Some(self.update(cx, |project, cx| {
20285            let buffer = buffer.clone();
20286            let task = project.prepare_rename(buffer.clone(), position, cx);
20287            cx.spawn(async move |_, cx| {
20288                Ok(match task.await? {
20289                    PrepareRenameResponse::Success(range) => Some(range),
20290                    PrepareRenameResponse::InvalidPosition => None,
20291                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20292                        // Fallback on using TreeSitter info to determine identifier range
20293                        buffer.update(cx, |buffer, _| {
20294                            let snapshot = buffer.snapshot();
20295                            let (range, kind) = snapshot.surrounding_word(position);
20296                            if kind != Some(CharKind::Word) {
20297                                return None;
20298                            }
20299                            Some(
20300                                snapshot.anchor_before(range.start)
20301                                    ..snapshot.anchor_after(range.end),
20302                            )
20303                        })?
20304                    }
20305                })
20306            })
20307        }))
20308    }
20309
20310    fn perform_rename(
20311        &self,
20312        buffer: &Entity<Buffer>,
20313        position: text::Anchor,
20314        new_name: String,
20315        cx: &mut App,
20316    ) -> Option<Task<Result<ProjectTransaction>>> {
20317        Some(self.update(cx, |project, cx| {
20318            project.perform_rename(buffer.clone(), position, new_name, cx)
20319        }))
20320    }
20321}
20322
20323fn inlay_hint_settings(
20324    location: Anchor,
20325    snapshot: &MultiBufferSnapshot,
20326    cx: &mut Context<Editor>,
20327) -> InlayHintSettings {
20328    let file = snapshot.file_at(location);
20329    let language = snapshot.language_at(location).map(|l| l.name());
20330    language_settings(language, file, cx).inlay_hints
20331}
20332
20333fn consume_contiguous_rows(
20334    contiguous_row_selections: &mut Vec<Selection<Point>>,
20335    selection: &Selection<Point>,
20336    display_map: &DisplaySnapshot,
20337    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20338) -> (MultiBufferRow, MultiBufferRow) {
20339    contiguous_row_selections.push(selection.clone());
20340    let start_row = MultiBufferRow(selection.start.row);
20341    let mut end_row = ending_row(selection, display_map);
20342
20343    while let Some(next_selection) = selections.peek() {
20344        if next_selection.start.row <= end_row.0 {
20345            end_row = ending_row(next_selection, display_map);
20346            contiguous_row_selections.push(selections.next().unwrap().clone());
20347        } else {
20348            break;
20349        }
20350    }
20351    (start_row, end_row)
20352}
20353
20354fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20355    if next_selection.end.column > 0 || next_selection.is_empty() {
20356        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20357    } else {
20358        MultiBufferRow(next_selection.end.row)
20359    }
20360}
20361
20362impl EditorSnapshot {
20363    pub fn remote_selections_in_range<'a>(
20364        &'a self,
20365        range: &'a Range<Anchor>,
20366        collaboration_hub: &dyn CollaborationHub,
20367        cx: &'a App,
20368    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20369        let participant_names = collaboration_hub.user_names(cx);
20370        let participant_indices = collaboration_hub.user_participant_indices(cx);
20371        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20372        let collaborators_by_replica_id = collaborators_by_peer_id
20373            .values()
20374            .map(|collaborator| (collaborator.replica_id, collaborator))
20375            .collect::<HashMap<_, _>>();
20376        self.buffer_snapshot
20377            .selections_in_range(range, false)
20378            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20379                if replica_id == AGENT_REPLICA_ID {
20380                    Some(RemoteSelection {
20381                        replica_id,
20382                        selection,
20383                        cursor_shape,
20384                        line_mode,
20385                        collaborator_id: CollaboratorId::Agent,
20386                        user_name: Some("Agent".into()),
20387                        color: cx.theme().players().agent(),
20388                    })
20389                } else {
20390                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20391                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20392                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20393                    Some(RemoteSelection {
20394                        replica_id,
20395                        selection,
20396                        cursor_shape,
20397                        line_mode,
20398                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20399                        user_name,
20400                        color: if let Some(index) = participant_index {
20401                            cx.theme().players().color_for_participant(index.0)
20402                        } else {
20403                            cx.theme().players().absent()
20404                        },
20405                    })
20406                }
20407            })
20408    }
20409
20410    pub fn hunks_for_ranges(
20411        &self,
20412        ranges: impl IntoIterator<Item = Range<Point>>,
20413    ) -> Vec<MultiBufferDiffHunk> {
20414        let mut hunks = Vec::new();
20415        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20416            HashMap::default();
20417        for query_range in ranges {
20418            let query_rows =
20419                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20420            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20421                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20422            ) {
20423                // Include deleted hunks that are adjacent to the query range, because
20424                // otherwise they would be missed.
20425                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20426                if hunk.status().is_deleted() {
20427                    intersects_range |= hunk.row_range.start == query_rows.end;
20428                    intersects_range |= hunk.row_range.end == query_rows.start;
20429                }
20430                if intersects_range {
20431                    if !processed_buffer_rows
20432                        .entry(hunk.buffer_id)
20433                        .or_default()
20434                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20435                    {
20436                        continue;
20437                    }
20438                    hunks.push(hunk);
20439                }
20440            }
20441        }
20442
20443        hunks
20444    }
20445
20446    fn display_diff_hunks_for_rows<'a>(
20447        &'a self,
20448        display_rows: Range<DisplayRow>,
20449        folded_buffers: &'a HashSet<BufferId>,
20450    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20451        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20452        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20453
20454        self.buffer_snapshot
20455            .diff_hunks_in_range(buffer_start..buffer_end)
20456            .filter_map(|hunk| {
20457                if folded_buffers.contains(&hunk.buffer_id) {
20458                    return None;
20459                }
20460
20461                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20462                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20463
20464                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20465                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20466
20467                let display_hunk = if hunk_display_start.column() != 0 {
20468                    DisplayDiffHunk::Folded {
20469                        display_row: hunk_display_start.row(),
20470                    }
20471                } else {
20472                    let mut end_row = hunk_display_end.row();
20473                    if hunk_display_end.column() > 0 {
20474                        end_row.0 += 1;
20475                    }
20476                    let is_created_file = hunk.is_created_file();
20477                    DisplayDiffHunk::Unfolded {
20478                        status: hunk.status(),
20479                        diff_base_byte_range: hunk.diff_base_byte_range,
20480                        display_row_range: hunk_display_start.row()..end_row,
20481                        multi_buffer_range: Anchor::range_in_buffer(
20482                            hunk.excerpt_id,
20483                            hunk.buffer_id,
20484                            hunk.buffer_range,
20485                        ),
20486                        is_created_file,
20487                    }
20488                };
20489
20490                Some(display_hunk)
20491            })
20492    }
20493
20494    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20495        self.display_snapshot.buffer_snapshot.language_at(position)
20496    }
20497
20498    pub fn is_focused(&self) -> bool {
20499        self.is_focused
20500    }
20501
20502    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20503        self.placeholder_text.as_ref()
20504    }
20505
20506    pub fn scroll_position(&self) -> gpui::Point<f32> {
20507        self.scroll_anchor.scroll_position(&self.display_snapshot)
20508    }
20509
20510    fn gutter_dimensions(
20511        &self,
20512        font_id: FontId,
20513        font_size: Pixels,
20514        max_line_number_width: Pixels,
20515        cx: &App,
20516    ) -> Option<GutterDimensions> {
20517        if !self.show_gutter {
20518            return None;
20519        }
20520
20521        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20522        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20523
20524        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20525            matches!(
20526                ProjectSettings::get_global(cx).git.git_gutter,
20527                Some(GitGutterSetting::TrackedFiles)
20528            )
20529        });
20530        let gutter_settings = EditorSettings::get_global(cx).gutter;
20531        let show_line_numbers = self
20532            .show_line_numbers
20533            .unwrap_or(gutter_settings.line_numbers);
20534        let line_gutter_width = if show_line_numbers {
20535            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20536            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20537            max_line_number_width.max(min_width_for_number_on_gutter)
20538        } else {
20539            0.0.into()
20540        };
20541
20542        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20543        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20544
20545        let git_blame_entries_width =
20546            self.git_blame_gutter_max_author_length
20547                .map(|max_author_length| {
20548                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20549                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20550
20551                    /// The number of characters to dedicate to gaps and margins.
20552                    const SPACING_WIDTH: usize = 4;
20553
20554                    let max_char_count = max_author_length.min(renderer.max_author_length())
20555                        + ::git::SHORT_SHA_LENGTH
20556                        + MAX_RELATIVE_TIMESTAMP.len()
20557                        + SPACING_WIDTH;
20558
20559                    em_advance * max_char_count
20560                });
20561
20562        let is_singleton = self.buffer_snapshot.is_singleton();
20563
20564        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20565        left_padding += if !is_singleton {
20566            em_width * 4.0
20567        } else if show_runnables || show_breakpoints {
20568            em_width * 3.0
20569        } else if show_git_gutter && show_line_numbers {
20570            em_width * 2.0
20571        } else if show_git_gutter || show_line_numbers {
20572            em_width
20573        } else {
20574            px(0.)
20575        };
20576
20577        let shows_folds = is_singleton && gutter_settings.folds;
20578
20579        let right_padding = if shows_folds && show_line_numbers {
20580            em_width * 4.0
20581        } else if shows_folds || (!is_singleton && show_line_numbers) {
20582            em_width * 3.0
20583        } else if show_line_numbers {
20584            em_width
20585        } else {
20586            px(0.)
20587        };
20588
20589        Some(GutterDimensions {
20590            left_padding,
20591            right_padding,
20592            width: line_gutter_width + left_padding + right_padding,
20593            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20594            git_blame_entries_width,
20595        })
20596    }
20597
20598    pub fn render_crease_toggle(
20599        &self,
20600        buffer_row: MultiBufferRow,
20601        row_contains_cursor: bool,
20602        editor: Entity<Editor>,
20603        window: &mut Window,
20604        cx: &mut App,
20605    ) -> Option<AnyElement> {
20606        let folded = self.is_line_folded(buffer_row);
20607        let mut is_foldable = false;
20608
20609        if let Some(crease) = self
20610            .crease_snapshot
20611            .query_row(buffer_row, &self.buffer_snapshot)
20612        {
20613            is_foldable = true;
20614            match crease {
20615                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20616                    if let Some(render_toggle) = render_toggle {
20617                        let toggle_callback =
20618                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20619                                if folded {
20620                                    editor.update(cx, |editor, cx| {
20621                                        editor.fold_at(buffer_row, window, cx)
20622                                    });
20623                                } else {
20624                                    editor.update(cx, |editor, cx| {
20625                                        editor.unfold_at(buffer_row, window, cx)
20626                                    });
20627                                }
20628                            });
20629                        return Some((render_toggle)(
20630                            buffer_row,
20631                            folded,
20632                            toggle_callback,
20633                            window,
20634                            cx,
20635                        ));
20636                    }
20637                }
20638            }
20639        }
20640
20641        is_foldable |= self.starts_indent(buffer_row);
20642
20643        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20644            Some(
20645                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20646                    .toggle_state(folded)
20647                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20648                        if folded {
20649                            this.unfold_at(buffer_row, window, cx);
20650                        } else {
20651                            this.fold_at(buffer_row, window, cx);
20652                        }
20653                    }))
20654                    .into_any_element(),
20655            )
20656        } else {
20657            None
20658        }
20659    }
20660
20661    pub fn render_crease_trailer(
20662        &self,
20663        buffer_row: MultiBufferRow,
20664        window: &mut Window,
20665        cx: &mut App,
20666    ) -> Option<AnyElement> {
20667        let folded = self.is_line_folded(buffer_row);
20668        if let Crease::Inline { render_trailer, .. } = self
20669            .crease_snapshot
20670            .query_row(buffer_row, &self.buffer_snapshot)?
20671        {
20672            let render_trailer = render_trailer.as_ref()?;
20673            Some(render_trailer(buffer_row, folded, window, cx))
20674        } else {
20675            None
20676        }
20677    }
20678}
20679
20680impl Deref for EditorSnapshot {
20681    type Target = DisplaySnapshot;
20682
20683    fn deref(&self) -> &Self::Target {
20684        &self.display_snapshot
20685    }
20686}
20687
20688#[derive(Clone, Debug, PartialEq, Eq)]
20689pub enum EditorEvent {
20690    InputIgnored {
20691        text: Arc<str>,
20692    },
20693    InputHandled {
20694        utf16_range_to_replace: Option<Range<isize>>,
20695        text: Arc<str>,
20696    },
20697    ExcerptsAdded {
20698        buffer: Entity<Buffer>,
20699        predecessor: ExcerptId,
20700        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20701    },
20702    ExcerptsRemoved {
20703        ids: Vec<ExcerptId>,
20704        removed_buffer_ids: Vec<BufferId>,
20705    },
20706    BufferFoldToggled {
20707        ids: Vec<ExcerptId>,
20708        folded: bool,
20709    },
20710    ExcerptsEdited {
20711        ids: Vec<ExcerptId>,
20712    },
20713    ExcerptsExpanded {
20714        ids: Vec<ExcerptId>,
20715    },
20716    BufferEdited,
20717    Edited {
20718        transaction_id: clock::Lamport,
20719    },
20720    Reparsed(BufferId),
20721    Focused,
20722    FocusedIn,
20723    Blurred,
20724    DirtyChanged,
20725    Saved,
20726    TitleChanged,
20727    DiffBaseChanged,
20728    SelectionsChanged {
20729        local: bool,
20730    },
20731    ScrollPositionChanged {
20732        local: bool,
20733        autoscroll: bool,
20734    },
20735    Closed,
20736    TransactionUndone {
20737        transaction_id: clock::Lamport,
20738    },
20739    TransactionBegun {
20740        transaction_id: clock::Lamport,
20741    },
20742    Reloaded,
20743    CursorShapeChanged,
20744    PushedToNavHistory {
20745        anchor: Anchor,
20746        is_deactivate: bool,
20747    },
20748}
20749
20750impl EventEmitter<EditorEvent> for Editor {}
20751
20752impl Focusable for Editor {
20753    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20754        self.focus_handle.clone()
20755    }
20756}
20757
20758impl Render for Editor {
20759    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20760        let settings = ThemeSettings::get_global(cx);
20761
20762        let mut text_style = match self.mode {
20763            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20764                color: cx.theme().colors().editor_foreground,
20765                font_family: settings.ui_font.family.clone(),
20766                font_features: settings.ui_font.features.clone(),
20767                font_fallbacks: settings.ui_font.fallbacks.clone(),
20768                font_size: rems(0.875).into(),
20769                font_weight: settings.ui_font.weight,
20770                line_height: relative(settings.buffer_line_height.value()),
20771                ..Default::default()
20772            },
20773            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20774                color: cx.theme().colors().editor_foreground,
20775                font_family: settings.buffer_font.family.clone(),
20776                font_features: settings.buffer_font.features.clone(),
20777                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20778                font_size: settings.buffer_font_size(cx).into(),
20779                font_weight: settings.buffer_font.weight,
20780                line_height: relative(settings.buffer_line_height.value()),
20781                ..Default::default()
20782            },
20783        };
20784        if let Some(text_style_refinement) = &self.text_style_refinement {
20785            text_style.refine(text_style_refinement)
20786        }
20787
20788        let background = match self.mode {
20789            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20790            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20791            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20792            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20793        };
20794
20795        EditorElement::new(
20796            &cx.entity(),
20797            EditorStyle {
20798                background,
20799                local_player: cx.theme().players().local(),
20800                text: text_style,
20801                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20802                syntax: cx.theme().syntax().clone(),
20803                status: cx.theme().status().clone(),
20804                inlay_hints_style: make_inlay_hints_style(cx),
20805                inline_completion_styles: make_suggestion_styles(cx),
20806                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20807                show_underlines: !self.mode.is_minimap(),
20808            },
20809        )
20810    }
20811}
20812
20813impl EntityInputHandler for Editor {
20814    fn text_for_range(
20815        &mut self,
20816        range_utf16: Range<usize>,
20817        adjusted_range: &mut Option<Range<usize>>,
20818        _: &mut Window,
20819        cx: &mut Context<Self>,
20820    ) -> Option<String> {
20821        let snapshot = self.buffer.read(cx).read(cx);
20822        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20823        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20824        if (start.0..end.0) != range_utf16 {
20825            adjusted_range.replace(start.0..end.0);
20826        }
20827        Some(snapshot.text_for_range(start..end).collect())
20828    }
20829
20830    fn selected_text_range(
20831        &mut self,
20832        ignore_disabled_input: bool,
20833        _: &mut Window,
20834        cx: &mut Context<Self>,
20835    ) -> Option<UTF16Selection> {
20836        // Prevent the IME menu from appearing when holding down an alphabetic key
20837        // while input is disabled.
20838        if !ignore_disabled_input && !self.input_enabled {
20839            return None;
20840        }
20841
20842        let selection = self.selections.newest::<OffsetUtf16>(cx);
20843        let range = selection.range();
20844
20845        Some(UTF16Selection {
20846            range: range.start.0..range.end.0,
20847            reversed: selection.reversed,
20848        })
20849    }
20850
20851    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20852        let snapshot = self.buffer.read(cx).read(cx);
20853        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20854        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20855    }
20856
20857    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20858        self.clear_highlights::<InputComposition>(cx);
20859        self.ime_transaction.take();
20860    }
20861
20862    fn replace_text_in_range(
20863        &mut self,
20864        range_utf16: Option<Range<usize>>,
20865        text: &str,
20866        window: &mut Window,
20867        cx: &mut Context<Self>,
20868    ) {
20869        if !self.input_enabled {
20870            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20871            return;
20872        }
20873
20874        self.transact(window, cx, |this, window, cx| {
20875            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20876                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20877                Some(this.selection_replacement_ranges(range_utf16, cx))
20878            } else {
20879                this.marked_text_ranges(cx)
20880            };
20881
20882            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20883                let newest_selection_id = this.selections.newest_anchor().id;
20884                this.selections
20885                    .all::<OffsetUtf16>(cx)
20886                    .iter()
20887                    .zip(ranges_to_replace.iter())
20888                    .find_map(|(selection, range)| {
20889                        if selection.id == newest_selection_id {
20890                            Some(
20891                                (range.start.0 as isize - selection.head().0 as isize)
20892                                    ..(range.end.0 as isize - selection.head().0 as isize),
20893                            )
20894                        } else {
20895                            None
20896                        }
20897                    })
20898            });
20899
20900            cx.emit(EditorEvent::InputHandled {
20901                utf16_range_to_replace: range_to_replace,
20902                text: text.into(),
20903            });
20904
20905            if let Some(new_selected_ranges) = new_selected_ranges {
20906                this.change_selections(None, window, cx, |selections| {
20907                    selections.select_ranges(new_selected_ranges)
20908                });
20909                this.backspace(&Default::default(), window, cx);
20910            }
20911
20912            this.handle_input(text, window, cx);
20913        });
20914
20915        if let Some(transaction) = self.ime_transaction {
20916            self.buffer.update(cx, |buffer, cx| {
20917                buffer.group_until_transaction(transaction, cx);
20918            });
20919        }
20920
20921        self.unmark_text(window, cx);
20922    }
20923
20924    fn replace_and_mark_text_in_range(
20925        &mut self,
20926        range_utf16: Option<Range<usize>>,
20927        text: &str,
20928        new_selected_range_utf16: Option<Range<usize>>,
20929        window: &mut Window,
20930        cx: &mut Context<Self>,
20931    ) {
20932        if !self.input_enabled {
20933            return;
20934        }
20935
20936        let transaction = self.transact(window, cx, |this, window, cx| {
20937            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20938                let snapshot = this.buffer.read(cx).read(cx);
20939                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20940                    for marked_range in &mut marked_ranges {
20941                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20942                        marked_range.start.0 += relative_range_utf16.start;
20943                        marked_range.start =
20944                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20945                        marked_range.end =
20946                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20947                    }
20948                }
20949                Some(marked_ranges)
20950            } else if let Some(range_utf16) = range_utf16 {
20951                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20952                Some(this.selection_replacement_ranges(range_utf16, cx))
20953            } else {
20954                None
20955            };
20956
20957            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20958                let newest_selection_id = this.selections.newest_anchor().id;
20959                this.selections
20960                    .all::<OffsetUtf16>(cx)
20961                    .iter()
20962                    .zip(ranges_to_replace.iter())
20963                    .find_map(|(selection, range)| {
20964                        if selection.id == newest_selection_id {
20965                            Some(
20966                                (range.start.0 as isize - selection.head().0 as isize)
20967                                    ..(range.end.0 as isize - selection.head().0 as isize),
20968                            )
20969                        } else {
20970                            None
20971                        }
20972                    })
20973            });
20974
20975            cx.emit(EditorEvent::InputHandled {
20976                utf16_range_to_replace: range_to_replace,
20977                text: text.into(),
20978            });
20979
20980            if let Some(ranges) = ranges_to_replace {
20981                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20982            }
20983
20984            let marked_ranges = {
20985                let snapshot = this.buffer.read(cx).read(cx);
20986                this.selections
20987                    .disjoint_anchors()
20988                    .iter()
20989                    .map(|selection| {
20990                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20991                    })
20992                    .collect::<Vec<_>>()
20993            };
20994
20995            if text.is_empty() {
20996                this.unmark_text(window, cx);
20997            } else {
20998                this.highlight_text::<InputComposition>(
20999                    marked_ranges.clone(),
21000                    HighlightStyle {
21001                        underline: Some(UnderlineStyle {
21002                            thickness: px(1.),
21003                            color: None,
21004                            wavy: false,
21005                        }),
21006                        ..Default::default()
21007                    },
21008                    cx,
21009                );
21010            }
21011
21012            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21013            let use_autoclose = this.use_autoclose;
21014            let use_auto_surround = this.use_auto_surround;
21015            this.set_use_autoclose(false);
21016            this.set_use_auto_surround(false);
21017            this.handle_input(text, window, cx);
21018            this.set_use_autoclose(use_autoclose);
21019            this.set_use_auto_surround(use_auto_surround);
21020
21021            if let Some(new_selected_range) = new_selected_range_utf16 {
21022                let snapshot = this.buffer.read(cx).read(cx);
21023                let new_selected_ranges = marked_ranges
21024                    .into_iter()
21025                    .map(|marked_range| {
21026                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21027                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21028                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21029                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21030                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21031                    })
21032                    .collect::<Vec<_>>();
21033
21034                drop(snapshot);
21035                this.change_selections(None, window, cx, |selections| {
21036                    selections.select_ranges(new_selected_ranges)
21037                });
21038            }
21039        });
21040
21041        self.ime_transaction = self.ime_transaction.or(transaction);
21042        if let Some(transaction) = self.ime_transaction {
21043            self.buffer.update(cx, |buffer, cx| {
21044                buffer.group_until_transaction(transaction, cx);
21045            });
21046        }
21047
21048        if self.text_highlights::<InputComposition>(cx).is_none() {
21049            self.ime_transaction.take();
21050        }
21051    }
21052
21053    fn bounds_for_range(
21054        &mut self,
21055        range_utf16: Range<usize>,
21056        element_bounds: gpui::Bounds<Pixels>,
21057        window: &mut Window,
21058        cx: &mut Context<Self>,
21059    ) -> Option<gpui::Bounds<Pixels>> {
21060        let text_layout_details = self.text_layout_details(window);
21061        let gpui::Size {
21062            width: em_width,
21063            height: line_height,
21064        } = self.character_size(window);
21065
21066        let snapshot = self.snapshot(window, cx);
21067        let scroll_position = snapshot.scroll_position();
21068        let scroll_left = scroll_position.x * em_width;
21069
21070        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21071        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21072            + self.gutter_dimensions.width
21073            + self.gutter_dimensions.margin;
21074        let y = line_height * (start.row().as_f32() - scroll_position.y);
21075
21076        Some(Bounds {
21077            origin: element_bounds.origin + point(x, y),
21078            size: size(em_width, line_height),
21079        })
21080    }
21081
21082    fn character_index_for_point(
21083        &mut self,
21084        point: gpui::Point<Pixels>,
21085        _window: &mut Window,
21086        _cx: &mut Context<Self>,
21087    ) -> Option<usize> {
21088        let position_map = self.last_position_map.as_ref()?;
21089        if !position_map.text_hitbox.contains(&point) {
21090            return None;
21091        }
21092        let display_point = position_map.point_for_position(point).previous_valid;
21093        let anchor = position_map
21094            .snapshot
21095            .display_point_to_anchor(display_point, Bias::Left);
21096        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21097        Some(utf16_offset.0)
21098    }
21099}
21100
21101trait SelectionExt {
21102    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21103    fn spanned_rows(
21104        &self,
21105        include_end_if_at_line_start: bool,
21106        map: &DisplaySnapshot,
21107    ) -> Range<MultiBufferRow>;
21108}
21109
21110impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21111    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21112        let start = self
21113            .start
21114            .to_point(&map.buffer_snapshot)
21115            .to_display_point(map);
21116        let end = self
21117            .end
21118            .to_point(&map.buffer_snapshot)
21119            .to_display_point(map);
21120        if self.reversed {
21121            end..start
21122        } else {
21123            start..end
21124        }
21125    }
21126
21127    fn spanned_rows(
21128        &self,
21129        include_end_if_at_line_start: bool,
21130        map: &DisplaySnapshot,
21131    ) -> Range<MultiBufferRow> {
21132        let start = self.start.to_point(&map.buffer_snapshot);
21133        let mut end = self.end.to_point(&map.buffer_snapshot);
21134        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21135            end.row -= 1;
21136        }
21137
21138        let buffer_start = map.prev_line_boundary(start).0;
21139        let buffer_end = map.next_line_boundary(end).0;
21140        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21141    }
21142}
21143
21144impl<T: InvalidationRegion> InvalidationStack<T> {
21145    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21146    where
21147        S: Clone + ToOffset,
21148    {
21149        while let Some(region) = self.last() {
21150            let all_selections_inside_invalidation_ranges =
21151                if selections.len() == region.ranges().len() {
21152                    selections
21153                        .iter()
21154                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21155                        .all(|(selection, invalidation_range)| {
21156                            let head = selection.head().to_offset(buffer);
21157                            invalidation_range.start <= head && invalidation_range.end >= head
21158                        })
21159                } else {
21160                    false
21161                };
21162
21163            if all_selections_inside_invalidation_ranges {
21164                break;
21165            } else {
21166                self.pop();
21167            }
21168        }
21169    }
21170}
21171
21172impl<T> Default for InvalidationStack<T> {
21173    fn default() -> Self {
21174        Self(Default::default())
21175    }
21176}
21177
21178impl<T> Deref for InvalidationStack<T> {
21179    type Target = Vec<T>;
21180
21181    fn deref(&self) -> &Self::Target {
21182        &self.0
21183    }
21184}
21185
21186impl<T> DerefMut for InvalidationStack<T> {
21187    fn deref_mut(&mut self) -> &mut Self::Target {
21188        &mut self.0
21189    }
21190}
21191
21192impl InvalidationRegion for SnippetState {
21193    fn ranges(&self) -> &[Range<Anchor>] {
21194        &self.ranges[self.active_index]
21195    }
21196}
21197
21198fn inline_completion_edit_text(
21199    current_snapshot: &BufferSnapshot,
21200    edits: &[(Range<Anchor>, String)],
21201    edit_preview: &EditPreview,
21202    include_deletions: bool,
21203    cx: &App,
21204) -> HighlightedText {
21205    let edits = edits
21206        .iter()
21207        .map(|(anchor, text)| {
21208            (
21209                anchor.start.text_anchor..anchor.end.text_anchor,
21210                text.clone(),
21211            )
21212        })
21213        .collect::<Vec<_>>();
21214
21215    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21216}
21217
21218pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21219    match severity {
21220        lsp::DiagnosticSeverity::ERROR => colors.error,
21221        lsp::DiagnosticSeverity::WARNING => colors.warning,
21222        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21223        lsp::DiagnosticSeverity::HINT => colors.info,
21224        _ => colors.ignored,
21225    }
21226}
21227
21228pub fn styled_runs_for_code_label<'a>(
21229    label: &'a CodeLabel,
21230    syntax_theme: &'a theme::SyntaxTheme,
21231) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21232    let fade_out = HighlightStyle {
21233        fade_out: Some(0.35),
21234        ..Default::default()
21235    };
21236
21237    let mut prev_end = label.filter_range.end;
21238    label
21239        .runs
21240        .iter()
21241        .enumerate()
21242        .flat_map(move |(ix, (range, highlight_id))| {
21243            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21244                style
21245            } else {
21246                return Default::default();
21247            };
21248            let mut muted_style = style;
21249            muted_style.highlight(fade_out);
21250
21251            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21252            if range.start >= label.filter_range.end {
21253                if range.start > prev_end {
21254                    runs.push((prev_end..range.start, fade_out));
21255                }
21256                runs.push((range.clone(), muted_style));
21257            } else if range.end <= label.filter_range.end {
21258                runs.push((range.clone(), style));
21259            } else {
21260                runs.push((range.start..label.filter_range.end, style));
21261                runs.push((label.filter_range.end..range.end, muted_style));
21262            }
21263            prev_end = cmp::max(prev_end, range.end);
21264
21265            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21266                runs.push((prev_end..label.text.len(), fade_out));
21267            }
21268
21269            runs
21270        })
21271}
21272
21273pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21274    let mut prev_index = 0;
21275    let mut prev_codepoint: Option<char> = None;
21276    text.char_indices()
21277        .chain([(text.len(), '\0')])
21278        .filter_map(move |(index, codepoint)| {
21279            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21280            let is_boundary = index == text.len()
21281                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21282                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21283            if is_boundary {
21284                let chunk = &text[prev_index..index];
21285                prev_index = index;
21286                Some(chunk)
21287            } else {
21288                None
21289            }
21290        })
21291}
21292
21293pub trait RangeToAnchorExt: Sized {
21294    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21295
21296    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21297        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21298        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21299    }
21300}
21301
21302impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21303    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21304        let start_offset = self.start.to_offset(snapshot);
21305        let end_offset = self.end.to_offset(snapshot);
21306        if start_offset == end_offset {
21307            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21308        } else {
21309            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21310        }
21311    }
21312}
21313
21314pub trait RowExt {
21315    fn as_f32(&self) -> f32;
21316
21317    fn next_row(&self) -> Self;
21318
21319    fn previous_row(&self) -> Self;
21320
21321    fn minus(&self, other: Self) -> u32;
21322}
21323
21324impl RowExt for DisplayRow {
21325    fn as_f32(&self) -> f32 {
21326        self.0 as f32
21327    }
21328
21329    fn next_row(&self) -> Self {
21330        Self(self.0 + 1)
21331    }
21332
21333    fn previous_row(&self) -> Self {
21334        Self(self.0.saturating_sub(1))
21335    }
21336
21337    fn minus(&self, other: Self) -> u32 {
21338        self.0 - other.0
21339    }
21340}
21341
21342impl RowExt for MultiBufferRow {
21343    fn as_f32(&self) -> f32 {
21344        self.0 as f32
21345    }
21346
21347    fn next_row(&self) -> Self {
21348        Self(self.0 + 1)
21349    }
21350
21351    fn previous_row(&self) -> Self {
21352        Self(self.0.saturating_sub(1))
21353    }
21354
21355    fn minus(&self, other: Self) -> u32 {
21356        self.0 - other.0
21357    }
21358}
21359
21360trait RowRangeExt {
21361    type Row;
21362
21363    fn len(&self) -> usize;
21364
21365    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21366}
21367
21368impl RowRangeExt for Range<MultiBufferRow> {
21369    type Row = MultiBufferRow;
21370
21371    fn len(&self) -> usize {
21372        (self.end.0 - self.start.0) as usize
21373    }
21374
21375    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21376        (self.start.0..self.end.0).map(MultiBufferRow)
21377    }
21378}
21379
21380impl RowRangeExt for Range<DisplayRow> {
21381    type Row = DisplayRow;
21382
21383    fn len(&self) -> usize {
21384        (self.end.0 - self.start.0) as usize
21385    }
21386
21387    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21388        (self.start.0..self.end.0).map(DisplayRow)
21389    }
21390}
21391
21392/// If select range has more than one line, we
21393/// just point the cursor to range.start.
21394fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21395    if range.start.row == range.end.row {
21396        range
21397    } else {
21398        range.start..range.start
21399    }
21400}
21401pub struct KillRing(ClipboardItem);
21402impl Global for KillRing {}
21403
21404const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21405
21406enum BreakpointPromptEditAction {
21407    Log,
21408    Condition,
21409    HitCondition,
21410}
21411
21412struct BreakpointPromptEditor {
21413    pub(crate) prompt: Entity<Editor>,
21414    editor: WeakEntity<Editor>,
21415    breakpoint_anchor: Anchor,
21416    breakpoint: Breakpoint,
21417    edit_action: BreakpointPromptEditAction,
21418    block_ids: HashSet<CustomBlockId>,
21419    editor_margins: Arc<Mutex<EditorMargins>>,
21420    _subscriptions: Vec<Subscription>,
21421}
21422
21423impl BreakpointPromptEditor {
21424    const MAX_LINES: u8 = 4;
21425
21426    fn new(
21427        editor: WeakEntity<Editor>,
21428        breakpoint_anchor: Anchor,
21429        breakpoint: Breakpoint,
21430        edit_action: BreakpointPromptEditAction,
21431        window: &mut Window,
21432        cx: &mut Context<Self>,
21433    ) -> Self {
21434        let base_text = match edit_action {
21435            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21436            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21437            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21438        }
21439        .map(|msg| msg.to_string())
21440        .unwrap_or_default();
21441
21442        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21443        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21444
21445        let prompt = cx.new(|cx| {
21446            let mut prompt = Editor::new(
21447                EditorMode::AutoHeight {
21448                    max_lines: Self::MAX_LINES as usize,
21449                },
21450                buffer,
21451                None,
21452                window,
21453                cx,
21454            );
21455            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21456            prompt.set_show_cursor_when_unfocused(false, cx);
21457            prompt.set_placeholder_text(
21458                match edit_action {
21459                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21460                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21461                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21462                },
21463                cx,
21464            );
21465
21466            prompt
21467        });
21468
21469        Self {
21470            prompt,
21471            editor,
21472            breakpoint_anchor,
21473            breakpoint,
21474            edit_action,
21475            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21476            block_ids: Default::default(),
21477            _subscriptions: vec![],
21478        }
21479    }
21480
21481    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21482        self.block_ids.extend(block_ids)
21483    }
21484
21485    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21486        if let Some(editor) = self.editor.upgrade() {
21487            let message = self
21488                .prompt
21489                .read(cx)
21490                .buffer
21491                .read(cx)
21492                .as_singleton()
21493                .expect("A multi buffer in breakpoint prompt isn't possible")
21494                .read(cx)
21495                .as_rope()
21496                .to_string();
21497
21498            editor.update(cx, |editor, cx| {
21499                editor.edit_breakpoint_at_anchor(
21500                    self.breakpoint_anchor,
21501                    self.breakpoint.clone(),
21502                    match self.edit_action {
21503                        BreakpointPromptEditAction::Log => {
21504                            BreakpointEditAction::EditLogMessage(message.into())
21505                        }
21506                        BreakpointPromptEditAction::Condition => {
21507                            BreakpointEditAction::EditCondition(message.into())
21508                        }
21509                        BreakpointPromptEditAction::HitCondition => {
21510                            BreakpointEditAction::EditHitCondition(message.into())
21511                        }
21512                    },
21513                    cx,
21514                );
21515
21516                editor.remove_blocks(self.block_ids.clone(), None, cx);
21517                cx.focus_self(window);
21518            });
21519        }
21520    }
21521
21522    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21523        self.editor
21524            .update(cx, |editor, cx| {
21525                editor.remove_blocks(self.block_ids.clone(), None, cx);
21526                window.focus(&editor.focus_handle);
21527            })
21528            .log_err();
21529    }
21530
21531    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21532        let settings = ThemeSettings::get_global(cx);
21533        let text_style = TextStyle {
21534            color: if self.prompt.read(cx).read_only(cx) {
21535                cx.theme().colors().text_disabled
21536            } else {
21537                cx.theme().colors().text
21538            },
21539            font_family: settings.buffer_font.family.clone(),
21540            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21541            font_size: settings.buffer_font_size(cx).into(),
21542            font_weight: settings.buffer_font.weight,
21543            line_height: relative(settings.buffer_line_height.value()),
21544            ..Default::default()
21545        };
21546        EditorElement::new(
21547            &self.prompt,
21548            EditorStyle {
21549                background: cx.theme().colors().editor_background,
21550                local_player: cx.theme().players().local(),
21551                text: text_style,
21552                ..Default::default()
21553            },
21554        )
21555    }
21556}
21557
21558impl Render for BreakpointPromptEditor {
21559    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21560        let editor_margins = *self.editor_margins.lock();
21561        let gutter_dimensions = editor_margins.gutter;
21562        h_flex()
21563            .key_context("Editor")
21564            .bg(cx.theme().colors().editor_background)
21565            .border_y_1()
21566            .border_color(cx.theme().status().info_border)
21567            .size_full()
21568            .py(window.line_height() / 2.5)
21569            .on_action(cx.listener(Self::confirm))
21570            .on_action(cx.listener(Self::cancel))
21571            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21572            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21573    }
21574}
21575
21576impl Focusable for BreakpointPromptEditor {
21577    fn focus_handle(&self, cx: &App) -> FocusHandle {
21578        self.prompt.focus_handle(cx)
21579    }
21580}
21581
21582fn all_edits_insertions_or_deletions(
21583    edits: &Vec<(Range<Anchor>, String)>,
21584    snapshot: &MultiBufferSnapshot,
21585) -> bool {
21586    let mut all_insertions = true;
21587    let mut all_deletions = true;
21588
21589    for (range, new_text) in edits.iter() {
21590        let range_is_empty = range.to_offset(&snapshot).is_empty();
21591        let text_is_empty = new_text.is_empty();
21592
21593        if range_is_empty != text_is_empty {
21594            if range_is_empty {
21595                all_deletions = false;
21596            } else {
21597                all_insertions = false;
21598            }
21599        } else {
21600            return false;
21601        }
21602
21603        if !all_insertions && !all_deletions {
21604            return false;
21605        }
21606    }
21607    all_insertions || all_deletions
21608}
21609
21610struct MissingEditPredictionKeybindingTooltip;
21611
21612impl Render for MissingEditPredictionKeybindingTooltip {
21613    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21614        ui::tooltip_container(window, cx, |container, _, cx| {
21615            container
21616                .flex_shrink_0()
21617                .max_w_80()
21618                .min_h(rems_from_px(124.))
21619                .justify_between()
21620                .child(
21621                    v_flex()
21622                        .flex_1()
21623                        .text_ui_sm(cx)
21624                        .child(Label::new("Conflict with Accept Keybinding"))
21625                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21626                )
21627                .child(
21628                    h_flex()
21629                        .pb_1()
21630                        .gap_1()
21631                        .items_end()
21632                        .w_full()
21633                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21634                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21635                        }))
21636                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21637                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21638                        })),
21639                )
21640        })
21641    }
21642}
21643
21644#[derive(Debug, Clone, Copy, PartialEq)]
21645pub struct LineHighlight {
21646    pub background: Background,
21647    pub border: Option<gpui::Hsla>,
21648    pub include_gutter: bool,
21649    pub type_id: Option<TypeId>,
21650}
21651
21652fn render_diff_hunk_controls(
21653    row: u32,
21654    status: &DiffHunkStatus,
21655    hunk_range: Range<Anchor>,
21656    is_created_file: bool,
21657    line_height: Pixels,
21658    editor: &Entity<Editor>,
21659    _window: &mut Window,
21660    cx: &mut App,
21661) -> AnyElement {
21662    h_flex()
21663        .h(line_height)
21664        .mr_1()
21665        .gap_1()
21666        .px_0p5()
21667        .pb_1()
21668        .border_x_1()
21669        .border_b_1()
21670        .border_color(cx.theme().colors().border_variant)
21671        .rounded_b_lg()
21672        .bg(cx.theme().colors().editor_background)
21673        .gap_1()
21674        .occlude()
21675        .shadow_md()
21676        .child(if status.has_secondary_hunk() {
21677            Button::new(("stage", row as u64), "Stage")
21678                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21679                .tooltip({
21680                    let focus_handle = editor.focus_handle(cx);
21681                    move |window, cx| {
21682                        Tooltip::for_action_in(
21683                            "Stage Hunk",
21684                            &::git::ToggleStaged,
21685                            &focus_handle,
21686                            window,
21687                            cx,
21688                        )
21689                    }
21690                })
21691                .on_click({
21692                    let editor = editor.clone();
21693                    move |_event, _window, cx| {
21694                        editor.update(cx, |editor, cx| {
21695                            editor.stage_or_unstage_diff_hunks(
21696                                true,
21697                                vec![hunk_range.start..hunk_range.start],
21698                                cx,
21699                            );
21700                        });
21701                    }
21702                })
21703        } else {
21704            Button::new(("unstage", row as u64), "Unstage")
21705                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21706                .tooltip({
21707                    let focus_handle = editor.focus_handle(cx);
21708                    move |window, cx| {
21709                        Tooltip::for_action_in(
21710                            "Unstage Hunk",
21711                            &::git::ToggleStaged,
21712                            &focus_handle,
21713                            window,
21714                            cx,
21715                        )
21716                    }
21717                })
21718                .on_click({
21719                    let editor = editor.clone();
21720                    move |_event, _window, cx| {
21721                        editor.update(cx, |editor, cx| {
21722                            editor.stage_or_unstage_diff_hunks(
21723                                false,
21724                                vec![hunk_range.start..hunk_range.start],
21725                                cx,
21726                            );
21727                        });
21728                    }
21729                })
21730        })
21731        .child(
21732            Button::new(("restore", row as u64), "Restore")
21733                .tooltip({
21734                    let focus_handle = editor.focus_handle(cx);
21735                    move |window, cx| {
21736                        Tooltip::for_action_in(
21737                            "Restore Hunk",
21738                            &::git::Restore,
21739                            &focus_handle,
21740                            window,
21741                            cx,
21742                        )
21743                    }
21744                })
21745                .on_click({
21746                    let editor = editor.clone();
21747                    move |_event, window, cx| {
21748                        editor.update(cx, |editor, cx| {
21749                            let snapshot = editor.snapshot(window, cx);
21750                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21751                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21752                        });
21753                    }
21754                })
21755                .disabled(is_created_file),
21756        )
21757        .when(
21758            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21759            |el| {
21760                el.child(
21761                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21762                        .shape(IconButtonShape::Square)
21763                        .icon_size(IconSize::Small)
21764                        // .disabled(!has_multiple_hunks)
21765                        .tooltip({
21766                            let focus_handle = editor.focus_handle(cx);
21767                            move |window, cx| {
21768                                Tooltip::for_action_in(
21769                                    "Next Hunk",
21770                                    &GoToHunk,
21771                                    &focus_handle,
21772                                    window,
21773                                    cx,
21774                                )
21775                            }
21776                        })
21777                        .on_click({
21778                            let editor = editor.clone();
21779                            move |_event, window, cx| {
21780                                editor.update(cx, |editor, cx| {
21781                                    let snapshot = editor.snapshot(window, cx);
21782                                    let position =
21783                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21784                                    editor.go_to_hunk_before_or_after_position(
21785                                        &snapshot,
21786                                        position,
21787                                        Direction::Next,
21788                                        window,
21789                                        cx,
21790                                    );
21791                                    editor.expand_selected_diff_hunks(cx);
21792                                });
21793                            }
21794                        }),
21795                )
21796                .child(
21797                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21798                        .shape(IconButtonShape::Square)
21799                        .icon_size(IconSize::Small)
21800                        // .disabled(!has_multiple_hunks)
21801                        .tooltip({
21802                            let focus_handle = editor.focus_handle(cx);
21803                            move |window, cx| {
21804                                Tooltip::for_action_in(
21805                                    "Previous Hunk",
21806                                    &GoToPreviousHunk,
21807                                    &focus_handle,
21808                                    window,
21809                                    cx,
21810                                )
21811                            }
21812                        })
21813                        .on_click({
21814                            let editor = editor.clone();
21815                            move |_event, window, cx| {
21816                                editor.update(cx, |editor, cx| {
21817                                    let snapshot = editor.snapshot(window, cx);
21818                                    let point =
21819                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21820                                    editor.go_to_hunk_before_or_after_position(
21821                                        &snapshot,
21822                                        point,
21823                                        Direction::Prev,
21824                                        window,
21825                                        cx,
21826                                    );
21827                                    editor.expand_selected_diff_hunks(cx);
21828                                });
21829                            }
21830                        }),
21831                )
21832            },
21833        )
21834        .into_any_element()
21835}