editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::StringMatchCandidate;
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  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, 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, wrap_with_prefix};
  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)]
  779pub struct 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    offset_content: bool,
  927    disable_expand_excerpt_buttons: bool,
  928    show_line_numbers: Option<bool>,
  929    use_relative_line_numbers: Option<bool>,
  930    show_git_diff_gutter: Option<bool>,
  931    show_code_actions: Option<bool>,
  932    show_runnables: Option<bool>,
  933    show_breakpoints: Option<bool>,
  934    show_wrap_guides: Option<bool>,
  935    show_indent_guides: Option<bool>,
  936    placeholder_text: Option<Arc<str>>,
  937    highlight_order: usize,
  938    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  939    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  940    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  941    scrollbar_marker_state: ScrollbarMarkerState,
  942    active_indent_guides_state: ActiveIndentGuidesState,
  943    nav_history: Option<ItemNavHistory>,
  944    context_menu: RefCell<Option<CodeContextMenu>>,
  945    context_menu_options: Option<ContextMenuOptions>,
  946    mouse_context_menu: Option<MouseContextMenu>,
  947    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  948    inline_blame_popover: Option<InlineBlamePopover>,
  949    signature_help_state: SignatureHelpState,
  950    auto_signature_help: Option<bool>,
  951    find_all_references_task_sources: Vec<Anchor>,
  952    next_completion_id: CompletionId,
  953    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  954    code_actions_task: Option<Task<Result<()>>>,
  955    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  957    document_highlights_task: Option<Task<()>>,
  958    linked_editing_range_task: Option<Task<Option<()>>>,
  959    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  960    pending_rename: Option<RenameState>,
  961    searchable: bool,
  962    cursor_shape: CursorShape,
  963    current_line_highlight: Option<CurrentLineHighlight>,
  964    collapse_matches: bool,
  965    autoindent_mode: Option<AutoindentMode>,
  966    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  967    input_enabled: bool,
  968    use_modal_editing: bool,
  969    read_only: bool,
  970    leader_id: Option<CollaboratorId>,
  971    remote_id: Option<ViewId>,
  972    pub hover_state: HoverState,
  973    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  974    gutter_hovered: bool,
  975    hovered_link_state: Option<HoveredLinkState>,
  976    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  977    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  978    active_inline_completion: Option<InlineCompletionState>,
  979    /// Used to prevent flickering as the user types while the menu is open
  980    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  981    edit_prediction_settings: EditPredictionSettings,
  982    inline_completions_hidden_for_vim_mode: bool,
  983    show_inline_completions_override: Option<bool>,
  984    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  985    edit_prediction_preview: EditPredictionPreview,
  986    edit_prediction_indent_conflict: bool,
  987    edit_prediction_requires_modifier_in_indent_conflict: bool,
  988    inlay_hint_cache: InlayHintCache,
  989    next_inlay_id: usize,
  990    _subscriptions: Vec<Subscription>,
  991    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  992    gutter_dimensions: GutterDimensions,
  993    style: Option<EditorStyle>,
  994    text_style_refinement: Option<TextStyleRefinement>,
  995    next_editor_action_id: EditorActionId,
  996    editor_actions:
  997        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  998    use_autoclose: bool,
  999    use_auto_surround: bool,
 1000    auto_replace_emoji_shortcode: bool,
 1001    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1002    show_git_blame_gutter: bool,
 1003    show_git_blame_inline: bool,
 1004    show_git_blame_inline_delay_task: Option<Task<()>>,
 1005    git_blame_inline_enabled: bool,
 1006    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1007    serialize_dirty_buffers: bool,
 1008    show_selection_menu: Option<bool>,
 1009    blame: Option<Entity<GitBlame>>,
 1010    blame_subscription: Option<Subscription>,
 1011    custom_context_menu: Option<
 1012        Box<
 1013            dyn 'static
 1014                + Fn(
 1015                    &mut Self,
 1016                    DisplayPoint,
 1017                    &mut Window,
 1018                    &mut Context<Self>,
 1019                ) -> Option<Entity<ui::ContextMenu>>,
 1020        >,
 1021    >,
 1022    last_bounds: Option<Bounds<Pixels>>,
 1023    last_position_map: Option<Rc<PositionMap>>,
 1024    expect_bounds_change: Option<Bounds<Pixels>>,
 1025    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1026    tasks_update_task: Option<Task<()>>,
 1027    breakpoint_store: Option<Entity<BreakpointStore>>,
 1028    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1029    in_project_search: bool,
 1030    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1031    breadcrumb_header: Option<String>,
 1032    focused_block: Option<FocusedBlock>,
 1033    next_scroll_position: NextScrollCursorCenterTopBottom,
 1034    addons: HashMap<TypeId, Box<dyn Addon>>,
 1035    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1036    load_diff_task: Option<Shared<Task<()>>>,
 1037    /// Whether we are temporarily displaying a diff other than git's
 1038    temporary_diff_override: bool,
 1039    selection_mark_mode: bool,
 1040    toggle_fold_multiple_buffers: Task<()>,
 1041    _scroll_cursor_center_top_bottom_task: Task<()>,
 1042    serialize_selections: Task<()>,
 1043    serialize_folds: Task<()>,
 1044    mouse_cursor_hidden: bool,
 1045    minimap: Option<Entity<Self>>,
 1046    hide_mouse_mode: HideMouseMode,
 1047    pub change_list: ChangeList,
 1048    inline_value_cache: InlineValueCache,
 1049}
 1050
 1051#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1052enum NextScrollCursorCenterTopBottom {
 1053    #[default]
 1054    Center,
 1055    Top,
 1056    Bottom,
 1057}
 1058
 1059impl NextScrollCursorCenterTopBottom {
 1060    fn next(&self) -> Self {
 1061        match self {
 1062            Self::Center => Self::Top,
 1063            Self::Top => Self::Bottom,
 1064            Self::Bottom => Self::Center,
 1065        }
 1066    }
 1067}
 1068
 1069#[derive(Clone)]
 1070pub struct EditorSnapshot {
 1071    pub mode: EditorMode,
 1072    show_gutter: bool,
 1073    show_line_numbers: Option<bool>,
 1074    show_git_diff_gutter: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    git_blame_gutter_max_author_length: Option<usize>,
 1078    pub display_snapshot: DisplaySnapshot,
 1079    pub placeholder_text: Option<Arc<str>>,
 1080    is_focused: bool,
 1081    scroll_anchor: ScrollAnchor,
 1082    ongoing_scroll: OngoingScroll,
 1083    current_line_highlight: CurrentLineHighlight,
 1084    gutter_hovered: bool,
 1085}
 1086
 1087#[derive(Default, Debug, Clone, Copy)]
 1088pub struct GutterDimensions {
 1089    pub left_padding: Pixels,
 1090    pub right_padding: Pixels,
 1091    pub width: Pixels,
 1092    pub margin: Pixels,
 1093    pub git_blame_entries_width: Option<Pixels>,
 1094}
 1095
 1096impl GutterDimensions {
 1097    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1098        Self {
 1099            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1100            ..Default::default()
 1101        }
 1102    }
 1103
 1104    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1105        -cx.text_system().descent(font_id, font_size)
 1106    }
 1107    /// The full width of the space taken up by the gutter.
 1108    pub fn full_width(&self) -> Pixels {
 1109        self.margin + self.width
 1110    }
 1111
 1112    /// The width of the space reserved for the fold indicators,
 1113    /// use alongside 'justify_end' and `gutter_width` to
 1114    /// right align content with the line numbers
 1115    pub fn fold_area_width(&self) -> Pixels {
 1116        self.margin + self.right_padding
 1117    }
 1118}
 1119
 1120#[derive(Debug)]
 1121pub struct RemoteSelection {
 1122    pub replica_id: ReplicaId,
 1123    pub selection: Selection<Anchor>,
 1124    pub cursor_shape: CursorShape,
 1125    pub collaborator_id: CollaboratorId,
 1126    pub line_mode: bool,
 1127    pub user_name: Option<SharedString>,
 1128    pub color: PlayerColor,
 1129}
 1130
 1131#[derive(Clone, Debug)]
 1132struct SelectionHistoryEntry {
 1133    selections: Arc<[Selection<Anchor>]>,
 1134    select_next_state: Option<SelectNextState>,
 1135    select_prev_state: Option<SelectNextState>,
 1136    add_selections_state: Option<AddSelectionsState>,
 1137}
 1138
 1139enum SelectionHistoryMode {
 1140    Normal,
 1141    Undoing,
 1142    Redoing,
 1143}
 1144
 1145#[derive(Clone, PartialEq, Eq, Hash)]
 1146struct HoveredCursor {
 1147    replica_id: u16,
 1148    selection_id: usize,
 1149}
 1150
 1151impl Default for SelectionHistoryMode {
 1152    fn default() -> Self {
 1153        Self::Normal
 1154    }
 1155}
 1156
 1157#[derive(Default)]
 1158struct SelectionHistory {
 1159    #[allow(clippy::type_complexity)]
 1160    selections_by_transaction:
 1161        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1162    mode: SelectionHistoryMode,
 1163    undo_stack: VecDeque<SelectionHistoryEntry>,
 1164    redo_stack: VecDeque<SelectionHistoryEntry>,
 1165}
 1166
 1167impl SelectionHistory {
 1168    fn insert_transaction(
 1169        &mut self,
 1170        transaction_id: TransactionId,
 1171        selections: Arc<[Selection<Anchor>]>,
 1172    ) {
 1173        self.selections_by_transaction
 1174            .insert(transaction_id, (selections, None));
 1175    }
 1176
 1177    #[allow(clippy::type_complexity)]
 1178    fn transaction(
 1179        &self,
 1180        transaction_id: TransactionId,
 1181    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1182        self.selections_by_transaction.get(&transaction_id)
 1183    }
 1184
 1185    #[allow(clippy::type_complexity)]
 1186    fn transaction_mut(
 1187        &mut self,
 1188        transaction_id: TransactionId,
 1189    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1190        self.selections_by_transaction.get_mut(&transaction_id)
 1191    }
 1192
 1193    fn push(&mut self, entry: SelectionHistoryEntry) {
 1194        if !entry.selections.is_empty() {
 1195            match self.mode {
 1196                SelectionHistoryMode::Normal => {
 1197                    self.push_undo(entry);
 1198                    self.redo_stack.clear();
 1199                }
 1200                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1201                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1202            }
 1203        }
 1204    }
 1205
 1206    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1207        if self
 1208            .undo_stack
 1209            .back()
 1210            .map_or(true, |e| e.selections != entry.selections)
 1211        {
 1212            self.undo_stack.push_back(entry);
 1213            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1214                self.undo_stack.pop_front();
 1215            }
 1216        }
 1217    }
 1218
 1219    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1220        if self
 1221            .redo_stack
 1222            .back()
 1223            .map_or(true, |e| e.selections != entry.selections)
 1224        {
 1225            self.redo_stack.push_back(entry);
 1226            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1227                self.redo_stack.pop_front();
 1228            }
 1229        }
 1230    }
 1231}
 1232
 1233#[derive(Clone, Copy)]
 1234pub struct RowHighlightOptions {
 1235    pub autoscroll: bool,
 1236    pub include_gutter: bool,
 1237}
 1238
 1239impl Default for RowHighlightOptions {
 1240    fn default() -> Self {
 1241        Self {
 1242            autoscroll: Default::default(),
 1243            include_gutter: true,
 1244        }
 1245    }
 1246}
 1247
 1248struct RowHighlight {
 1249    index: usize,
 1250    range: Range<Anchor>,
 1251    color: Hsla,
 1252    options: RowHighlightOptions,
 1253    type_id: TypeId,
 1254}
 1255
 1256#[derive(Clone, Debug)]
 1257struct AddSelectionsState {
 1258    above: bool,
 1259    stack: Vec<usize>,
 1260}
 1261
 1262#[derive(Clone)]
 1263struct SelectNextState {
 1264    query: AhoCorasick,
 1265    wordwise: bool,
 1266    done: bool,
 1267}
 1268
 1269impl std::fmt::Debug for SelectNextState {
 1270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1271        f.debug_struct(std::any::type_name::<Self>())
 1272            .field("wordwise", &self.wordwise)
 1273            .field("done", &self.done)
 1274            .finish()
 1275    }
 1276}
 1277
 1278#[derive(Debug)]
 1279struct AutocloseRegion {
 1280    selection_id: usize,
 1281    range: Range<Anchor>,
 1282    pair: BracketPair,
 1283}
 1284
 1285#[derive(Debug)]
 1286struct SnippetState {
 1287    ranges: Vec<Vec<Range<Anchor>>>,
 1288    active_index: usize,
 1289    choices: Vec<Option<Vec<String>>>,
 1290}
 1291
 1292#[doc(hidden)]
 1293pub struct RenameState {
 1294    pub range: Range<Anchor>,
 1295    pub old_name: Arc<str>,
 1296    pub editor: Entity<Editor>,
 1297    block_id: CustomBlockId,
 1298}
 1299
 1300struct InvalidationStack<T>(Vec<T>);
 1301
 1302struct RegisteredInlineCompletionProvider {
 1303    provider: Arc<dyn InlineCompletionProviderHandle>,
 1304    _subscription: Subscription,
 1305}
 1306
 1307#[derive(Debug, PartialEq, Eq)]
 1308pub struct ActiveDiagnosticGroup {
 1309    pub active_range: Range<Anchor>,
 1310    pub active_message: String,
 1311    pub group_id: usize,
 1312    pub blocks: HashSet<CustomBlockId>,
 1313}
 1314
 1315#[derive(Debug, PartialEq, Eq)]
 1316
 1317pub(crate) enum ActiveDiagnostic {
 1318    None,
 1319    All,
 1320    Group(ActiveDiagnosticGroup),
 1321}
 1322
 1323#[derive(Serialize, Deserialize, Clone, Debug)]
 1324pub struct ClipboardSelection {
 1325    /// The number of bytes in this selection.
 1326    pub len: usize,
 1327    /// Whether this was a full-line selection.
 1328    pub is_entire_line: bool,
 1329    /// The indentation of the first line when this content was originally copied.
 1330    pub first_line_indent: u32,
 1331}
 1332
 1333// selections, scroll behavior, was newest selection reversed
 1334type SelectSyntaxNodeHistoryState = (
 1335    Box<[Selection<usize>]>,
 1336    SelectSyntaxNodeScrollBehavior,
 1337    bool,
 1338);
 1339
 1340#[derive(Default)]
 1341struct SelectSyntaxNodeHistory {
 1342    stack: Vec<SelectSyntaxNodeHistoryState>,
 1343    // disable temporarily to allow changing selections without losing the stack
 1344    pub disable_clearing: bool,
 1345}
 1346
 1347impl SelectSyntaxNodeHistory {
 1348    pub fn try_clear(&mut self) {
 1349        if !self.disable_clearing {
 1350            self.stack.clear();
 1351        }
 1352    }
 1353
 1354    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1355        self.stack.push(selection);
 1356    }
 1357
 1358    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1359        self.stack.pop()
 1360    }
 1361}
 1362
 1363enum SelectSyntaxNodeScrollBehavior {
 1364    CursorTop,
 1365    FitSelection,
 1366    CursorBottom,
 1367}
 1368
 1369#[derive(Debug)]
 1370pub(crate) struct NavigationData {
 1371    cursor_anchor: Anchor,
 1372    cursor_position: Point,
 1373    scroll_anchor: ScrollAnchor,
 1374    scroll_top_row: u32,
 1375}
 1376
 1377#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1378pub enum GotoDefinitionKind {
 1379    Symbol,
 1380    Declaration,
 1381    Type,
 1382    Implementation,
 1383}
 1384
 1385#[derive(Debug, Clone)]
 1386enum InlayHintRefreshReason {
 1387    ModifiersChanged(bool),
 1388    Toggle(bool),
 1389    SettingsChange(InlayHintSettings),
 1390    NewLinesShown,
 1391    BufferEdited(HashSet<Arc<Language>>),
 1392    RefreshRequested,
 1393    ExcerptsRemoved(Vec<ExcerptId>),
 1394}
 1395
 1396impl InlayHintRefreshReason {
 1397    fn description(&self) -> &'static str {
 1398        match self {
 1399            Self::ModifiersChanged(_) => "modifiers changed",
 1400            Self::Toggle(_) => "toggle",
 1401            Self::SettingsChange(_) => "settings change",
 1402            Self::NewLinesShown => "new lines shown",
 1403            Self::BufferEdited(_) => "buffer edited",
 1404            Self::RefreshRequested => "refresh requested",
 1405            Self::ExcerptsRemoved(_) => "excerpts removed",
 1406        }
 1407    }
 1408}
 1409
 1410pub enum FormatTarget {
 1411    Buffers,
 1412    Ranges(Vec<Range<MultiBufferPoint>>),
 1413}
 1414
 1415pub(crate) struct FocusedBlock {
 1416    id: BlockId,
 1417    focus_handle: WeakFocusHandle,
 1418}
 1419
 1420#[derive(Clone)]
 1421enum JumpData {
 1422    MultiBufferRow {
 1423        row: MultiBufferRow,
 1424        line_offset_from_top: u32,
 1425    },
 1426    MultiBufferPoint {
 1427        excerpt_id: ExcerptId,
 1428        position: Point,
 1429        anchor: text::Anchor,
 1430        line_offset_from_top: u32,
 1431    },
 1432}
 1433
 1434pub enum MultibufferSelectionMode {
 1435    First,
 1436    All,
 1437}
 1438
 1439#[derive(Clone, Copy, Debug, Default)]
 1440pub struct RewrapOptions {
 1441    pub override_language_settings: bool,
 1442    pub preserve_existing_whitespace: bool,
 1443}
 1444
 1445impl Editor {
 1446    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1447        let buffer = cx.new(|cx| Buffer::local("", cx));
 1448        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1449        Self::new(
 1450            EditorMode::SingleLine { auto_width: false },
 1451            buffer,
 1452            None,
 1453            window,
 1454            cx,
 1455        )
 1456    }
 1457
 1458    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1459        let buffer = cx.new(|cx| Buffer::local("", cx));
 1460        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1461        Self::new(EditorMode::full(), buffer, None, window, cx)
 1462    }
 1463
 1464    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1465        let buffer = cx.new(|cx| Buffer::local("", cx));
 1466        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1467        Self::new(
 1468            EditorMode::SingleLine { auto_width: true },
 1469            buffer,
 1470            None,
 1471            window,
 1472            cx,
 1473        )
 1474    }
 1475
 1476    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1477        let buffer = cx.new(|cx| Buffer::local("", cx));
 1478        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1479        Self::new(
 1480            EditorMode::AutoHeight { max_lines },
 1481            buffer,
 1482            None,
 1483            window,
 1484            cx,
 1485        )
 1486    }
 1487
 1488    pub fn for_buffer(
 1489        buffer: Entity<Buffer>,
 1490        project: Option<Entity<Project>>,
 1491        window: &mut Window,
 1492        cx: &mut Context<Self>,
 1493    ) -> Self {
 1494        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1495        Self::new(EditorMode::full(), buffer, project, window, cx)
 1496    }
 1497
 1498    pub fn for_multibuffer(
 1499        buffer: Entity<MultiBuffer>,
 1500        project: Option<Entity<Project>>,
 1501        window: &mut Window,
 1502        cx: &mut Context<Self>,
 1503    ) -> Self {
 1504        Self::new(EditorMode::full(), buffer, project, window, cx)
 1505    }
 1506
 1507    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1508        let mut clone = Self::new(
 1509            self.mode.clone(),
 1510            self.buffer.clone(),
 1511            self.project.clone(),
 1512            window,
 1513            cx,
 1514        );
 1515        self.display_map.update(cx, |display_map, cx| {
 1516            let snapshot = display_map.snapshot(cx);
 1517            clone.display_map.update(cx, |display_map, cx| {
 1518                display_map.set_state(&snapshot, cx);
 1519            });
 1520        });
 1521        clone.folds_did_change(cx);
 1522        clone.selections.clone_state(&self.selections);
 1523        clone.scroll_manager.clone_state(&self.scroll_manager);
 1524        clone.searchable = self.searchable;
 1525        clone.read_only = self.read_only;
 1526        clone
 1527    }
 1528
 1529    pub fn new(
 1530        mode: EditorMode,
 1531        buffer: Entity<MultiBuffer>,
 1532        project: Option<Entity<Project>>,
 1533        window: &mut Window,
 1534        cx: &mut Context<Self>,
 1535    ) -> Self {
 1536        Editor::new_internal(mode, buffer, project, None, window, cx)
 1537    }
 1538
 1539    fn new_internal(
 1540        mode: EditorMode,
 1541        buffer: Entity<MultiBuffer>,
 1542        project: Option<Entity<Project>>,
 1543        display_map: Option<Entity<DisplayMap>>,
 1544        window: &mut Window,
 1545        cx: &mut Context<Self>,
 1546    ) -> Self {
 1547        debug_assert!(
 1548            display_map.is_none() || mode.is_minimap(),
 1549            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1550        );
 1551
 1552        let full_mode = mode.is_full();
 1553        let diagnostics_max_severity = if full_mode {
 1554            EditorSettings::get_global(cx)
 1555                .diagnostics_max_severity
 1556                .unwrap_or(DiagnosticSeverity::Hint)
 1557        } else {
 1558            DiagnosticSeverity::Off
 1559        };
 1560        let style = window.text_style();
 1561        let font_size = style.font_size.to_pixels(window.rem_size());
 1562        let editor = cx.entity().downgrade();
 1563        let fold_placeholder = FoldPlaceholder {
 1564            constrain_width: true,
 1565            render: Arc::new(move |fold_id, fold_range, cx| {
 1566                let editor = editor.clone();
 1567                div()
 1568                    .id(fold_id)
 1569                    .bg(cx.theme().colors().ghost_element_background)
 1570                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1571                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1572                    .rounded_xs()
 1573                    .size_full()
 1574                    .cursor_pointer()
 1575                    .child("")
 1576                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1577                    .on_click(move |_, _window, cx| {
 1578                        editor
 1579                            .update(cx, |editor, cx| {
 1580                                editor.unfold_ranges(
 1581                                    &[fold_range.start..fold_range.end],
 1582                                    true,
 1583                                    false,
 1584                                    cx,
 1585                                );
 1586                                cx.stop_propagation();
 1587                            })
 1588                            .ok();
 1589                    })
 1590                    .into_any()
 1591            }),
 1592            merge_adjacent: true,
 1593            ..FoldPlaceholder::default()
 1594        };
 1595        let display_map = display_map.unwrap_or_else(|| {
 1596            cx.new(|cx| {
 1597                DisplayMap::new(
 1598                    buffer.clone(),
 1599                    style.font(),
 1600                    font_size,
 1601                    None,
 1602                    FILE_HEADER_HEIGHT,
 1603                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1604                    fold_placeholder,
 1605                    diagnostics_max_severity,
 1606                    cx,
 1607                )
 1608            })
 1609        });
 1610
 1611        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1612
 1613        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1614
 1615        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1616            .then(|| language_settings::SoftWrap::None);
 1617
 1618        let mut project_subscriptions = Vec::new();
 1619        if mode.is_full() {
 1620            if let Some(project) = project.as_ref() {
 1621                project_subscriptions.push(cx.subscribe_in(
 1622                    project,
 1623                    window,
 1624                    |editor, _, event, window, cx| match event {
 1625                        project::Event::RefreshCodeLens => {
 1626                            // we always query lens with actions, without storing them, always refreshing them
 1627                        }
 1628                        project::Event::RefreshInlayHints => {
 1629                            editor
 1630                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1631                        }
 1632                        project::Event::SnippetEdit(id, snippet_edits) => {
 1633                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1634                                let focus_handle = editor.focus_handle(cx);
 1635                                if focus_handle.is_focused(window) {
 1636                                    let snapshot = buffer.read(cx).snapshot();
 1637                                    for (range, snippet) in snippet_edits {
 1638                                        let editor_range =
 1639                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1640                                        editor
 1641                                            .insert_snippet(
 1642                                                &[editor_range],
 1643                                                snippet.clone(),
 1644                                                window,
 1645                                                cx,
 1646                                            )
 1647                                            .ok();
 1648                                    }
 1649                                }
 1650                            }
 1651                        }
 1652                        _ => {}
 1653                    },
 1654                ));
 1655                if let Some(task_inventory) = project
 1656                    .read(cx)
 1657                    .task_store()
 1658                    .read(cx)
 1659                    .task_inventory()
 1660                    .cloned()
 1661                {
 1662                    project_subscriptions.push(cx.observe_in(
 1663                        &task_inventory,
 1664                        window,
 1665                        |editor, _, window, cx| {
 1666                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1667                        },
 1668                    ));
 1669                };
 1670
 1671                project_subscriptions.push(cx.subscribe_in(
 1672                    &project.read(cx).breakpoint_store(),
 1673                    window,
 1674                    |editor, _, event, window, cx| match event {
 1675                        BreakpointStoreEvent::ClearDebugLines => {
 1676                            editor.clear_row_highlights::<ActiveDebugLine>();
 1677                            editor.refresh_inline_values(cx);
 1678                        }
 1679                        BreakpointStoreEvent::SetDebugLine => {
 1680                            if editor.go_to_active_debug_line(window, cx) {
 1681                                cx.stop_propagation();
 1682                            }
 1683
 1684                            editor.refresh_inline_values(cx);
 1685                        }
 1686                        _ => {}
 1687                    },
 1688                ));
 1689            }
 1690        }
 1691
 1692        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1693
 1694        let inlay_hint_settings =
 1695            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1696        let focus_handle = cx.focus_handle();
 1697        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1698            .detach();
 1699        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1700            .detach();
 1701        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1702            .detach();
 1703        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1704            .detach();
 1705
 1706        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1707            Some(false)
 1708        } else {
 1709            None
 1710        };
 1711
 1712        let breakpoint_store = match (&mode, project.as_ref()) {
 1713            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1714            _ => None,
 1715        };
 1716
 1717        let mut code_action_providers = Vec::new();
 1718        let mut load_uncommitted_diff = None;
 1719        if let Some(project) = project.clone() {
 1720            load_uncommitted_diff = Some(
 1721                update_uncommitted_diff_for_buffer(
 1722                    cx.entity(),
 1723                    &project,
 1724                    buffer.read(cx).all_buffers(),
 1725                    buffer.clone(),
 1726                    cx,
 1727                )
 1728                .shared(),
 1729            );
 1730            code_action_providers.push(Rc::new(project) as Rc<_>);
 1731        }
 1732
 1733        let mut this = Self {
 1734            focus_handle,
 1735            show_cursor_when_unfocused: false,
 1736            last_focused_descendant: None,
 1737            buffer: buffer.clone(),
 1738            display_map: display_map.clone(),
 1739            selections,
 1740            scroll_manager: ScrollManager::new(cx),
 1741            columnar_selection_tail: None,
 1742            add_selections_state: None,
 1743            select_next_state: None,
 1744            select_prev_state: None,
 1745            selection_history: SelectionHistory::default(),
 1746            autoclose_regions: Vec::new(),
 1747            snippet_stack: InvalidationStack::default(),
 1748            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1749            ime_transaction: None,
 1750            active_diagnostics: ActiveDiagnostic::None,
 1751            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1752            inline_diagnostics_update: Task::ready(()),
 1753            inline_diagnostics: Vec::new(),
 1754            soft_wrap_mode_override,
 1755            diagnostics_max_severity,
 1756            hard_wrap: None,
 1757            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1758            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1759            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1760            project,
 1761            blink_manager: blink_manager.clone(),
 1762            show_local_selections: true,
 1763            show_scrollbars: full_mode,
 1764            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1765            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1766            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1767            show_gutter: mode.is_full(),
 1768            show_line_numbers: None,
 1769            use_relative_line_numbers: None,
 1770            disable_expand_excerpt_buttons: false,
 1771            show_git_diff_gutter: None,
 1772            show_code_actions: None,
 1773            show_runnables: None,
 1774            show_breakpoints: None,
 1775            show_wrap_guides: None,
 1776            show_indent_guides,
 1777            placeholder_text: None,
 1778            highlight_order: 0,
 1779            highlighted_rows: HashMap::default(),
 1780            background_highlights: TreeMap::default(),
 1781            gutter_highlights: TreeMap::default(),
 1782            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1783            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1784            nav_history: None,
 1785            context_menu: RefCell::new(None),
 1786            context_menu_options: None,
 1787            mouse_context_menu: None,
 1788            completion_tasks: Vec::new(),
 1789            inline_blame_popover: None,
 1790            signature_help_state: SignatureHelpState::default(),
 1791            auto_signature_help: None,
 1792            find_all_references_task_sources: Vec::new(),
 1793            next_completion_id: 0,
 1794            next_inlay_id: 0,
 1795            code_action_providers,
 1796            available_code_actions: None,
 1797            code_actions_task: None,
 1798            quick_selection_highlight_task: None,
 1799            debounced_selection_highlight_task: None,
 1800            document_highlights_task: None,
 1801            linked_editing_range_task: None,
 1802            pending_rename: None,
 1803            searchable: true,
 1804            cursor_shape: EditorSettings::get_global(cx)
 1805                .cursor_shape
 1806                .unwrap_or_default(),
 1807            current_line_highlight: None,
 1808            autoindent_mode: Some(AutoindentMode::EachLine),
 1809            collapse_matches: false,
 1810            workspace: None,
 1811            input_enabled: true,
 1812            use_modal_editing: mode.is_full(),
 1813            read_only: mode.is_minimap(),
 1814            use_autoclose: true,
 1815            use_auto_surround: true,
 1816            auto_replace_emoji_shortcode: false,
 1817            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1818            leader_id: None,
 1819            remote_id: None,
 1820            hover_state: HoverState::default(),
 1821            pending_mouse_down: None,
 1822            hovered_link_state: None,
 1823            edit_prediction_provider: None,
 1824            active_inline_completion: None,
 1825            stale_inline_completion_in_menu: None,
 1826            edit_prediction_preview: EditPredictionPreview::Inactive {
 1827                released_too_fast: false,
 1828            },
 1829            inline_diagnostics_enabled: mode.is_full(),
 1830            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1831            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1832
 1833            gutter_hovered: false,
 1834            pixel_position_of_newest_cursor: None,
 1835            last_bounds: None,
 1836            last_position_map: None,
 1837            expect_bounds_change: None,
 1838            gutter_dimensions: GutterDimensions::default(),
 1839            style: None,
 1840            show_cursor_names: false,
 1841            hovered_cursors: HashMap::default(),
 1842            next_editor_action_id: EditorActionId::default(),
 1843            editor_actions: Rc::default(),
 1844            inline_completions_hidden_for_vim_mode: false,
 1845            show_inline_completions_override: None,
 1846            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1847            edit_prediction_settings: EditPredictionSettings::Disabled,
 1848            edit_prediction_indent_conflict: false,
 1849            edit_prediction_requires_modifier_in_indent_conflict: true,
 1850            custom_context_menu: None,
 1851            show_git_blame_gutter: false,
 1852            show_git_blame_inline: false,
 1853            show_selection_menu: None,
 1854            show_git_blame_inline_delay_task: None,
 1855            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1856            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1857            serialize_dirty_buffers: !mode.is_minimap()
 1858                && ProjectSettings::get_global(cx)
 1859                    .session
 1860                    .restore_unsaved_buffers,
 1861            blame: None,
 1862            blame_subscription: None,
 1863            tasks: BTreeMap::default(),
 1864
 1865            breakpoint_store,
 1866            gutter_breakpoint_indicator: (None, None),
 1867            _subscriptions: vec![
 1868                cx.observe(&buffer, Self::on_buffer_changed),
 1869                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1870                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1871                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1872                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1873                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1874                cx.observe_window_activation(window, |editor, window, cx| {
 1875                    let active = window.is_window_active();
 1876                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1877                        if active {
 1878                            blink_manager.enable(cx);
 1879                        } else {
 1880                            blink_manager.disable(cx);
 1881                        }
 1882                    });
 1883                }),
 1884            ],
 1885            tasks_update_task: None,
 1886            linked_edit_ranges: Default::default(),
 1887            in_project_search: false,
 1888            previous_search_ranges: None,
 1889            breadcrumb_header: None,
 1890            focused_block: None,
 1891            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1892            addons: HashMap::default(),
 1893            registered_buffers: HashMap::default(),
 1894            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1895            selection_mark_mode: false,
 1896            toggle_fold_multiple_buffers: Task::ready(()),
 1897            serialize_selections: Task::ready(()),
 1898            serialize_folds: Task::ready(()),
 1899            text_style_refinement: None,
 1900            load_diff_task: load_uncommitted_diff,
 1901            temporary_diff_override: false,
 1902            mouse_cursor_hidden: false,
 1903            minimap: None,
 1904            hide_mouse_mode: EditorSettings::get_global(cx)
 1905                .hide_mouse
 1906                .unwrap_or_default(),
 1907            change_list: ChangeList::new(),
 1908            mode,
 1909        };
 1910        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1911            this._subscriptions
 1912                .push(cx.observe(breakpoints, |_, _, cx| {
 1913                    cx.notify();
 1914                }));
 1915        }
 1916        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1917        this._subscriptions.extend(project_subscriptions);
 1918
 1919        this._subscriptions.push(cx.subscribe_in(
 1920            &cx.entity(),
 1921            window,
 1922            |editor, _, e: &EditorEvent, window, cx| match e {
 1923                EditorEvent::ScrollPositionChanged { local, .. } => {
 1924                    if *local {
 1925                        let new_anchor = editor.scroll_manager.anchor();
 1926                        let snapshot = editor.snapshot(window, cx);
 1927                        editor.update_restoration_data(cx, move |data| {
 1928                            data.scroll_position = (
 1929                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1930                                new_anchor.offset,
 1931                            );
 1932                        });
 1933                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1934                        editor.inline_blame_popover.take();
 1935                    }
 1936                }
 1937                EditorEvent::Edited { .. } => {
 1938                    if !vim_enabled(cx) {
 1939                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1940                        let pop_state = editor
 1941                            .change_list
 1942                            .last()
 1943                            .map(|previous| {
 1944                                previous.len() == selections.len()
 1945                                    && previous.iter().enumerate().all(|(ix, p)| {
 1946                                        p.to_display_point(&map).row()
 1947                                            == selections[ix].head().row()
 1948                                    })
 1949                            })
 1950                            .unwrap_or(false);
 1951                        let new_positions = selections
 1952                            .into_iter()
 1953                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1954                            .collect();
 1955                        editor
 1956                            .change_list
 1957                            .push_to_change_list(pop_state, new_positions);
 1958                    }
 1959                }
 1960                _ => (),
 1961            },
 1962        ));
 1963
 1964        if let Some(dap_store) = this
 1965            .project
 1966            .as_ref()
 1967            .map(|project| project.read(cx).dap_store())
 1968        {
 1969            let weak_editor = cx.weak_entity();
 1970
 1971            this._subscriptions
 1972                .push(
 1973                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1974                        let session_entity = cx.entity();
 1975                        weak_editor
 1976                            .update(cx, |editor, cx| {
 1977                                editor._subscriptions.push(
 1978                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1979                                );
 1980                            })
 1981                            .ok();
 1982                    }),
 1983                );
 1984
 1985            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1986                this._subscriptions
 1987                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1988            }
 1989        }
 1990
 1991        this.end_selection(window, cx);
 1992        this.scroll_manager.show_scrollbars(window, cx);
 1993        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1994
 1995        if full_mode {
 1996            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1997            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1998
 1999            if this.git_blame_inline_enabled {
 2000                this.start_git_blame_inline(false, window, cx);
 2001            }
 2002
 2003            this.go_to_active_debug_line(window, cx);
 2004
 2005            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2006                if let Some(project) = this.project.as_ref() {
 2007                    let handle = project.update(cx, |project, cx| {
 2008                        project.register_buffer_with_language_servers(&buffer, cx)
 2009                    });
 2010                    this.registered_buffers
 2011                        .insert(buffer.read(cx).remote_id(), handle);
 2012                }
 2013            }
 2014
 2015            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2016        }
 2017
 2018        this.report_editor_event("Editor Opened", None, cx);
 2019        this
 2020    }
 2021
 2022    pub fn deploy_mouse_context_menu(
 2023        &mut self,
 2024        position: gpui::Point<Pixels>,
 2025        context_menu: Entity<ContextMenu>,
 2026        window: &mut Window,
 2027        cx: &mut Context<Self>,
 2028    ) {
 2029        self.mouse_context_menu = Some(MouseContextMenu::new(
 2030            self,
 2031            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2032            context_menu,
 2033            window,
 2034            cx,
 2035        ));
 2036    }
 2037
 2038    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2039        self.mouse_context_menu
 2040            .as_ref()
 2041            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2042    }
 2043
 2044    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2045        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2046    }
 2047
 2048    fn key_context_internal(
 2049        &self,
 2050        has_active_edit_prediction: bool,
 2051        window: &Window,
 2052        cx: &App,
 2053    ) -> KeyContext {
 2054        let mut key_context = KeyContext::new_with_defaults();
 2055        key_context.add("Editor");
 2056        let mode = match self.mode {
 2057            EditorMode::SingleLine { .. } => "single_line",
 2058            EditorMode::AutoHeight { .. } => "auto_height",
 2059            EditorMode::Minimap { .. } => "minimap",
 2060            EditorMode::Full { .. } => "full",
 2061        };
 2062
 2063        if EditorSettings::jupyter_enabled(cx) {
 2064            key_context.add("jupyter");
 2065        }
 2066
 2067        key_context.set("mode", mode);
 2068        if self.pending_rename.is_some() {
 2069            key_context.add("renaming");
 2070        }
 2071
 2072        match self.context_menu.borrow().as_ref() {
 2073            Some(CodeContextMenu::Completions(_)) => {
 2074                key_context.add("menu");
 2075                key_context.add("showing_completions");
 2076            }
 2077            Some(CodeContextMenu::CodeActions(_)) => {
 2078                key_context.add("menu");
 2079                key_context.add("showing_code_actions")
 2080            }
 2081            None => {}
 2082        }
 2083
 2084        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2085        if !self.focus_handle(cx).contains_focused(window, cx)
 2086            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2087        {
 2088            for addon in self.addons.values() {
 2089                addon.extend_key_context(&mut key_context, cx)
 2090            }
 2091        }
 2092
 2093        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2094            if let Some(extension) = singleton_buffer
 2095                .read(cx)
 2096                .file()
 2097                .and_then(|file| file.path().extension()?.to_str())
 2098            {
 2099                key_context.set("extension", extension.to_string());
 2100            }
 2101        } else {
 2102            key_context.add("multibuffer");
 2103        }
 2104
 2105        if has_active_edit_prediction {
 2106            if self.edit_prediction_in_conflict() {
 2107                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2108            } else {
 2109                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2110                key_context.add("copilot_suggestion");
 2111            }
 2112        }
 2113
 2114        if self.selection_mark_mode {
 2115            key_context.add("selection_mode");
 2116        }
 2117
 2118        key_context
 2119    }
 2120
 2121    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2122        self.mouse_cursor_hidden = match origin {
 2123            HideMouseCursorOrigin::TypingAction => {
 2124                matches!(
 2125                    self.hide_mouse_mode,
 2126                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2127                )
 2128            }
 2129            HideMouseCursorOrigin::MovementAction => {
 2130                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2131            }
 2132        };
 2133    }
 2134
 2135    pub fn edit_prediction_in_conflict(&self) -> bool {
 2136        if !self.show_edit_predictions_in_menu() {
 2137            return false;
 2138        }
 2139
 2140        let showing_completions = self
 2141            .context_menu
 2142            .borrow()
 2143            .as_ref()
 2144            .map_or(false, |context| {
 2145                matches!(context, CodeContextMenu::Completions(_))
 2146            });
 2147
 2148        showing_completions
 2149            || self.edit_prediction_requires_modifier()
 2150            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2151            // bindings to insert tab characters.
 2152            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2153    }
 2154
 2155    pub fn accept_edit_prediction_keybind(
 2156        &self,
 2157        window: &Window,
 2158        cx: &App,
 2159    ) -> AcceptEditPredictionBinding {
 2160        let key_context = self.key_context_internal(true, window, cx);
 2161        let in_conflict = self.edit_prediction_in_conflict();
 2162
 2163        AcceptEditPredictionBinding(
 2164            window
 2165                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2166                .into_iter()
 2167                .filter(|binding| {
 2168                    !in_conflict
 2169                        || binding
 2170                            .keystrokes()
 2171                            .first()
 2172                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2173                })
 2174                .rev()
 2175                .min_by_key(|binding| {
 2176                    binding
 2177                        .keystrokes()
 2178                        .first()
 2179                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2180                }),
 2181        )
 2182    }
 2183
 2184    pub fn new_file(
 2185        workspace: &mut Workspace,
 2186        _: &workspace::NewFile,
 2187        window: &mut Window,
 2188        cx: &mut Context<Workspace>,
 2189    ) {
 2190        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2191            "Failed to create buffer",
 2192            window,
 2193            cx,
 2194            |e, _, _| match e.error_code() {
 2195                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2196                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2197                e.error_tag("required").unwrap_or("the latest version")
 2198            )),
 2199                _ => None,
 2200            },
 2201        );
 2202    }
 2203
 2204    pub fn new_in_workspace(
 2205        workspace: &mut Workspace,
 2206        window: &mut Window,
 2207        cx: &mut Context<Workspace>,
 2208    ) -> Task<Result<Entity<Editor>>> {
 2209        let project = workspace.project().clone();
 2210        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2211
 2212        cx.spawn_in(window, async move |workspace, cx| {
 2213            let buffer = create.await?;
 2214            workspace.update_in(cx, |workspace, window, cx| {
 2215                let editor =
 2216                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2217                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2218                editor
 2219            })
 2220        })
 2221    }
 2222
 2223    fn new_file_vertical(
 2224        workspace: &mut Workspace,
 2225        _: &workspace::NewFileSplitVertical,
 2226        window: &mut Window,
 2227        cx: &mut Context<Workspace>,
 2228    ) {
 2229        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2230    }
 2231
 2232    fn new_file_horizontal(
 2233        workspace: &mut Workspace,
 2234        _: &workspace::NewFileSplitHorizontal,
 2235        window: &mut Window,
 2236        cx: &mut Context<Workspace>,
 2237    ) {
 2238        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2239    }
 2240
 2241    fn new_file_in_direction(
 2242        workspace: &mut Workspace,
 2243        direction: SplitDirection,
 2244        window: &mut Window,
 2245        cx: &mut Context<Workspace>,
 2246    ) {
 2247        let project = workspace.project().clone();
 2248        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2249
 2250        cx.spawn_in(window, async move |workspace, cx| {
 2251            let buffer = create.await?;
 2252            workspace.update_in(cx, move |workspace, window, cx| {
 2253                workspace.split_item(
 2254                    direction,
 2255                    Box::new(
 2256                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2257                    ),
 2258                    window,
 2259                    cx,
 2260                )
 2261            })?;
 2262            anyhow::Ok(())
 2263        })
 2264        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2265            match e.error_code() {
 2266                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2267                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2268                e.error_tag("required").unwrap_or("the latest version")
 2269            )),
 2270                _ => None,
 2271            }
 2272        });
 2273    }
 2274
 2275    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2276        self.leader_id
 2277    }
 2278
 2279    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2280        &self.buffer
 2281    }
 2282
 2283    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2284        self.workspace.as_ref()?.0.upgrade()
 2285    }
 2286
 2287    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2288        self.buffer().read(cx).title(cx)
 2289    }
 2290
 2291    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2292        let git_blame_gutter_max_author_length = self
 2293            .render_git_blame_gutter(cx)
 2294            .then(|| {
 2295                if let Some(blame) = self.blame.as_ref() {
 2296                    let max_author_length =
 2297                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2298                    Some(max_author_length)
 2299                } else {
 2300                    None
 2301                }
 2302            })
 2303            .flatten();
 2304
 2305        EditorSnapshot {
 2306            mode: self.mode.clone(),
 2307            show_gutter: self.show_gutter,
 2308            show_line_numbers: self.show_line_numbers,
 2309            show_git_diff_gutter: self.show_git_diff_gutter,
 2310            show_runnables: self.show_runnables,
 2311            show_breakpoints: self.show_breakpoints,
 2312            git_blame_gutter_max_author_length,
 2313            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2314            scroll_anchor: self.scroll_manager.anchor(),
 2315            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2316            placeholder_text: self.placeholder_text.clone(),
 2317            is_focused: self.focus_handle.is_focused(window),
 2318            current_line_highlight: self
 2319                .current_line_highlight
 2320                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2321            gutter_hovered: self.gutter_hovered,
 2322        }
 2323    }
 2324
 2325    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2326        self.buffer.read(cx).language_at(point, cx)
 2327    }
 2328
 2329    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2330        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2331    }
 2332
 2333    pub fn active_excerpt(
 2334        &self,
 2335        cx: &App,
 2336    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2337        self.buffer
 2338            .read(cx)
 2339            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2340    }
 2341
 2342    pub fn mode(&self) -> &EditorMode {
 2343        &self.mode
 2344    }
 2345
 2346    pub fn set_mode(&mut self, mode: EditorMode) {
 2347        self.mode = mode;
 2348    }
 2349
 2350    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2351        self.collaboration_hub.as_deref()
 2352    }
 2353
 2354    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2355        self.collaboration_hub = Some(hub);
 2356    }
 2357
 2358    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2359        self.in_project_search = in_project_search;
 2360    }
 2361
 2362    pub fn set_custom_context_menu(
 2363        &mut self,
 2364        f: impl 'static
 2365        + Fn(
 2366            &mut Self,
 2367            DisplayPoint,
 2368            &mut Window,
 2369            &mut Context<Self>,
 2370        ) -> Option<Entity<ui::ContextMenu>>,
 2371    ) {
 2372        self.custom_context_menu = Some(Box::new(f))
 2373    }
 2374
 2375    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2376        self.completion_provider = provider;
 2377    }
 2378
 2379    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2380        self.semantics_provider.clone()
 2381    }
 2382
 2383    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2384        self.semantics_provider = provider;
 2385    }
 2386
 2387    pub fn set_edit_prediction_provider<T>(
 2388        &mut self,
 2389        provider: Option<Entity<T>>,
 2390        window: &mut Window,
 2391        cx: &mut Context<Self>,
 2392    ) where
 2393        T: EditPredictionProvider,
 2394    {
 2395        self.edit_prediction_provider =
 2396            provider.map(|provider| RegisteredInlineCompletionProvider {
 2397                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2398                    if this.focus_handle.is_focused(window) {
 2399                        this.update_visible_inline_completion(window, cx);
 2400                    }
 2401                }),
 2402                provider: Arc::new(provider),
 2403            });
 2404        self.update_edit_prediction_settings(cx);
 2405        self.refresh_inline_completion(false, false, window, cx);
 2406    }
 2407
 2408    pub fn placeholder_text(&self) -> Option<&str> {
 2409        self.placeholder_text.as_deref()
 2410    }
 2411
 2412    pub fn set_placeholder_text(
 2413        &mut self,
 2414        placeholder_text: impl Into<Arc<str>>,
 2415        cx: &mut Context<Self>,
 2416    ) {
 2417        let placeholder_text = Some(placeholder_text.into());
 2418        if self.placeholder_text != placeholder_text {
 2419            self.placeholder_text = placeholder_text;
 2420            cx.notify();
 2421        }
 2422    }
 2423
 2424    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2425        self.cursor_shape = cursor_shape;
 2426
 2427        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2428        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2429
 2430        cx.notify();
 2431    }
 2432
 2433    pub fn set_current_line_highlight(
 2434        &mut self,
 2435        current_line_highlight: Option<CurrentLineHighlight>,
 2436    ) {
 2437        self.current_line_highlight = current_line_highlight;
 2438    }
 2439
 2440    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2441        self.collapse_matches = collapse_matches;
 2442    }
 2443
 2444    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2445        let buffers = self.buffer.read(cx).all_buffers();
 2446        let Some(project) = self.project.as_ref() else {
 2447            return;
 2448        };
 2449        project.update(cx, |project, cx| {
 2450            for buffer in buffers {
 2451                self.registered_buffers
 2452                    .entry(buffer.read(cx).remote_id())
 2453                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2454            }
 2455        })
 2456    }
 2457
 2458    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2459        if self.collapse_matches {
 2460            return range.start..range.start;
 2461        }
 2462        range.clone()
 2463    }
 2464
 2465    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2466        if self.display_map.read(cx).clip_at_line_ends != clip {
 2467            self.display_map
 2468                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2469        }
 2470    }
 2471
 2472    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2473        self.input_enabled = input_enabled;
 2474    }
 2475
 2476    pub fn set_inline_completions_hidden_for_vim_mode(
 2477        &mut self,
 2478        hidden: bool,
 2479        window: &mut Window,
 2480        cx: &mut Context<Self>,
 2481    ) {
 2482        if hidden != self.inline_completions_hidden_for_vim_mode {
 2483            self.inline_completions_hidden_for_vim_mode = hidden;
 2484            if hidden {
 2485                self.update_visible_inline_completion(window, cx);
 2486            } else {
 2487                self.refresh_inline_completion(true, false, window, cx);
 2488            }
 2489        }
 2490    }
 2491
 2492    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2493        self.menu_inline_completions_policy = value;
 2494    }
 2495
 2496    pub fn set_autoindent(&mut self, autoindent: bool) {
 2497        if autoindent {
 2498            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2499        } else {
 2500            self.autoindent_mode = None;
 2501        }
 2502    }
 2503
 2504    pub fn read_only(&self, cx: &App) -> bool {
 2505        self.read_only || self.buffer.read(cx).read_only()
 2506    }
 2507
 2508    pub fn set_read_only(&mut self, read_only: bool) {
 2509        self.read_only = read_only;
 2510    }
 2511
 2512    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2513        self.use_autoclose = autoclose;
 2514    }
 2515
 2516    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2517        self.use_auto_surround = auto_surround;
 2518    }
 2519
 2520    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2521        self.auto_replace_emoji_shortcode = auto_replace;
 2522    }
 2523
 2524    pub fn toggle_edit_predictions(
 2525        &mut self,
 2526        _: &ToggleEditPrediction,
 2527        window: &mut Window,
 2528        cx: &mut Context<Self>,
 2529    ) {
 2530        if self.show_inline_completions_override.is_some() {
 2531            self.set_show_edit_predictions(None, window, cx);
 2532        } else {
 2533            let show_edit_predictions = !self.edit_predictions_enabled();
 2534            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2535        }
 2536    }
 2537
 2538    pub fn set_show_edit_predictions(
 2539        &mut self,
 2540        show_edit_predictions: Option<bool>,
 2541        window: &mut Window,
 2542        cx: &mut Context<Self>,
 2543    ) {
 2544        self.show_inline_completions_override = show_edit_predictions;
 2545        self.update_edit_prediction_settings(cx);
 2546
 2547        if let Some(false) = show_edit_predictions {
 2548            self.discard_inline_completion(false, cx);
 2549        } else {
 2550            self.refresh_inline_completion(false, true, window, cx);
 2551        }
 2552    }
 2553
 2554    fn inline_completions_disabled_in_scope(
 2555        &self,
 2556        buffer: &Entity<Buffer>,
 2557        buffer_position: language::Anchor,
 2558        cx: &App,
 2559    ) -> bool {
 2560        let snapshot = buffer.read(cx).snapshot();
 2561        let settings = snapshot.settings_at(buffer_position, cx);
 2562
 2563        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2564            return false;
 2565        };
 2566
 2567        scope.override_name().map_or(false, |scope_name| {
 2568            settings
 2569                .edit_predictions_disabled_in
 2570                .iter()
 2571                .any(|s| s == scope_name)
 2572        })
 2573    }
 2574
 2575    pub fn set_use_modal_editing(&mut self, to: bool) {
 2576        self.use_modal_editing = to;
 2577    }
 2578
 2579    pub fn use_modal_editing(&self) -> bool {
 2580        self.use_modal_editing
 2581    }
 2582
 2583    fn selections_did_change(
 2584        &mut self,
 2585        local: bool,
 2586        old_cursor_position: &Anchor,
 2587        show_completions: bool,
 2588        window: &mut Window,
 2589        cx: &mut Context<Self>,
 2590    ) {
 2591        window.invalidate_character_coordinates();
 2592
 2593        // Copy selections to primary selection buffer
 2594        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2595        if local {
 2596            let selections = self.selections.all::<usize>(cx);
 2597            let buffer_handle = self.buffer.read(cx).read(cx);
 2598
 2599            let mut text = String::new();
 2600            for (index, selection) in selections.iter().enumerate() {
 2601                let text_for_selection = buffer_handle
 2602                    .text_for_range(selection.start..selection.end)
 2603                    .collect::<String>();
 2604
 2605                text.push_str(&text_for_selection);
 2606                if index != selections.len() - 1 {
 2607                    text.push('\n');
 2608                }
 2609            }
 2610
 2611            if !text.is_empty() {
 2612                cx.write_to_primary(ClipboardItem::new_string(text));
 2613            }
 2614        }
 2615
 2616        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2617            self.buffer.update(cx, |buffer, cx| {
 2618                buffer.set_active_selections(
 2619                    &self.selections.disjoint_anchors(),
 2620                    self.selections.line_mode,
 2621                    self.cursor_shape,
 2622                    cx,
 2623                )
 2624            });
 2625        }
 2626        let display_map = self
 2627            .display_map
 2628            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2629        let buffer = &display_map.buffer_snapshot;
 2630        self.add_selections_state = None;
 2631        self.select_next_state = None;
 2632        self.select_prev_state = None;
 2633        self.select_syntax_node_history.try_clear();
 2634        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2635        self.snippet_stack
 2636            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2637        self.take_rename(false, window, cx);
 2638
 2639        let new_cursor_position = self.selections.newest_anchor().head();
 2640
 2641        self.push_to_nav_history(
 2642            *old_cursor_position,
 2643            Some(new_cursor_position.to_point(buffer)),
 2644            false,
 2645            cx,
 2646        );
 2647
 2648        if local {
 2649            let new_cursor_position = self.selections.newest_anchor().head();
 2650            let mut context_menu = self.context_menu.borrow_mut();
 2651            let completion_menu = match context_menu.as_ref() {
 2652                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2653                _ => {
 2654                    *context_menu = None;
 2655                    None
 2656                }
 2657            };
 2658            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2659                if !self.registered_buffers.contains_key(&buffer_id) {
 2660                    if let Some(project) = self.project.as_ref() {
 2661                        project.update(cx, |project, cx| {
 2662                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2663                                return;
 2664                            };
 2665                            self.registered_buffers.insert(
 2666                                buffer_id,
 2667                                project.register_buffer_with_language_servers(&buffer, cx),
 2668                            );
 2669                        })
 2670                    }
 2671                }
 2672            }
 2673
 2674            if let Some(completion_menu) = completion_menu {
 2675                let cursor_position = new_cursor_position.to_offset(buffer);
 2676                let (word_range, kind) =
 2677                    buffer.surrounding_word(completion_menu.initial_position, true);
 2678                if kind == Some(CharKind::Word)
 2679                    && word_range.to_inclusive().contains(&cursor_position)
 2680                {
 2681                    let mut completion_menu = completion_menu.clone();
 2682                    drop(context_menu);
 2683
 2684                    let query = Self::completion_query(buffer, cursor_position);
 2685                    cx.spawn(async move |this, cx| {
 2686                        completion_menu
 2687                            .filter(query.as_deref(), cx.background_executor().clone())
 2688                            .await;
 2689
 2690                        this.update(cx, |this, cx| {
 2691                            let mut context_menu = this.context_menu.borrow_mut();
 2692                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2693                            else {
 2694                                return;
 2695                            };
 2696
 2697                            if menu.id > completion_menu.id {
 2698                                return;
 2699                            }
 2700
 2701                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2702                            drop(context_menu);
 2703                            cx.notify();
 2704                        })
 2705                    })
 2706                    .detach();
 2707
 2708                    if show_completions {
 2709                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2710                    }
 2711                } else {
 2712                    drop(context_menu);
 2713                    self.hide_context_menu(window, cx);
 2714                }
 2715            } else {
 2716                drop(context_menu);
 2717            }
 2718
 2719            hide_hover(self, cx);
 2720
 2721            if old_cursor_position.to_display_point(&display_map).row()
 2722                != new_cursor_position.to_display_point(&display_map).row()
 2723            {
 2724                self.available_code_actions.take();
 2725            }
 2726            self.refresh_code_actions(window, cx);
 2727            self.refresh_document_highlights(cx);
 2728            self.refresh_selected_text_highlights(false, window, cx);
 2729            refresh_matching_bracket_highlights(self, window, cx);
 2730            self.update_visible_inline_completion(window, cx);
 2731            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2732            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2733            self.inline_blame_popover.take();
 2734            if self.git_blame_inline_enabled {
 2735                self.start_inline_blame_timer(window, cx);
 2736            }
 2737        }
 2738
 2739        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2740        cx.emit(EditorEvent::SelectionsChanged { local });
 2741
 2742        let selections = &self.selections.disjoint;
 2743        if selections.len() == 1 {
 2744            cx.emit(SearchEvent::ActiveMatchChanged)
 2745        }
 2746        if local {
 2747            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2748                let inmemory_selections = selections
 2749                    .iter()
 2750                    .map(|s| {
 2751                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2752                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2753                    })
 2754                    .collect();
 2755                self.update_restoration_data(cx, |data| {
 2756                    data.selections = inmemory_selections;
 2757                });
 2758
 2759                if WorkspaceSettings::get(None, cx).restore_on_startup
 2760                    != RestoreOnStartupBehavior::None
 2761                {
 2762                    if let Some(workspace_id) =
 2763                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2764                    {
 2765                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2766                        let selections = selections.clone();
 2767                        let background_executor = cx.background_executor().clone();
 2768                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2769                        self.serialize_selections = cx.background_spawn(async move {
 2770                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2771                    let db_selections = selections
 2772                        .iter()
 2773                        .map(|selection| {
 2774                            (
 2775                                selection.start.to_offset(&snapshot),
 2776                                selection.end.to_offset(&snapshot),
 2777                            )
 2778                        })
 2779                        .collect();
 2780
 2781                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2782                        .await
 2783                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2784                        .log_err();
 2785                });
 2786                    }
 2787                }
 2788            }
 2789        }
 2790
 2791        cx.notify();
 2792    }
 2793
 2794    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2795        use text::ToOffset as _;
 2796        use text::ToPoint as _;
 2797
 2798        if self.mode.is_minimap()
 2799            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2800        {
 2801            return;
 2802        }
 2803
 2804        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2805            return;
 2806        };
 2807
 2808        let snapshot = singleton.read(cx).snapshot();
 2809        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2810            let display_snapshot = display_map.snapshot(cx);
 2811
 2812            display_snapshot
 2813                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2814                .map(|fold| {
 2815                    fold.range.start.text_anchor.to_point(&snapshot)
 2816                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2817                })
 2818                .collect()
 2819        });
 2820        self.update_restoration_data(cx, |data| {
 2821            data.folds = inmemory_folds;
 2822        });
 2823
 2824        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2825            return;
 2826        };
 2827        let background_executor = cx.background_executor().clone();
 2828        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2829        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2830            display_map
 2831                .snapshot(cx)
 2832                .folds_in_range(0..snapshot.len())
 2833                .map(|fold| {
 2834                    (
 2835                        fold.range.start.text_anchor.to_offset(&snapshot),
 2836                        fold.range.end.text_anchor.to_offset(&snapshot),
 2837                    )
 2838                })
 2839                .collect()
 2840        });
 2841        self.serialize_folds = cx.background_spawn(async move {
 2842            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2843            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2844                .await
 2845                .with_context(|| {
 2846                    format!(
 2847                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2848                    )
 2849                })
 2850                .log_err();
 2851        });
 2852    }
 2853
 2854    pub fn sync_selections(
 2855        &mut self,
 2856        other: Entity<Editor>,
 2857        cx: &mut Context<Self>,
 2858    ) -> gpui::Subscription {
 2859        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2860        self.selections.change_with(cx, |selections| {
 2861            selections.select_anchors(other_selections);
 2862        });
 2863
 2864        let other_subscription =
 2865            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2866                EditorEvent::SelectionsChanged { local: true } => {
 2867                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2868                    if other_selections.is_empty() {
 2869                        return;
 2870                    }
 2871                    this.selections.change_with(cx, |selections| {
 2872                        selections.select_anchors(other_selections);
 2873                    });
 2874                }
 2875                _ => {}
 2876            });
 2877
 2878        let this_subscription =
 2879            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2880                EditorEvent::SelectionsChanged { local: true } => {
 2881                    let these_selections = this.selections.disjoint.to_vec();
 2882                    if these_selections.is_empty() {
 2883                        return;
 2884                    }
 2885                    other.update(cx, |other_editor, cx| {
 2886                        other_editor.selections.change_with(cx, |selections| {
 2887                            selections.select_anchors(these_selections);
 2888                        })
 2889                    });
 2890                }
 2891                _ => {}
 2892            });
 2893
 2894        Subscription::join(other_subscription, this_subscription)
 2895    }
 2896
 2897    pub fn change_selections<R>(
 2898        &mut self,
 2899        autoscroll: Option<Autoscroll>,
 2900        window: &mut Window,
 2901        cx: &mut Context<Self>,
 2902        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2903    ) -> R {
 2904        self.change_selections_inner(autoscroll, true, window, cx, change)
 2905    }
 2906
 2907    fn change_selections_inner<R>(
 2908        &mut self,
 2909        autoscroll: Option<Autoscroll>,
 2910        request_completions: bool,
 2911        window: &mut Window,
 2912        cx: &mut Context<Self>,
 2913        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2914    ) -> R {
 2915        let old_cursor_position = self.selections.newest_anchor().head();
 2916        self.push_to_selection_history();
 2917
 2918        let (changed, result) = self.selections.change_with(cx, change);
 2919
 2920        if changed {
 2921            if let Some(autoscroll) = autoscroll {
 2922                self.request_autoscroll(autoscroll, cx);
 2923            }
 2924            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2925
 2926            if self.should_open_signature_help_automatically(
 2927                &old_cursor_position,
 2928                self.signature_help_state.backspace_pressed(),
 2929                cx,
 2930            ) {
 2931                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2932            }
 2933            self.signature_help_state.set_backspace_pressed(false);
 2934        }
 2935
 2936        result
 2937    }
 2938
 2939    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2940    where
 2941        I: IntoIterator<Item = (Range<S>, T)>,
 2942        S: ToOffset,
 2943        T: Into<Arc<str>>,
 2944    {
 2945        if self.read_only(cx) {
 2946            return;
 2947        }
 2948
 2949        self.buffer
 2950            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2951    }
 2952
 2953    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2954    where
 2955        I: IntoIterator<Item = (Range<S>, T)>,
 2956        S: ToOffset,
 2957        T: Into<Arc<str>>,
 2958    {
 2959        if self.read_only(cx) {
 2960            return;
 2961        }
 2962
 2963        self.buffer.update(cx, |buffer, cx| {
 2964            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2965        });
 2966    }
 2967
 2968    pub fn edit_with_block_indent<I, S, T>(
 2969        &mut self,
 2970        edits: I,
 2971        original_indent_columns: Vec<Option<u32>>,
 2972        cx: &mut Context<Self>,
 2973    ) where
 2974        I: IntoIterator<Item = (Range<S>, T)>,
 2975        S: ToOffset,
 2976        T: Into<Arc<str>>,
 2977    {
 2978        if self.read_only(cx) {
 2979            return;
 2980        }
 2981
 2982        self.buffer.update(cx, |buffer, cx| {
 2983            buffer.edit(
 2984                edits,
 2985                Some(AutoindentMode::Block {
 2986                    original_indent_columns,
 2987                }),
 2988                cx,
 2989            )
 2990        });
 2991    }
 2992
 2993    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2994        self.hide_context_menu(window, cx);
 2995
 2996        match phase {
 2997            SelectPhase::Begin {
 2998                position,
 2999                add,
 3000                click_count,
 3001            } => self.begin_selection(position, add, click_count, window, cx),
 3002            SelectPhase::BeginColumnar {
 3003                position,
 3004                goal_column,
 3005                reset,
 3006            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3007            SelectPhase::Extend {
 3008                position,
 3009                click_count,
 3010            } => self.extend_selection(position, click_count, window, cx),
 3011            SelectPhase::Update {
 3012                position,
 3013                goal_column,
 3014                scroll_delta,
 3015            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3016            SelectPhase::End => self.end_selection(window, cx),
 3017        }
 3018    }
 3019
 3020    fn extend_selection(
 3021        &mut self,
 3022        position: DisplayPoint,
 3023        click_count: usize,
 3024        window: &mut Window,
 3025        cx: &mut Context<Self>,
 3026    ) {
 3027        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3028        let tail = self.selections.newest::<usize>(cx).tail();
 3029        self.begin_selection(position, false, click_count, window, cx);
 3030
 3031        let position = position.to_offset(&display_map, Bias::Left);
 3032        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3033
 3034        let mut pending_selection = self
 3035            .selections
 3036            .pending_anchor()
 3037            .expect("extend_selection not called with pending selection");
 3038        if position >= tail {
 3039            pending_selection.start = tail_anchor;
 3040        } else {
 3041            pending_selection.end = tail_anchor;
 3042            pending_selection.reversed = true;
 3043        }
 3044
 3045        let mut pending_mode = self.selections.pending_mode().unwrap();
 3046        match &mut pending_mode {
 3047            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3048            _ => {}
 3049        }
 3050
 3051        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3052
 3053        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3054            s.set_pending(pending_selection, pending_mode)
 3055        });
 3056    }
 3057
 3058    fn begin_selection(
 3059        &mut self,
 3060        position: DisplayPoint,
 3061        add: bool,
 3062        click_count: usize,
 3063        window: &mut Window,
 3064        cx: &mut Context<Self>,
 3065    ) {
 3066        if !self.focus_handle.is_focused(window) {
 3067            self.last_focused_descendant = None;
 3068            window.focus(&self.focus_handle);
 3069        }
 3070
 3071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3072        let buffer = &display_map.buffer_snapshot;
 3073        let position = display_map.clip_point(position, Bias::Left);
 3074
 3075        let start;
 3076        let end;
 3077        let mode;
 3078        let mut auto_scroll;
 3079        match click_count {
 3080            1 => {
 3081                start = buffer.anchor_before(position.to_point(&display_map));
 3082                end = start;
 3083                mode = SelectMode::Character;
 3084                auto_scroll = true;
 3085            }
 3086            2 => {
 3087                let range = movement::surrounding_word(&display_map, position);
 3088                start = buffer.anchor_before(range.start.to_point(&display_map));
 3089                end = buffer.anchor_before(range.end.to_point(&display_map));
 3090                mode = SelectMode::Word(start..end);
 3091                auto_scroll = true;
 3092            }
 3093            3 => {
 3094                let position = display_map
 3095                    .clip_point(position, Bias::Left)
 3096                    .to_point(&display_map);
 3097                let line_start = display_map.prev_line_boundary(position).0;
 3098                let next_line_start = buffer.clip_point(
 3099                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3100                    Bias::Left,
 3101                );
 3102                start = buffer.anchor_before(line_start);
 3103                end = buffer.anchor_before(next_line_start);
 3104                mode = SelectMode::Line(start..end);
 3105                auto_scroll = true;
 3106            }
 3107            _ => {
 3108                start = buffer.anchor_before(0);
 3109                end = buffer.anchor_before(buffer.len());
 3110                mode = SelectMode::All;
 3111                auto_scroll = false;
 3112            }
 3113        }
 3114        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3115
 3116        let point_to_delete: Option<usize> = {
 3117            let selected_points: Vec<Selection<Point>> =
 3118                self.selections.disjoint_in_range(start..end, cx);
 3119
 3120            if !add || click_count > 1 {
 3121                None
 3122            } else if !selected_points.is_empty() {
 3123                Some(selected_points[0].id)
 3124            } else {
 3125                let clicked_point_already_selected =
 3126                    self.selections.disjoint.iter().find(|selection| {
 3127                        selection.start.to_point(buffer) == start.to_point(buffer)
 3128                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3129                    });
 3130
 3131                clicked_point_already_selected.map(|selection| selection.id)
 3132            }
 3133        };
 3134
 3135        let selections_count = self.selections.count();
 3136
 3137        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3138            if let Some(point_to_delete) = point_to_delete {
 3139                s.delete(point_to_delete);
 3140
 3141                if selections_count == 1 {
 3142                    s.set_pending_anchor_range(start..end, mode);
 3143                }
 3144            } else {
 3145                if !add {
 3146                    s.clear_disjoint();
 3147                }
 3148
 3149                s.set_pending_anchor_range(start..end, mode);
 3150            }
 3151        });
 3152    }
 3153
 3154    fn begin_columnar_selection(
 3155        &mut self,
 3156        position: DisplayPoint,
 3157        goal_column: u32,
 3158        reset: bool,
 3159        window: &mut Window,
 3160        cx: &mut Context<Self>,
 3161    ) {
 3162        if !self.focus_handle.is_focused(window) {
 3163            self.last_focused_descendant = None;
 3164            window.focus(&self.focus_handle);
 3165        }
 3166
 3167        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3168
 3169        if reset {
 3170            let pointer_position = display_map
 3171                .buffer_snapshot
 3172                .anchor_before(position.to_point(&display_map));
 3173
 3174            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3175                s.clear_disjoint();
 3176                s.set_pending_anchor_range(
 3177                    pointer_position..pointer_position,
 3178                    SelectMode::Character,
 3179                );
 3180            });
 3181        }
 3182
 3183        let tail = self.selections.newest::<Point>(cx).tail();
 3184        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3185
 3186        if !reset {
 3187            self.select_columns(
 3188                tail.to_display_point(&display_map),
 3189                position,
 3190                goal_column,
 3191                &display_map,
 3192                window,
 3193                cx,
 3194            );
 3195        }
 3196    }
 3197
 3198    fn update_selection(
 3199        &mut self,
 3200        position: DisplayPoint,
 3201        goal_column: u32,
 3202        scroll_delta: gpui::Point<f32>,
 3203        window: &mut Window,
 3204        cx: &mut Context<Self>,
 3205    ) {
 3206        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3207
 3208        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3209            let tail = tail.to_display_point(&display_map);
 3210            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3211        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3212            let buffer = self.buffer.read(cx).snapshot(cx);
 3213            let head;
 3214            let tail;
 3215            let mode = self.selections.pending_mode().unwrap();
 3216            match &mode {
 3217                SelectMode::Character => {
 3218                    head = position.to_point(&display_map);
 3219                    tail = pending.tail().to_point(&buffer);
 3220                }
 3221                SelectMode::Word(original_range) => {
 3222                    let original_display_range = original_range.start.to_display_point(&display_map)
 3223                        ..original_range.end.to_display_point(&display_map);
 3224                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3225                        ..original_display_range.end.to_point(&display_map);
 3226                    if movement::is_inside_word(&display_map, position)
 3227                        || original_display_range.contains(&position)
 3228                    {
 3229                        let word_range = movement::surrounding_word(&display_map, position);
 3230                        if word_range.start < original_display_range.start {
 3231                            head = word_range.start.to_point(&display_map);
 3232                        } else {
 3233                            head = word_range.end.to_point(&display_map);
 3234                        }
 3235                    } else {
 3236                        head = position.to_point(&display_map);
 3237                    }
 3238
 3239                    if head <= original_buffer_range.start {
 3240                        tail = original_buffer_range.end;
 3241                    } else {
 3242                        tail = original_buffer_range.start;
 3243                    }
 3244                }
 3245                SelectMode::Line(original_range) => {
 3246                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3247
 3248                    let position = display_map
 3249                        .clip_point(position, Bias::Left)
 3250                        .to_point(&display_map);
 3251                    let line_start = display_map.prev_line_boundary(position).0;
 3252                    let next_line_start = buffer.clip_point(
 3253                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3254                        Bias::Left,
 3255                    );
 3256
 3257                    if line_start < original_range.start {
 3258                        head = line_start
 3259                    } else {
 3260                        head = next_line_start
 3261                    }
 3262
 3263                    if head <= original_range.start {
 3264                        tail = original_range.end;
 3265                    } else {
 3266                        tail = original_range.start;
 3267                    }
 3268                }
 3269                SelectMode::All => {
 3270                    return;
 3271                }
 3272            };
 3273
 3274            if head < tail {
 3275                pending.start = buffer.anchor_before(head);
 3276                pending.end = buffer.anchor_before(tail);
 3277                pending.reversed = true;
 3278            } else {
 3279                pending.start = buffer.anchor_before(tail);
 3280                pending.end = buffer.anchor_before(head);
 3281                pending.reversed = false;
 3282            }
 3283
 3284            self.change_selections(None, window, cx, |s| {
 3285                s.set_pending(pending, mode);
 3286            });
 3287        } else {
 3288            log::error!("update_selection dispatched with no pending selection");
 3289            return;
 3290        }
 3291
 3292        self.apply_scroll_delta(scroll_delta, window, cx);
 3293        cx.notify();
 3294    }
 3295
 3296    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3297        self.columnar_selection_tail.take();
 3298        if self.selections.pending_anchor().is_some() {
 3299            let selections = self.selections.all::<usize>(cx);
 3300            self.change_selections(None, window, cx, |s| {
 3301                s.select(selections);
 3302                s.clear_pending();
 3303            });
 3304        }
 3305    }
 3306
 3307    fn select_columns(
 3308        &mut self,
 3309        tail: DisplayPoint,
 3310        head: DisplayPoint,
 3311        goal_column: u32,
 3312        display_map: &DisplaySnapshot,
 3313        window: &mut Window,
 3314        cx: &mut Context<Self>,
 3315    ) {
 3316        let start_row = cmp::min(tail.row(), head.row());
 3317        let end_row = cmp::max(tail.row(), head.row());
 3318        let start_column = cmp::min(tail.column(), goal_column);
 3319        let end_column = cmp::max(tail.column(), goal_column);
 3320        let reversed = start_column < tail.column();
 3321
 3322        let selection_ranges = (start_row.0..=end_row.0)
 3323            .map(DisplayRow)
 3324            .filter_map(|row| {
 3325                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3326                    let start = display_map
 3327                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3328                        .to_point(display_map);
 3329                    let end = display_map
 3330                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3331                        .to_point(display_map);
 3332                    if reversed {
 3333                        Some(end..start)
 3334                    } else {
 3335                        Some(start..end)
 3336                    }
 3337                } else {
 3338                    None
 3339                }
 3340            })
 3341            .collect::<Vec<_>>();
 3342
 3343        self.change_selections(None, window, cx, |s| {
 3344            s.select_ranges(selection_ranges);
 3345        });
 3346        cx.notify();
 3347    }
 3348
 3349    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3350        self.selections
 3351            .all_adjusted(cx)
 3352            .iter()
 3353            .any(|selection| !selection.is_empty())
 3354    }
 3355
 3356    pub fn has_pending_nonempty_selection(&self) -> bool {
 3357        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3358            Some(Selection { start, end, .. }) => start != end,
 3359            None => false,
 3360        };
 3361
 3362        pending_nonempty_selection
 3363            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3364    }
 3365
 3366    pub fn has_pending_selection(&self) -> bool {
 3367        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3368    }
 3369
 3370    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3371        self.selection_mark_mode = false;
 3372
 3373        if self.clear_expanded_diff_hunks(cx) {
 3374            cx.notify();
 3375            return;
 3376        }
 3377        if self.dismiss_menus_and_popups(true, window, cx) {
 3378            return;
 3379        }
 3380
 3381        if self.mode.is_full()
 3382            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3383        {
 3384            return;
 3385        }
 3386
 3387        cx.propagate();
 3388    }
 3389
 3390    pub fn dismiss_menus_and_popups(
 3391        &mut self,
 3392        is_user_requested: bool,
 3393        window: &mut Window,
 3394        cx: &mut Context<Self>,
 3395    ) -> bool {
 3396        if self.take_rename(false, window, cx).is_some() {
 3397            return true;
 3398        }
 3399
 3400        if hide_hover(self, cx) {
 3401            return true;
 3402        }
 3403
 3404        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3405            return true;
 3406        }
 3407
 3408        if self.hide_context_menu(window, cx).is_some() {
 3409            return true;
 3410        }
 3411
 3412        if self.mouse_context_menu.take().is_some() {
 3413            return true;
 3414        }
 3415
 3416        if is_user_requested && self.discard_inline_completion(true, cx) {
 3417            return true;
 3418        }
 3419
 3420        if self.snippet_stack.pop().is_some() {
 3421            return true;
 3422        }
 3423
 3424        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3425            self.dismiss_diagnostics(cx);
 3426            return true;
 3427        }
 3428
 3429        false
 3430    }
 3431
 3432    fn linked_editing_ranges_for(
 3433        &self,
 3434        selection: Range<text::Anchor>,
 3435        cx: &App,
 3436    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3437        if self.linked_edit_ranges.is_empty() {
 3438            return None;
 3439        }
 3440        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3441            selection.end.buffer_id.and_then(|end_buffer_id| {
 3442                if selection.start.buffer_id != Some(end_buffer_id) {
 3443                    return None;
 3444                }
 3445                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3446                let snapshot = buffer.read(cx).snapshot();
 3447                self.linked_edit_ranges
 3448                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3449                    .map(|ranges| (ranges, snapshot, buffer))
 3450            })?;
 3451        use text::ToOffset as TO;
 3452        // find offset from the start of current range to current cursor position
 3453        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3454
 3455        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3456        let start_difference = start_offset - start_byte_offset;
 3457        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3458        let end_difference = end_offset - start_byte_offset;
 3459        // Current range has associated linked ranges.
 3460        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3461        for range in linked_ranges.iter() {
 3462            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3463            let end_offset = start_offset + end_difference;
 3464            let start_offset = start_offset + start_difference;
 3465            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3466                continue;
 3467            }
 3468            if self.selections.disjoint_anchor_ranges().any(|s| {
 3469                if s.start.buffer_id != selection.start.buffer_id
 3470                    || s.end.buffer_id != selection.end.buffer_id
 3471                {
 3472                    return false;
 3473                }
 3474                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3475                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3476            }) {
 3477                continue;
 3478            }
 3479            let start = buffer_snapshot.anchor_after(start_offset);
 3480            let end = buffer_snapshot.anchor_after(end_offset);
 3481            linked_edits
 3482                .entry(buffer.clone())
 3483                .or_default()
 3484                .push(start..end);
 3485        }
 3486        Some(linked_edits)
 3487    }
 3488
 3489    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3490        let text: Arc<str> = text.into();
 3491
 3492        if self.read_only(cx) {
 3493            return;
 3494        }
 3495
 3496        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3497
 3498        let selections = self.selections.all_adjusted(cx);
 3499        let mut bracket_inserted = false;
 3500        let mut edits = Vec::new();
 3501        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3502        let mut new_selections = Vec::with_capacity(selections.len());
 3503        let mut new_autoclose_regions = Vec::new();
 3504        let snapshot = self.buffer.read(cx).read(cx);
 3505        let mut clear_linked_edit_ranges = false;
 3506
 3507        for (selection, autoclose_region) in
 3508            self.selections_with_autoclose_regions(selections, &snapshot)
 3509        {
 3510            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3511                // Determine if the inserted text matches the opening or closing
 3512                // bracket of any of this language's bracket pairs.
 3513                let mut bracket_pair = None;
 3514                let mut is_bracket_pair_start = false;
 3515                let mut is_bracket_pair_end = false;
 3516                if !text.is_empty() {
 3517                    let mut bracket_pair_matching_end = None;
 3518                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3519                    //  and they are removing the character that triggered IME popup.
 3520                    for (pair, enabled) in scope.brackets() {
 3521                        if !pair.close && !pair.surround {
 3522                            continue;
 3523                        }
 3524
 3525                        if enabled && pair.start.ends_with(text.as_ref()) {
 3526                            let prefix_len = pair.start.len() - text.len();
 3527                            let preceding_text_matches_prefix = prefix_len == 0
 3528                                || (selection.start.column >= (prefix_len as u32)
 3529                                    && snapshot.contains_str_at(
 3530                                        Point::new(
 3531                                            selection.start.row,
 3532                                            selection.start.column - (prefix_len as u32),
 3533                                        ),
 3534                                        &pair.start[..prefix_len],
 3535                                    ));
 3536                            if preceding_text_matches_prefix {
 3537                                bracket_pair = Some(pair.clone());
 3538                                is_bracket_pair_start = true;
 3539                                break;
 3540                            }
 3541                        }
 3542                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3543                        {
 3544                            // take first bracket pair matching end, but don't break in case a later bracket
 3545                            // pair matches start
 3546                            bracket_pair_matching_end = Some(pair.clone());
 3547                        }
 3548                    }
 3549                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3550                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3551                        is_bracket_pair_end = true;
 3552                    }
 3553                }
 3554
 3555                if let Some(bracket_pair) = bracket_pair {
 3556                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3557                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3558                    let auto_surround =
 3559                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3560                    if selection.is_empty() {
 3561                        if is_bracket_pair_start {
 3562                            // If the inserted text is a suffix of an opening bracket and the
 3563                            // selection is preceded by the rest of the opening bracket, then
 3564                            // insert the closing bracket.
 3565                            let following_text_allows_autoclose = snapshot
 3566                                .chars_at(selection.start)
 3567                                .next()
 3568                                .map_or(true, |c| scope.should_autoclose_before(c));
 3569
 3570                            let preceding_text_allows_autoclose = selection.start.column == 0
 3571                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3572                                    true,
 3573                                    |c| {
 3574                                        bracket_pair.start != bracket_pair.end
 3575                                            || !snapshot
 3576                                                .char_classifier_at(selection.start)
 3577                                                .is_word(c)
 3578                                    },
 3579                                );
 3580
 3581                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3582                                && bracket_pair.start.len() == 1
 3583                            {
 3584                                let target = bracket_pair.start.chars().next().unwrap();
 3585                                let current_line_count = snapshot
 3586                                    .reversed_chars_at(selection.start)
 3587                                    .take_while(|&c| c != '\n')
 3588                                    .filter(|&c| c == target)
 3589                                    .count();
 3590                                current_line_count % 2 == 1
 3591                            } else {
 3592                                false
 3593                            };
 3594
 3595                            if autoclose
 3596                                && bracket_pair.close
 3597                                && following_text_allows_autoclose
 3598                                && preceding_text_allows_autoclose
 3599                                && !is_closing_quote
 3600                            {
 3601                                let anchor = snapshot.anchor_before(selection.end);
 3602                                new_selections.push((selection.map(|_| anchor), text.len()));
 3603                                new_autoclose_regions.push((
 3604                                    anchor,
 3605                                    text.len(),
 3606                                    selection.id,
 3607                                    bracket_pair.clone(),
 3608                                ));
 3609                                edits.push((
 3610                                    selection.range(),
 3611                                    format!("{}{}", text, bracket_pair.end).into(),
 3612                                ));
 3613                                bracket_inserted = true;
 3614                                continue;
 3615                            }
 3616                        }
 3617
 3618                        if let Some(region) = autoclose_region {
 3619                            // If the selection is followed by an auto-inserted closing bracket,
 3620                            // then don't insert that closing bracket again; just move the selection
 3621                            // past the closing bracket.
 3622                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3623                                && text.as_ref() == region.pair.end.as_str();
 3624                            if should_skip {
 3625                                let anchor = snapshot.anchor_after(selection.end);
 3626                                new_selections
 3627                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3628                                continue;
 3629                            }
 3630                        }
 3631
 3632                        let always_treat_brackets_as_autoclosed = snapshot
 3633                            .language_settings_at(selection.start, cx)
 3634                            .always_treat_brackets_as_autoclosed;
 3635                        if always_treat_brackets_as_autoclosed
 3636                            && is_bracket_pair_end
 3637                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3638                        {
 3639                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3640                            // and the inserted text is a closing bracket and the selection is followed
 3641                            // by the closing bracket then move the selection past the closing bracket.
 3642                            let anchor = snapshot.anchor_after(selection.end);
 3643                            new_selections.push((selection.map(|_| anchor), text.len()));
 3644                            continue;
 3645                        }
 3646                    }
 3647                    // If an opening bracket is 1 character long and is typed while
 3648                    // text is selected, then surround that text with the bracket pair.
 3649                    else if auto_surround
 3650                        && bracket_pair.surround
 3651                        && is_bracket_pair_start
 3652                        && bracket_pair.start.chars().count() == 1
 3653                    {
 3654                        edits.push((selection.start..selection.start, text.clone()));
 3655                        edits.push((
 3656                            selection.end..selection.end,
 3657                            bracket_pair.end.as_str().into(),
 3658                        ));
 3659                        bracket_inserted = true;
 3660                        new_selections.push((
 3661                            Selection {
 3662                                id: selection.id,
 3663                                start: snapshot.anchor_after(selection.start),
 3664                                end: snapshot.anchor_before(selection.end),
 3665                                reversed: selection.reversed,
 3666                                goal: selection.goal,
 3667                            },
 3668                            0,
 3669                        ));
 3670                        continue;
 3671                    }
 3672                }
 3673            }
 3674
 3675            if self.auto_replace_emoji_shortcode
 3676                && selection.is_empty()
 3677                && text.as_ref().ends_with(':')
 3678            {
 3679                if let Some(possible_emoji_short_code) =
 3680                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3681                {
 3682                    if !possible_emoji_short_code.is_empty() {
 3683                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3684                            let emoji_shortcode_start = Point::new(
 3685                                selection.start.row,
 3686                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3687                            );
 3688
 3689                            // Remove shortcode from buffer
 3690                            edits.push((
 3691                                emoji_shortcode_start..selection.start,
 3692                                "".to_string().into(),
 3693                            ));
 3694                            new_selections.push((
 3695                                Selection {
 3696                                    id: selection.id,
 3697                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3698                                    end: snapshot.anchor_before(selection.start),
 3699                                    reversed: selection.reversed,
 3700                                    goal: selection.goal,
 3701                                },
 3702                                0,
 3703                            ));
 3704
 3705                            // Insert emoji
 3706                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3707                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3708                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3709
 3710                            continue;
 3711                        }
 3712                    }
 3713                }
 3714            }
 3715
 3716            // If not handling any auto-close operation, then just replace the selected
 3717            // text with the given input and move the selection to the end of the
 3718            // newly inserted text.
 3719            let anchor = snapshot.anchor_after(selection.end);
 3720            if !self.linked_edit_ranges.is_empty() {
 3721                let start_anchor = snapshot.anchor_before(selection.start);
 3722
 3723                let is_word_char = text.chars().next().map_or(true, |char| {
 3724                    let classifier = snapshot
 3725                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3726                        .ignore_punctuation(true);
 3727                    classifier.is_word(char)
 3728                });
 3729
 3730                if is_word_char {
 3731                    if let Some(ranges) = self
 3732                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3733                    {
 3734                        for (buffer, edits) in ranges {
 3735                            linked_edits
 3736                                .entry(buffer.clone())
 3737                                .or_default()
 3738                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3739                        }
 3740                    }
 3741                } else {
 3742                    clear_linked_edit_ranges = true;
 3743                }
 3744            }
 3745
 3746            new_selections.push((selection.map(|_| anchor), 0));
 3747            edits.push((selection.start..selection.end, text.clone()));
 3748        }
 3749
 3750        drop(snapshot);
 3751
 3752        self.transact(window, cx, |this, window, cx| {
 3753            if clear_linked_edit_ranges {
 3754                this.linked_edit_ranges.clear();
 3755            }
 3756            let initial_buffer_versions =
 3757                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3758
 3759            this.buffer.update(cx, |buffer, cx| {
 3760                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3761            });
 3762            for (buffer, edits) in linked_edits {
 3763                buffer.update(cx, |buffer, cx| {
 3764                    let snapshot = buffer.snapshot();
 3765                    let edits = edits
 3766                        .into_iter()
 3767                        .map(|(range, text)| {
 3768                            use text::ToPoint as TP;
 3769                            let end_point = TP::to_point(&range.end, &snapshot);
 3770                            let start_point = TP::to_point(&range.start, &snapshot);
 3771                            (start_point..end_point, text)
 3772                        })
 3773                        .sorted_by_key(|(range, _)| range.start);
 3774                    buffer.edit(edits, None, cx);
 3775                })
 3776            }
 3777            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3778            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3779            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3780            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3781                .zip(new_selection_deltas)
 3782                .map(|(selection, delta)| Selection {
 3783                    id: selection.id,
 3784                    start: selection.start + delta,
 3785                    end: selection.end + delta,
 3786                    reversed: selection.reversed,
 3787                    goal: SelectionGoal::None,
 3788                })
 3789                .collect::<Vec<_>>();
 3790
 3791            let mut i = 0;
 3792            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3793                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3794                let start = map.buffer_snapshot.anchor_before(position);
 3795                let end = map.buffer_snapshot.anchor_after(position);
 3796                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3797                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3798                        Ordering::Less => i += 1,
 3799                        Ordering::Greater => break,
 3800                        Ordering::Equal => {
 3801                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3802                                Ordering::Less => i += 1,
 3803                                Ordering::Equal => break,
 3804                                Ordering::Greater => break,
 3805                            }
 3806                        }
 3807                    }
 3808                }
 3809                this.autoclose_regions.insert(
 3810                    i,
 3811                    AutocloseRegion {
 3812                        selection_id,
 3813                        range: start..end,
 3814                        pair,
 3815                    },
 3816                );
 3817            }
 3818
 3819            let had_active_inline_completion = this.has_active_inline_completion();
 3820            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3821                s.select(new_selections)
 3822            });
 3823
 3824            if !bracket_inserted {
 3825                if let Some(on_type_format_task) =
 3826                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3827                {
 3828                    on_type_format_task.detach_and_log_err(cx);
 3829                }
 3830            }
 3831
 3832            let editor_settings = EditorSettings::get_global(cx);
 3833            if bracket_inserted
 3834                && (editor_settings.auto_signature_help
 3835                    || editor_settings.show_signature_help_after_edits)
 3836            {
 3837                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3838            }
 3839
 3840            let trigger_in_words =
 3841                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3842            if this.hard_wrap.is_some() {
 3843                let latest: Range<Point> = this.selections.newest(cx).range();
 3844                if latest.is_empty()
 3845                    && this
 3846                        .buffer()
 3847                        .read(cx)
 3848                        .snapshot(cx)
 3849                        .line_len(MultiBufferRow(latest.start.row))
 3850                        == latest.start.column
 3851                {
 3852                    this.rewrap_impl(
 3853                        RewrapOptions {
 3854                            override_language_settings: true,
 3855                            preserve_existing_whitespace: true,
 3856                        },
 3857                        cx,
 3858                    )
 3859                }
 3860            }
 3861            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3862            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3863            this.refresh_inline_completion(true, false, window, cx);
 3864            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3865        });
 3866    }
 3867
 3868    fn find_possible_emoji_shortcode_at_position(
 3869        snapshot: &MultiBufferSnapshot,
 3870        position: Point,
 3871    ) -> Option<String> {
 3872        let mut chars = Vec::new();
 3873        let mut found_colon = false;
 3874        for char in snapshot.reversed_chars_at(position).take(100) {
 3875            // Found a possible emoji shortcode in the middle of the buffer
 3876            if found_colon {
 3877                if char.is_whitespace() {
 3878                    chars.reverse();
 3879                    return Some(chars.iter().collect());
 3880                }
 3881                // If the previous character is not a whitespace, we are in the middle of a word
 3882                // and we only want to complete the shortcode if the word is made up of other emojis
 3883                let mut containing_word = String::new();
 3884                for ch in snapshot
 3885                    .reversed_chars_at(position)
 3886                    .skip(chars.len() + 1)
 3887                    .take(100)
 3888                {
 3889                    if ch.is_whitespace() {
 3890                        break;
 3891                    }
 3892                    containing_word.push(ch);
 3893                }
 3894                let containing_word = containing_word.chars().rev().collect::<String>();
 3895                if util::word_consists_of_emojis(containing_word.as_str()) {
 3896                    chars.reverse();
 3897                    return Some(chars.iter().collect());
 3898                }
 3899            }
 3900
 3901            if char.is_whitespace() || !char.is_ascii() {
 3902                return None;
 3903            }
 3904            if char == ':' {
 3905                found_colon = true;
 3906            } else {
 3907                chars.push(char);
 3908            }
 3909        }
 3910        // Found a possible emoji shortcode at the beginning of the buffer
 3911        chars.reverse();
 3912        Some(chars.iter().collect())
 3913    }
 3914
 3915    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3916        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3917        self.transact(window, cx, |this, window, cx| {
 3918            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3919                let selections = this.selections.all::<usize>(cx);
 3920                let multi_buffer = this.buffer.read(cx);
 3921                let buffer = multi_buffer.snapshot(cx);
 3922                selections
 3923                    .iter()
 3924                    .map(|selection| {
 3925                        let start_point = selection.start.to_point(&buffer);
 3926                        let mut existing_indent =
 3927                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3928                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3929                        let start = selection.start;
 3930                        let end = selection.end;
 3931                        let selection_is_empty = start == end;
 3932                        let language_scope = buffer.language_scope_at(start);
 3933                        let (
 3934                            comment_delimiter,
 3935                            doc_delimiter,
 3936                            insert_extra_newline,
 3937                            indent_on_newline,
 3938                            indent_on_extra_newline,
 3939                        ) = if let Some(language) = &language_scope {
 3940                            let mut insert_extra_newline =
 3941                                insert_extra_newline_brackets(&buffer, start..end, language)
 3942                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3943
 3944                            // Comment extension on newline is allowed only for cursor selections
 3945                            let comment_delimiter = maybe!({
 3946                                if !selection_is_empty {
 3947                                    return None;
 3948                                }
 3949
 3950                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3951                                    return None;
 3952                                }
 3953
 3954                                let delimiters = language.line_comment_prefixes();
 3955                                let max_len_of_delimiter =
 3956                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3957                                let (snapshot, range) =
 3958                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3959
 3960                                let num_of_whitespaces = snapshot
 3961                                    .chars_for_range(range.clone())
 3962                                    .take_while(|c| c.is_whitespace())
 3963                                    .count();
 3964                                let comment_candidate = snapshot
 3965                                    .chars_for_range(range)
 3966                                    .skip(num_of_whitespaces)
 3967                                    .take(max_len_of_delimiter)
 3968                                    .collect::<String>();
 3969                                let (delimiter, trimmed_len) = delimiters
 3970                                    .iter()
 3971                                    .filter_map(|delimiter| {
 3972                                        let prefix = delimiter.trim_end();
 3973                                        if comment_candidate.starts_with(prefix) {
 3974                                            Some((delimiter, prefix.len()))
 3975                                        } else {
 3976                                            None
 3977                                        }
 3978                                    })
 3979                                    .max_by_key(|(_, len)| *len)?;
 3980
 3981                                let cursor_is_placed_after_comment_marker =
 3982                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3983                                if cursor_is_placed_after_comment_marker {
 3984                                    Some(delimiter.clone())
 3985                                } else {
 3986                                    None
 3987                                }
 3988                            });
 3989
 3990                            let mut indent_on_newline = IndentSize::spaces(0);
 3991                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3992
 3993                            let doc_delimiter = maybe!({
 3994                                if !selection_is_empty {
 3995                                    return None;
 3996                                }
 3997
 3998                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3999                                    return None;
 4000                                }
 4001
 4002                                let DocumentationConfig {
 4003                                    start: start_tag,
 4004                                    end: end_tag,
 4005                                    prefix: delimiter,
 4006                                    tab_size: len,
 4007                                } = language.documentation()?;
 4008
 4009                                let is_within_block_comment = buffer
 4010                                    .language_scope_at(start_point)
 4011                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4012                                if !is_within_block_comment {
 4013                                    return None;
 4014                                }
 4015
 4016                                let (snapshot, range) =
 4017                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4018
 4019                                let num_of_whitespaces = snapshot
 4020                                    .chars_for_range(range.clone())
 4021                                    .take_while(|c| c.is_whitespace())
 4022                                    .count();
 4023
 4024                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4025                                let column = start_point.column;
 4026                                let cursor_is_after_start_tag = {
 4027                                    let start_tag_len = start_tag.len();
 4028                                    let start_tag_line = snapshot
 4029                                        .chars_for_range(range.clone())
 4030                                        .skip(num_of_whitespaces)
 4031                                        .take(start_tag_len)
 4032                                        .collect::<String>();
 4033                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4034                                        num_of_whitespaces + start_tag_len <= column as usize
 4035                                    } else {
 4036                                        false
 4037                                    }
 4038                                };
 4039
 4040                                let cursor_is_after_delimiter = {
 4041                                    let delimiter_trim = delimiter.trim_end();
 4042                                    let delimiter_line = snapshot
 4043                                        .chars_for_range(range.clone())
 4044                                        .skip(num_of_whitespaces)
 4045                                        .take(delimiter_trim.len())
 4046                                        .collect::<String>();
 4047                                    if delimiter_line.starts_with(delimiter_trim) {
 4048                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4049                                    } else {
 4050                                        false
 4051                                    }
 4052                                };
 4053
 4054                                let cursor_is_before_end_tag_if_exists = {
 4055                                    let mut char_position = 0u32;
 4056                                    let mut end_tag_offset = None;
 4057
 4058                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4059                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4060                                            let chars_before_match =
 4061                                                chunk[..byte_pos].chars().count() as u32;
 4062                                            end_tag_offset =
 4063                                                Some(char_position + chars_before_match);
 4064                                            break 'outer;
 4065                                        }
 4066                                        char_position += chunk.chars().count() as u32;
 4067                                    }
 4068
 4069                                    if let Some(end_tag_offset) = end_tag_offset {
 4070                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4071                                        if cursor_is_after_start_tag {
 4072                                            if cursor_is_before_end_tag {
 4073                                                insert_extra_newline = true;
 4074                                            }
 4075                                            let cursor_is_at_start_of_end_tag =
 4076                                                column == end_tag_offset;
 4077                                            if cursor_is_at_start_of_end_tag {
 4078                                                indent_on_extra_newline.len = (*len).into();
 4079                                            }
 4080                                        }
 4081                                        cursor_is_before_end_tag
 4082                                    } else {
 4083                                        true
 4084                                    }
 4085                                };
 4086
 4087                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4088                                    && cursor_is_before_end_tag_if_exists
 4089                                {
 4090                                    if cursor_is_after_start_tag {
 4091                                        indent_on_newline.len = (*len).into();
 4092                                    }
 4093                                    Some(delimiter.clone())
 4094                                } else {
 4095                                    None
 4096                                }
 4097                            });
 4098
 4099                            (
 4100                                comment_delimiter,
 4101                                doc_delimiter,
 4102                                insert_extra_newline,
 4103                                indent_on_newline,
 4104                                indent_on_extra_newline,
 4105                            )
 4106                        } else {
 4107                            (
 4108                                None,
 4109                                None,
 4110                                false,
 4111                                IndentSize::default(),
 4112                                IndentSize::default(),
 4113                            )
 4114                        };
 4115
 4116                        let prevent_auto_indent = doc_delimiter.is_some();
 4117                        let delimiter = comment_delimiter.or(doc_delimiter);
 4118
 4119                        let capacity_for_delimiter =
 4120                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4121                        let mut new_text = String::with_capacity(
 4122                            1 + capacity_for_delimiter
 4123                                + existing_indent.len as usize
 4124                                + indent_on_newline.len as usize
 4125                                + indent_on_extra_newline.len as usize,
 4126                        );
 4127                        new_text.push('\n');
 4128                        new_text.extend(existing_indent.chars());
 4129                        new_text.extend(indent_on_newline.chars());
 4130
 4131                        if let Some(delimiter) = &delimiter {
 4132                            new_text.push_str(delimiter);
 4133                        }
 4134
 4135                        if insert_extra_newline {
 4136                            new_text.push('\n');
 4137                            new_text.extend(existing_indent.chars());
 4138                            new_text.extend(indent_on_extra_newline.chars());
 4139                        }
 4140
 4141                        let anchor = buffer.anchor_after(end);
 4142                        let new_selection = selection.map(|_| anchor);
 4143                        (
 4144                            ((start..end, new_text), prevent_auto_indent),
 4145                            (insert_extra_newline, new_selection),
 4146                        )
 4147                    })
 4148                    .unzip()
 4149            };
 4150
 4151            let mut auto_indent_edits = Vec::new();
 4152            let mut edits = Vec::new();
 4153            for (edit, prevent_auto_indent) in edits_with_flags {
 4154                if prevent_auto_indent {
 4155                    edits.push(edit);
 4156                } else {
 4157                    auto_indent_edits.push(edit);
 4158                }
 4159            }
 4160            if !edits.is_empty() {
 4161                this.edit(edits, cx);
 4162            }
 4163            if !auto_indent_edits.is_empty() {
 4164                this.edit_with_autoindent(auto_indent_edits, cx);
 4165            }
 4166
 4167            let buffer = this.buffer.read(cx).snapshot(cx);
 4168            let new_selections = selection_info
 4169                .into_iter()
 4170                .map(|(extra_newline_inserted, new_selection)| {
 4171                    let mut cursor = new_selection.end.to_point(&buffer);
 4172                    if extra_newline_inserted {
 4173                        cursor.row -= 1;
 4174                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4175                    }
 4176                    new_selection.map(|_| cursor)
 4177                })
 4178                .collect();
 4179
 4180            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4181                s.select(new_selections)
 4182            });
 4183            this.refresh_inline_completion(true, false, window, cx);
 4184        });
 4185    }
 4186
 4187    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4188        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4189
 4190        let buffer = self.buffer.read(cx);
 4191        let snapshot = buffer.snapshot(cx);
 4192
 4193        let mut edits = Vec::new();
 4194        let mut rows = Vec::new();
 4195
 4196        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4197            let cursor = selection.head();
 4198            let row = cursor.row;
 4199
 4200            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4201
 4202            let newline = "\n".to_string();
 4203            edits.push((start_of_line..start_of_line, newline));
 4204
 4205            rows.push(row + rows_inserted as u32);
 4206        }
 4207
 4208        self.transact(window, cx, |editor, window, cx| {
 4209            editor.edit(edits, cx);
 4210
 4211            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4212                let mut index = 0;
 4213                s.move_cursors_with(|map, _, _| {
 4214                    let row = rows[index];
 4215                    index += 1;
 4216
 4217                    let point = Point::new(row, 0);
 4218                    let boundary = map.next_line_boundary(point).1;
 4219                    let clipped = map.clip_point(boundary, Bias::Left);
 4220
 4221                    (clipped, SelectionGoal::None)
 4222                });
 4223            });
 4224
 4225            let mut indent_edits = Vec::new();
 4226            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4227            for row in rows {
 4228                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4229                for (row, indent) in indents {
 4230                    if indent.len == 0 {
 4231                        continue;
 4232                    }
 4233
 4234                    let text = match indent.kind {
 4235                        IndentKind::Space => " ".repeat(indent.len as usize),
 4236                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4237                    };
 4238                    let point = Point::new(row.0, 0);
 4239                    indent_edits.push((point..point, text));
 4240                }
 4241            }
 4242            editor.edit(indent_edits, cx);
 4243        });
 4244    }
 4245
 4246    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4247        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4248
 4249        let buffer = self.buffer.read(cx);
 4250        let snapshot = buffer.snapshot(cx);
 4251
 4252        let mut edits = Vec::new();
 4253        let mut rows = Vec::new();
 4254        let mut rows_inserted = 0;
 4255
 4256        for selection in self.selections.all_adjusted(cx) {
 4257            let cursor = selection.head();
 4258            let row = cursor.row;
 4259
 4260            let point = Point::new(row + 1, 0);
 4261            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4262
 4263            let newline = "\n".to_string();
 4264            edits.push((start_of_line..start_of_line, newline));
 4265
 4266            rows_inserted += 1;
 4267            rows.push(row + rows_inserted);
 4268        }
 4269
 4270        self.transact(window, cx, |editor, window, cx| {
 4271            editor.edit(edits, cx);
 4272
 4273            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4274                let mut index = 0;
 4275                s.move_cursors_with(|map, _, _| {
 4276                    let row = rows[index];
 4277                    index += 1;
 4278
 4279                    let point = Point::new(row, 0);
 4280                    let boundary = map.next_line_boundary(point).1;
 4281                    let clipped = map.clip_point(boundary, Bias::Left);
 4282
 4283                    (clipped, SelectionGoal::None)
 4284                });
 4285            });
 4286
 4287            let mut indent_edits = Vec::new();
 4288            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4289            for row in rows {
 4290                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4291                for (row, indent) in indents {
 4292                    if indent.len == 0 {
 4293                        continue;
 4294                    }
 4295
 4296                    let text = match indent.kind {
 4297                        IndentKind::Space => " ".repeat(indent.len as usize),
 4298                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4299                    };
 4300                    let point = Point::new(row.0, 0);
 4301                    indent_edits.push((point..point, text));
 4302                }
 4303            }
 4304            editor.edit(indent_edits, cx);
 4305        });
 4306    }
 4307
 4308    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4309        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4310            original_indent_columns: Vec::new(),
 4311        });
 4312        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4313    }
 4314
 4315    fn insert_with_autoindent_mode(
 4316        &mut self,
 4317        text: &str,
 4318        autoindent_mode: Option<AutoindentMode>,
 4319        window: &mut Window,
 4320        cx: &mut Context<Self>,
 4321    ) {
 4322        if self.read_only(cx) {
 4323            return;
 4324        }
 4325
 4326        let text: Arc<str> = text.into();
 4327        self.transact(window, cx, |this, window, cx| {
 4328            let old_selections = this.selections.all_adjusted(cx);
 4329            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4330                let anchors = {
 4331                    let snapshot = buffer.read(cx);
 4332                    old_selections
 4333                        .iter()
 4334                        .map(|s| {
 4335                            let anchor = snapshot.anchor_after(s.head());
 4336                            s.map(|_| anchor)
 4337                        })
 4338                        .collect::<Vec<_>>()
 4339                };
 4340                buffer.edit(
 4341                    old_selections
 4342                        .iter()
 4343                        .map(|s| (s.start..s.end, text.clone())),
 4344                    autoindent_mode,
 4345                    cx,
 4346                );
 4347                anchors
 4348            });
 4349
 4350            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4351                s.select_anchors(selection_anchors);
 4352            });
 4353
 4354            cx.notify();
 4355        });
 4356    }
 4357
 4358    fn trigger_completion_on_input(
 4359        &mut self,
 4360        text: &str,
 4361        trigger_in_words: bool,
 4362        window: &mut Window,
 4363        cx: &mut Context<Self>,
 4364    ) {
 4365        let ignore_completion_provider = self
 4366            .context_menu
 4367            .borrow()
 4368            .as_ref()
 4369            .map(|menu| match menu {
 4370                CodeContextMenu::Completions(completions_menu) => {
 4371                    completions_menu.ignore_completion_provider
 4372                }
 4373                CodeContextMenu::CodeActions(_) => false,
 4374            })
 4375            .unwrap_or(false);
 4376
 4377        if ignore_completion_provider {
 4378            self.show_word_completions(&ShowWordCompletions, window, cx);
 4379        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4380            self.show_completions(
 4381                &ShowCompletions {
 4382                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4383                },
 4384                window,
 4385                cx,
 4386            );
 4387        } else {
 4388            self.hide_context_menu(window, cx);
 4389        }
 4390    }
 4391
 4392    fn is_completion_trigger(
 4393        &self,
 4394        text: &str,
 4395        trigger_in_words: bool,
 4396        cx: &mut Context<Self>,
 4397    ) -> bool {
 4398        let position = self.selections.newest_anchor().head();
 4399        let multibuffer = self.buffer.read(cx);
 4400        let Some(buffer) = position
 4401            .buffer_id
 4402            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4403        else {
 4404            return false;
 4405        };
 4406
 4407        if let Some(completion_provider) = &self.completion_provider {
 4408            completion_provider.is_completion_trigger(
 4409                &buffer,
 4410                position.text_anchor,
 4411                text,
 4412                trigger_in_words,
 4413                cx,
 4414            )
 4415        } else {
 4416            false
 4417        }
 4418    }
 4419
 4420    /// If any empty selections is touching the start of its innermost containing autoclose
 4421    /// region, expand it to select the brackets.
 4422    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4423        let selections = self.selections.all::<usize>(cx);
 4424        let buffer = self.buffer.read(cx).read(cx);
 4425        let new_selections = self
 4426            .selections_with_autoclose_regions(selections, &buffer)
 4427            .map(|(mut selection, region)| {
 4428                if !selection.is_empty() {
 4429                    return selection;
 4430                }
 4431
 4432                if let Some(region) = region {
 4433                    let mut range = region.range.to_offset(&buffer);
 4434                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4435                        range.start -= region.pair.start.len();
 4436                        if buffer.contains_str_at(range.start, &region.pair.start)
 4437                            && buffer.contains_str_at(range.end, &region.pair.end)
 4438                        {
 4439                            range.end += region.pair.end.len();
 4440                            selection.start = range.start;
 4441                            selection.end = range.end;
 4442
 4443                            return selection;
 4444                        }
 4445                    }
 4446                }
 4447
 4448                let always_treat_brackets_as_autoclosed = buffer
 4449                    .language_settings_at(selection.start, cx)
 4450                    .always_treat_brackets_as_autoclosed;
 4451
 4452                if !always_treat_brackets_as_autoclosed {
 4453                    return selection;
 4454                }
 4455
 4456                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4457                    for (pair, enabled) in scope.brackets() {
 4458                        if !enabled || !pair.close {
 4459                            continue;
 4460                        }
 4461
 4462                        if buffer.contains_str_at(selection.start, &pair.end) {
 4463                            let pair_start_len = pair.start.len();
 4464                            if buffer.contains_str_at(
 4465                                selection.start.saturating_sub(pair_start_len),
 4466                                &pair.start,
 4467                            ) {
 4468                                selection.start -= pair_start_len;
 4469                                selection.end += pair.end.len();
 4470
 4471                                return selection;
 4472                            }
 4473                        }
 4474                    }
 4475                }
 4476
 4477                selection
 4478            })
 4479            .collect();
 4480
 4481        drop(buffer);
 4482        self.change_selections(None, window, cx, |selections| {
 4483            selections.select(new_selections)
 4484        });
 4485    }
 4486
 4487    /// Iterate the given selections, and for each one, find the smallest surrounding
 4488    /// autoclose region. This uses the ordering of the selections and the autoclose
 4489    /// regions to avoid repeated comparisons.
 4490    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4491        &'a self,
 4492        selections: impl IntoIterator<Item = Selection<D>>,
 4493        buffer: &'a MultiBufferSnapshot,
 4494    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4495        let mut i = 0;
 4496        let mut regions = self.autoclose_regions.as_slice();
 4497        selections.into_iter().map(move |selection| {
 4498            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4499
 4500            let mut enclosing = None;
 4501            while let Some(pair_state) = regions.get(i) {
 4502                if pair_state.range.end.to_offset(buffer) < range.start {
 4503                    regions = &regions[i + 1..];
 4504                    i = 0;
 4505                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4506                    break;
 4507                } else {
 4508                    if pair_state.selection_id == selection.id {
 4509                        enclosing = Some(pair_state);
 4510                    }
 4511                    i += 1;
 4512                }
 4513            }
 4514
 4515            (selection, enclosing)
 4516        })
 4517    }
 4518
 4519    /// Remove any autoclose regions that no longer contain their selection.
 4520    fn invalidate_autoclose_regions(
 4521        &mut self,
 4522        mut selections: &[Selection<Anchor>],
 4523        buffer: &MultiBufferSnapshot,
 4524    ) {
 4525        self.autoclose_regions.retain(|state| {
 4526            let mut i = 0;
 4527            while let Some(selection) = selections.get(i) {
 4528                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4529                    selections = &selections[1..];
 4530                    continue;
 4531                }
 4532                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4533                    break;
 4534                }
 4535                if selection.id == state.selection_id {
 4536                    return true;
 4537                } else {
 4538                    i += 1;
 4539                }
 4540            }
 4541            false
 4542        });
 4543    }
 4544
 4545    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4546        let offset = position.to_offset(buffer);
 4547        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4548        if offset > word_range.start && kind == Some(CharKind::Word) {
 4549            Some(
 4550                buffer
 4551                    .text_for_range(word_range.start..offset)
 4552                    .collect::<String>(),
 4553            )
 4554        } else {
 4555            None
 4556        }
 4557    }
 4558
 4559    pub fn toggle_inline_values(
 4560        &mut self,
 4561        _: &ToggleInlineValues,
 4562        _: &mut Window,
 4563        cx: &mut Context<Self>,
 4564    ) {
 4565        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4566
 4567        self.refresh_inline_values(cx);
 4568    }
 4569
 4570    pub fn toggle_inlay_hints(
 4571        &mut self,
 4572        _: &ToggleInlayHints,
 4573        _: &mut Window,
 4574        cx: &mut Context<Self>,
 4575    ) {
 4576        self.refresh_inlay_hints(
 4577            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4578            cx,
 4579        );
 4580    }
 4581
 4582    pub fn inlay_hints_enabled(&self) -> bool {
 4583        self.inlay_hint_cache.enabled
 4584    }
 4585
 4586    pub fn inline_values_enabled(&self) -> bool {
 4587        self.inline_value_cache.enabled
 4588    }
 4589
 4590    #[cfg(any(test, feature = "test-support"))]
 4591    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4592        self.display_map
 4593            .read(cx)
 4594            .current_inlays()
 4595            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4596            .cloned()
 4597            .collect()
 4598    }
 4599
 4600    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4601        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4602            return;
 4603        }
 4604
 4605        let reason_description = reason.description();
 4606        let ignore_debounce = matches!(
 4607            reason,
 4608            InlayHintRefreshReason::SettingsChange(_)
 4609                | InlayHintRefreshReason::Toggle(_)
 4610                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4611                | InlayHintRefreshReason::ModifiersChanged(_)
 4612        );
 4613        let (invalidate_cache, required_languages) = match reason {
 4614            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4615                match self.inlay_hint_cache.modifiers_override(enabled) {
 4616                    Some(enabled) => {
 4617                        if enabled {
 4618                            (InvalidationStrategy::RefreshRequested, None)
 4619                        } else {
 4620                            self.splice_inlays(
 4621                                &self
 4622                                    .visible_inlay_hints(cx)
 4623                                    .iter()
 4624                                    .map(|inlay| inlay.id)
 4625                                    .collect::<Vec<InlayId>>(),
 4626                                Vec::new(),
 4627                                cx,
 4628                            );
 4629                            return;
 4630                        }
 4631                    }
 4632                    None => return,
 4633                }
 4634            }
 4635            InlayHintRefreshReason::Toggle(enabled) => {
 4636                if self.inlay_hint_cache.toggle(enabled) {
 4637                    if enabled {
 4638                        (InvalidationStrategy::RefreshRequested, None)
 4639                    } else {
 4640                        self.splice_inlays(
 4641                            &self
 4642                                .visible_inlay_hints(cx)
 4643                                .iter()
 4644                                .map(|inlay| inlay.id)
 4645                                .collect::<Vec<InlayId>>(),
 4646                            Vec::new(),
 4647                            cx,
 4648                        );
 4649                        return;
 4650                    }
 4651                } else {
 4652                    return;
 4653                }
 4654            }
 4655            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4656                match self.inlay_hint_cache.update_settings(
 4657                    &self.buffer,
 4658                    new_settings,
 4659                    self.visible_inlay_hints(cx),
 4660                    cx,
 4661                ) {
 4662                    ControlFlow::Break(Some(InlaySplice {
 4663                        to_remove,
 4664                        to_insert,
 4665                    })) => {
 4666                        self.splice_inlays(&to_remove, to_insert, cx);
 4667                        return;
 4668                    }
 4669                    ControlFlow::Break(None) => return,
 4670                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4671                }
 4672            }
 4673            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4674                if let Some(InlaySplice {
 4675                    to_remove,
 4676                    to_insert,
 4677                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4678                {
 4679                    self.splice_inlays(&to_remove, to_insert, cx);
 4680                }
 4681                self.display_map.update(cx, |display_map, _| {
 4682                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4683                });
 4684                return;
 4685            }
 4686            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4687            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4688                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4689            }
 4690            InlayHintRefreshReason::RefreshRequested => {
 4691                (InvalidationStrategy::RefreshRequested, None)
 4692            }
 4693        };
 4694
 4695        if let Some(InlaySplice {
 4696            to_remove,
 4697            to_insert,
 4698        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4699            reason_description,
 4700            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4701            invalidate_cache,
 4702            ignore_debounce,
 4703            cx,
 4704        ) {
 4705            self.splice_inlays(&to_remove, to_insert, cx);
 4706        }
 4707    }
 4708
 4709    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4710        self.display_map
 4711            .read(cx)
 4712            .current_inlays()
 4713            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4714            .cloned()
 4715            .collect()
 4716    }
 4717
 4718    pub fn excerpts_for_inlay_hints_query(
 4719        &self,
 4720        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4721        cx: &mut Context<Editor>,
 4722    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4723        let Some(project) = self.project.as_ref() else {
 4724            return HashMap::default();
 4725        };
 4726        let project = project.read(cx);
 4727        let multi_buffer = self.buffer().read(cx);
 4728        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4729        let multi_buffer_visible_start = self
 4730            .scroll_manager
 4731            .anchor()
 4732            .anchor
 4733            .to_point(&multi_buffer_snapshot);
 4734        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4735            multi_buffer_visible_start
 4736                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4737            Bias::Left,
 4738        );
 4739        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4740        multi_buffer_snapshot
 4741            .range_to_buffer_ranges(multi_buffer_visible_range)
 4742            .into_iter()
 4743            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4744            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4745                let buffer_file = project::File::from_dyn(buffer.file())?;
 4746                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4747                let worktree_entry = buffer_worktree
 4748                    .read(cx)
 4749                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4750                if worktree_entry.is_ignored {
 4751                    return None;
 4752                }
 4753
 4754                let language = buffer.language()?;
 4755                if let Some(restrict_to_languages) = restrict_to_languages {
 4756                    if !restrict_to_languages.contains(language) {
 4757                        return None;
 4758                    }
 4759                }
 4760                Some((
 4761                    excerpt_id,
 4762                    (
 4763                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4764                        buffer.version().clone(),
 4765                        excerpt_visible_range,
 4766                    ),
 4767                ))
 4768            })
 4769            .collect()
 4770    }
 4771
 4772    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4773        TextLayoutDetails {
 4774            text_system: window.text_system().clone(),
 4775            editor_style: self.style.clone().unwrap(),
 4776            rem_size: window.rem_size(),
 4777            scroll_anchor: self.scroll_manager.anchor(),
 4778            visible_rows: self.visible_line_count(),
 4779            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4780        }
 4781    }
 4782
 4783    pub fn splice_inlays(
 4784        &self,
 4785        to_remove: &[InlayId],
 4786        to_insert: Vec<Inlay>,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        self.display_map.update(cx, |display_map, cx| {
 4790            display_map.splice_inlays(to_remove, to_insert, cx)
 4791        });
 4792        cx.notify();
 4793    }
 4794
 4795    fn trigger_on_type_formatting(
 4796        &self,
 4797        input: String,
 4798        window: &mut Window,
 4799        cx: &mut Context<Self>,
 4800    ) -> Option<Task<Result<()>>> {
 4801        if input.len() != 1 {
 4802            return None;
 4803        }
 4804
 4805        let project = self.project.as_ref()?;
 4806        let position = self.selections.newest_anchor().head();
 4807        let (buffer, buffer_position) = self
 4808            .buffer
 4809            .read(cx)
 4810            .text_anchor_for_position(position, cx)?;
 4811
 4812        let settings = language_settings::language_settings(
 4813            buffer
 4814                .read(cx)
 4815                .language_at(buffer_position)
 4816                .map(|l| l.name()),
 4817            buffer.read(cx).file(),
 4818            cx,
 4819        );
 4820        if !settings.use_on_type_format {
 4821            return None;
 4822        }
 4823
 4824        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4825        // hence we do LSP request & edit on host side only — add formats to host's history.
 4826        let push_to_lsp_host_history = true;
 4827        // If this is not the host, append its history with new edits.
 4828        let push_to_client_history = project.read(cx).is_via_collab();
 4829
 4830        let on_type_formatting = project.update(cx, |project, cx| {
 4831            project.on_type_format(
 4832                buffer.clone(),
 4833                buffer_position,
 4834                input,
 4835                push_to_lsp_host_history,
 4836                cx,
 4837            )
 4838        });
 4839        Some(cx.spawn_in(window, async move |editor, cx| {
 4840            if let Some(transaction) = on_type_formatting.await? {
 4841                if push_to_client_history {
 4842                    buffer
 4843                        .update(cx, |buffer, _| {
 4844                            buffer.push_transaction(transaction, Instant::now());
 4845                            buffer.finalize_last_transaction();
 4846                        })
 4847                        .ok();
 4848                }
 4849                editor.update(cx, |editor, cx| {
 4850                    editor.refresh_document_highlights(cx);
 4851                })?;
 4852            }
 4853            Ok(())
 4854        }))
 4855    }
 4856
 4857    pub fn show_word_completions(
 4858        &mut self,
 4859        _: &ShowWordCompletions,
 4860        window: &mut Window,
 4861        cx: &mut Context<Self>,
 4862    ) {
 4863        self.open_completions_menu(true, None, window, cx);
 4864    }
 4865
 4866    pub fn show_completions(
 4867        &mut self,
 4868        options: &ShowCompletions,
 4869        window: &mut Window,
 4870        cx: &mut Context<Self>,
 4871    ) {
 4872        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4873    }
 4874
 4875    fn open_completions_menu(
 4876        &mut self,
 4877        ignore_completion_provider: bool,
 4878        trigger: Option<&str>,
 4879        window: &mut Window,
 4880        cx: &mut Context<Self>,
 4881    ) {
 4882        if self.pending_rename.is_some() {
 4883            return;
 4884        }
 4885        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4886            return;
 4887        }
 4888
 4889        let position = self.selections.newest_anchor().head();
 4890        if position.diff_base_anchor.is_some() {
 4891            return;
 4892        }
 4893        let (buffer, buffer_position) =
 4894            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4895                output
 4896            } else {
 4897                return;
 4898            };
 4899        let buffer_snapshot = buffer.read(cx).snapshot();
 4900        let show_completion_documentation = buffer_snapshot
 4901            .settings_at(buffer_position, cx)
 4902            .show_completion_documentation;
 4903
 4904        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4905
 4906        let trigger_kind = match trigger {
 4907            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4908                CompletionTriggerKind::TRIGGER_CHARACTER
 4909            }
 4910            _ => CompletionTriggerKind::INVOKED,
 4911        };
 4912        let completion_context = CompletionContext {
 4913            trigger_character: trigger.and_then(|trigger| {
 4914                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4915                    Some(String::from(trigger))
 4916                } else {
 4917                    None
 4918                }
 4919            }),
 4920            trigger_kind,
 4921        };
 4922
 4923        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4924        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4925            let word_to_exclude = buffer_snapshot
 4926                .text_for_range(old_range.clone())
 4927                .collect::<String>();
 4928            (
 4929                buffer_snapshot.anchor_before(old_range.start)
 4930                    ..buffer_snapshot.anchor_after(old_range.end),
 4931                Some(word_to_exclude),
 4932            )
 4933        } else {
 4934            (buffer_position..buffer_position, None)
 4935        };
 4936
 4937        let completion_settings = language_settings(
 4938            buffer_snapshot
 4939                .language_at(buffer_position)
 4940                .map(|language| language.name()),
 4941            buffer_snapshot.file(),
 4942            cx,
 4943        )
 4944        .completions;
 4945
 4946        // The document can be large, so stay in reasonable bounds when searching for words,
 4947        // otherwise completion pop-up might be slow to appear.
 4948        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4949        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4950        let min_word_search = buffer_snapshot.clip_point(
 4951            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4952            Bias::Left,
 4953        );
 4954        let max_word_search = buffer_snapshot.clip_point(
 4955            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4956            Bias::Right,
 4957        );
 4958        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4959            ..buffer_snapshot.point_to_offset(max_word_search);
 4960
 4961        let provider = self
 4962            .completion_provider
 4963            .as_ref()
 4964            .filter(|_| !ignore_completion_provider);
 4965        let skip_digits = query
 4966            .as_ref()
 4967            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4968
 4969        let (mut words, provided_completions) = match provider {
 4970            Some(provider) => {
 4971                let completions = provider.completions(
 4972                    position.excerpt_id,
 4973                    &buffer,
 4974                    buffer_position,
 4975                    completion_context,
 4976                    window,
 4977                    cx,
 4978                );
 4979
 4980                let words = match completion_settings.words {
 4981                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4982                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4983                        .background_spawn(async move {
 4984                            buffer_snapshot.words_in_range(WordsQuery {
 4985                                fuzzy_contents: None,
 4986                                range: word_search_range,
 4987                                skip_digits,
 4988                            })
 4989                        }),
 4990                };
 4991
 4992                (words, completions)
 4993            }
 4994            None => (
 4995                cx.background_spawn(async move {
 4996                    buffer_snapshot.words_in_range(WordsQuery {
 4997                        fuzzy_contents: None,
 4998                        range: word_search_range,
 4999                        skip_digits,
 5000                    })
 5001                }),
 5002                Task::ready(Ok(None)),
 5003            ),
 5004        };
 5005
 5006        let sort_completions = provider
 5007            .as_ref()
 5008            .map_or(false, |provider| provider.sort_completions());
 5009
 5010        let filter_completions = provider
 5011            .as_ref()
 5012            .map_or(true, |provider| provider.filter_completions());
 5013
 5014        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5015
 5016        let id = post_inc(&mut self.next_completion_id);
 5017        let task = cx.spawn_in(window, async move |editor, cx| {
 5018            async move {
 5019                editor.update(cx, |this, _| {
 5020                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5021                })?;
 5022
 5023                let mut completions = Vec::new();
 5024                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5025                    completions.extend(provided_completions);
 5026                    if completion_settings.words == WordsCompletionMode::Fallback {
 5027                        words = Task::ready(BTreeMap::default());
 5028                    }
 5029                }
 5030
 5031                let mut words = words.await;
 5032                if let Some(word_to_exclude) = &word_to_exclude {
 5033                    words.remove(word_to_exclude);
 5034                }
 5035                for lsp_completion in &completions {
 5036                    words.remove(&lsp_completion.new_text);
 5037                }
 5038                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5039                    replace_range: old_range.clone(),
 5040                    new_text: word.clone(),
 5041                    label: CodeLabel::plain(word, None),
 5042                    icon_path: None,
 5043                    documentation: None,
 5044                    source: CompletionSource::BufferWord {
 5045                        word_range,
 5046                        resolved: false,
 5047                    },
 5048                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5049                    confirm: None,
 5050                }));
 5051
 5052                let menu = if completions.is_empty() {
 5053                    None
 5054                } else {
 5055                    let mut menu = CompletionsMenu::new(
 5056                        id,
 5057                        sort_completions,
 5058                        show_completion_documentation,
 5059                        ignore_completion_provider,
 5060                        position,
 5061                        buffer.clone(),
 5062                        completions.into(),
 5063                        snippet_sort_order,
 5064                    );
 5065
 5066                    menu.filter(
 5067                        if filter_completions {
 5068                            query.as_deref()
 5069                        } else {
 5070                            None
 5071                        },
 5072                        cx.background_executor().clone(),
 5073                    )
 5074                    .await;
 5075
 5076                    menu.visible().then_some(menu)
 5077                };
 5078
 5079                editor.update_in(cx, |editor, window, cx| {
 5080                    match editor.context_menu.borrow().as_ref() {
 5081                        None => {}
 5082                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5083                            if prev_menu.id > id {
 5084                                return;
 5085                            }
 5086                        }
 5087                        _ => return,
 5088                    }
 5089
 5090                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5091                        let mut menu = menu.unwrap();
 5092                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5093                        crate::hover_popover::hide_hover(editor, cx);
 5094                        *editor.context_menu.borrow_mut() =
 5095                            Some(CodeContextMenu::Completions(menu));
 5096
 5097                        if editor.show_edit_predictions_in_menu() {
 5098                            editor.update_visible_inline_completion(window, cx);
 5099                        } else {
 5100                            editor.discard_inline_completion(false, cx);
 5101                        }
 5102
 5103                        cx.notify();
 5104                    } else if editor.completion_tasks.len() <= 1 {
 5105                        // If there are no more completion tasks and the last menu was
 5106                        // empty, we should hide it.
 5107                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5108                        // If it was already hidden and we don't show inline
 5109                        // completions in the menu, we should also show the
 5110                        // inline-completion when available.
 5111                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5112                            editor.update_visible_inline_completion(window, cx);
 5113                        }
 5114                    }
 5115                })?;
 5116
 5117                anyhow::Ok(())
 5118            }
 5119            .log_err()
 5120            .await
 5121        });
 5122
 5123        self.completion_tasks.push((id, task));
 5124    }
 5125
 5126    #[cfg(feature = "test-support")]
 5127    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5128        let menu = self.context_menu.borrow();
 5129        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5130            let completions = menu.completions.borrow();
 5131            Some(completions.to_vec())
 5132        } else {
 5133            None
 5134        }
 5135    }
 5136
 5137    pub fn confirm_completion(
 5138        &mut self,
 5139        action: &ConfirmCompletion,
 5140        window: &mut Window,
 5141        cx: &mut Context<Self>,
 5142    ) -> Option<Task<Result<()>>> {
 5143        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5144        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5145    }
 5146
 5147    pub fn confirm_completion_insert(
 5148        &mut self,
 5149        _: &ConfirmCompletionInsert,
 5150        window: &mut Window,
 5151        cx: &mut Context<Self>,
 5152    ) -> Option<Task<Result<()>>> {
 5153        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5154        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5155    }
 5156
 5157    pub fn confirm_completion_replace(
 5158        &mut self,
 5159        _: &ConfirmCompletionReplace,
 5160        window: &mut Window,
 5161        cx: &mut Context<Self>,
 5162    ) -> Option<Task<Result<()>>> {
 5163        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5164        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5165    }
 5166
 5167    pub fn compose_completion(
 5168        &mut self,
 5169        action: &ComposeCompletion,
 5170        window: &mut Window,
 5171        cx: &mut Context<Self>,
 5172    ) -> Option<Task<Result<()>>> {
 5173        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5174        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5175    }
 5176
 5177    fn do_completion(
 5178        &mut self,
 5179        item_ix: Option<usize>,
 5180        intent: CompletionIntent,
 5181        window: &mut Window,
 5182        cx: &mut Context<Editor>,
 5183    ) -> Option<Task<Result<()>>> {
 5184        use language::ToOffset as _;
 5185
 5186        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5187        else {
 5188            return None;
 5189        };
 5190
 5191        let candidate_id = {
 5192            let entries = completions_menu.entries.borrow();
 5193            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5194            if self.show_edit_predictions_in_menu() {
 5195                self.discard_inline_completion(true, cx);
 5196            }
 5197            mat.candidate_id
 5198        };
 5199
 5200        let buffer_handle = completions_menu.buffer;
 5201        let completion = completions_menu
 5202            .completions
 5203            .borrow()
 5204            .get(candidate_id)?
 5205            .clone();
 5206        cx.stop_propagation();
 5207
 5208        let snapshot = self.buffer.read(cx).snapshot(cx);
 5209        let newest_anchor = self.selections.newest_anchor();
 5210
 5211        let snippet;
 5212        let new_text;
 5213        if completion.is_snippet() {
 5214            let mut snippet_source = completion.new_text.clone();
 5215            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5216                if scope.prefers_label_for_snippet_in_completion() {
 5217                    if let Some(label) = completion.label() {
 5218                        if matches!(
 5219                            completion.kind(),
 5220                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5221                        ) {
 5222                            snippet_source = label;
 5223                        }
 5224                    }
 5225                }
 5226            }
 5227            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5228            new_text = snippet.as_ref().unwrap().text.clone();
 5229        } else {
 5230            snippet = None;
 5231            new_text = completion.new_text.clone();
 5232        };
 5233
 5234        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5235        let buffer = buffer_handle.read(cx);
 5236        let replace_range_multibuffer = {
 5237            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5238            let multibuffer_anchor = snapshot
 5239                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5240                .unwrap()
 5241                ..snapshot
 5242                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5243                    .unwrap();
 5244            multibuffer_anchor.start.to_offset(&snapshot)
 5245                ..multibuffer_anchor.end.to_offset(&snapshot)
 5246        };
 5247        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5248            return None;
 5249        }
 5250
 5251        let old_text = buffer
 5252            .text_for_range(replace_range.clone())
 5253            .collect::<String>();
 5254        let lookbehind = newest_anchor
 5255            .start
 5256            .text_anchor
 5257            .to_offset(buffer)
 5258            .saturating_sub(replace_range.start);
 5259        let lookahead = replace_range
 5260            .end
 5261            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5262        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5263        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5264
 5265        let selections = self.selections.all::<usize>(cx);
 5266        let mut ranges = Vec::new();
 5267        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5268
 5269        for selection in &selections {
 5270            let range = if selection.id == newest_anchor.id {
 5271                replace_range_multibuffer.clone()
 5272            } else {
 5273                let mut range = selection.range();
 5274
 5275                // if prefix is present, don't duplicate it
 5276                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5277                    range.start = range.start.saturating_sub(lookbehind);
 5278
 5279                    // if suffix is also present, mimic the newest cursor and replace it
 5280                    if selection.id != newest_anchor.id
 5281                        && snapshot.contains_str_at(range.end, suffix)
 5282                    {
 5283                        range.end += lookahead;
 5284                    }
 5285                }
 5286                range
 5287            };
 5288
 5289            ranges.push(range.clone());
 5290
 5291            if !self.linked_edit_ranges.is_empty() {
 5292                let start_anchor = snapshot.anchor_before(range.start);
 5293                let end_anchor = snapshot.anchor_after(range.end);
 5294                if let Some(ranges) = self
 5295                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5296                {
 5297                    for (buffer, edits) in ranges {
 5298                        linked_edits
 5299                            .entry(buffer.clone())
 5300                            .or_default()
 5301                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5302                    }
 5303                }
 5304            }
 5305        }
 5306
 5307        cx.emit(EditorEvent::InputHandled {
 5308            utf16_range_to_replace: None,
 5309            text: new_text.clone().into(),
 5310        });
 5311
 5312        self.transact(window, cx, |this, window, cx| {
 5313            if let Some(mut snippet) = snippet {
 5314                snippet.text = new_text.to_string();
 5315                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5316            } else {
 5317                this.buffer.update(cx, |buffer, cx| {
 5318                    let auto_indent = match completion.insert_text_mode {
 5319                        Some(InsertTextMode::AS_IS) => None,
 5320                        _ => this.autoindent_mode.clone(),
 5321                    };
 5322                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5323                    buffer.edit(edits, auto_indent, cx);
 5324                });
 5325            }
 5326            for (buffer, edits) in linked_edits {
 5327                buffer.update(cx, |buffer, cx| {
 5328                    let snapshot = buffer.snapshot();
 5329                    let edits = edits
 5330                        .into_iter()
 5331                        .map(|(range, text)| {
 5332                            use text::ToPoint as TP;
 5333                            let end_point = TP::to_point(&range.end, &snapshot);
 5334                            let start_point = TP::to_point(&range.start, &snapshot);
 5335                            (start_point..end_point, text)
 5336                        })
 5337                        .sorted_by_key(|(range, _)| range.start);
 5338                    buffer.edit(edits, None, cx);
 5339                })
 5340            }
 5341
 5342            this.refresh_inline_completion(true, false, window, cx);
 5343        });
 5344
 5345        let show_new_completions_on_confirm = completion
 5346            .confirm
 5347            .as_ref()
 5348            .map_or(false, |confirm| confirm(intent, window, cx));
 5349        if show_new_completions_on_confirm {
 5350            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5351        }
 5352
 5353        let provider = self.completion_provider.as_ref()?;
 5354        drop(completion);
 5355        let apply_edits = provider.apply_additional_edits_for_completion(
 5356            buffer_handle,
 5357            completions_menu.completions.clone(),
 5358            candidate_id,
 5359            true,
 5360            cx,
 5361        );
 5362
 5363        let editor_settings = EditorSettings::get_global(cx);
 5364        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5365            // After the code completion is finished, users often want to know what signatures are needed.
 5366            // so we should automatically call signature_help
 5367            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5368        }
 5369
 5370        Some(cx.foreground_executor().spawn(async move {
 5371            apply_edits.await?;
 5372            Ok(())
 5373        }))
 5374    }
 5375
 5376    pub fn toggle_code_actions(
 5377        &mut self,
 5378        action: &ToggleCodeActions,
 5379        window: &mut Window,
 5380        cx: &mut Context<Self>,
 5381    ) {
 5382        let quick_launch = action.quick_launch;
 5383        let mut context_menu = self.context_menu.borrow_mut();
 5384        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5385            if code_actions.deployed_from == action.deployed_from {
 5386                // Toggle if we're selecting the same one
 5387                *context_menu = None;
 5388                cx.notify();
 5389                return;
 5390            } else {
 5391                // Otherwise, clear it and start a new one
 5392                *context_menu = None;
 5393                cx.notify();
 5394            }
 5395        }
 5396        drop(context_menu);
 5397        let snapshot = self.snapshot(window, cx);
 5398        let deployed_from = action.deployed_from.clone();
 5399        let mut task = self.code_actions_task.take();
 5400        let action = action.clone();
 5401        cx.spawn_in(window, async move |editor, cx| {
 5402            while let Some(prev_task) = task {
 5403                prev_task.await.log_err();
 5404                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5405            }
 5406
 5407            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5408                if editor.focus_handle.is_focused(window) {
 5409                    let multibuffer_point = match &action.deployed_from {
 5410                        Some(CodeActionSource::Indicator(row)) => {
 5411                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5412                        }
 5413                        _ => editor.selections.newest::<Point>(cx).head(),
 5414                    };
 5415                    let (buffer, buffer_row) = snapshot
 5416                        .buffer_snapshot
 5417                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5418                        .and_then(|(buffer_snapshot, range)| {
 5419                            editor
 5420                                .buffer
 5421                                .read(cx)
 5422                                .buffer(buffer_snapshot.remote_id())
 5423                                .map(|buffer| (buffer, range.start.row))
 5424                        })?;
 5425                    let (_, code_actions) = editor
 5426                        .available_code_actions
 5427                        .clone()
 5428                        .and_then(|(location, code_actions)| {
 5429                            let snapshot = location.buffer.read(cx).snapshot();
 5430                            let point_range = location.range.to_point(&snapshot);
 5431                            let point_range = point_range.start.row..=point_range.end.row;
 5432                            if point_range.contains(&buffer_row) {
 5433                                Some((location, code_actions))
 5434                            } else {
 5435                                None
 5436                            }
 5437                        })
 5438                        .unzip();
 5439                    let buffer_id = buffer.read(cx).remote_id();
 5440                    let tasks = editor
 5441                        .tasks
 5442                        .get(&(buffer_id, buffer_row))
 5443                        .map(|t| Arc::new(t.to_owned()));
 5444                    if tasks.is_none() && code_actions.is_none() {
 5445                        return None;
 5446                    }
 5447
 5448                    editor.completion_tasks.clear();
 5449                    editor.discard_inline_completion(false, cx);
 5450                    let task_context =
 5451                        tasks
 5452                            .as_ref()
 5453                            .zip(editor.project.clone())
 5454                            .map(|(tasks, project)| {
 5455                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5456                            });
 5457
 5458                    Some(cx.spawn_in(window, async move |editor, cx| {
 5459                        let task_context = match task_context {
 5460                            Some(task_context) => task_context.await,
 5461                            None => None,
 5462                        };
 5463                        let resolved_tasks =
 5464                            tasks
 5465                                .zip(task_context.clone())
 5466                                .map(|(tasks, task_context)| ResolvedTasks {
 5467                                    templates: tasks.resolve(&task_context).collect(),
 5468                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5469                                        multibuffer_point.row,
 5470                                        tasks.column,
 5471                                    )),
 5472                                });
 5473                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5474                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5475                                maybe!({
 5476                                    let project = editor.project.as_ref()?;
 5477                                    let dap_store = project.read(cx).dap_store();
 5478                                    let mut scenarios = vec![];
 5479                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5480                                    let buffer = buffer.read(cx);
 5481                                    let language = buffer.language()?;
 5482                                    let file = buffer.file();
 5483                                    let debug_adapter =
 5484                                        language_settings(language.name().into(), file, cx)
 5485                                            .debuggers
 5486                                            .first()
 5487                                            .map(SharedString::from)
 5488                                            .or_else(|| {
 5489                                                language
 5490                                                    .config()
 5491                                                    .debuggers
 5492                                                    .first()
 5493                                                    .map(SharedString::from)
 5494                                            })?;
 5495
 5496                                    dap_store.update(cx, |dap_store, cx| {
 5497                                        for (_, task) in &resolved_tasks.templates {
 5498                                            if let Some(scenario) = dap_store
 5499                                                .debug_scenario_for_build_task(
 5500                                                    task.original_task().clone(),
 5501                                                    debug_adapter.clone().into(),
 5502                                                    task.display_label().to_owned().into(),
 5503                                                    cx,
 5504                                                )
 5505                                            {
 5506                                                scenarios.push(scenario);
 5507                                            }
 5508                                        }
 5509                                    });
 5510                                    Some(scenarios)
 5511                                })
 5512                                .unwrap_or_default()
 5513                            } else {
 5514                                vec![]
 5515                            }
 5516                        })?;
 5517                        let spawn_straight_away = quick_launch
 5518                            && resolved_tasks
 5519                                .as_ref()
 5520                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5521                            && code_actions
 5522                                .as_ref()
 5523                                .map_or(true, |actions| actions.is_empty())
 5524                            && debug_scenarios.is_empty();
 5525                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5526                            crate::hover_popover::hide_hover(editor, cx);
 5527                            *editor.context_menu.borrow_mut() =
 5528                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5529                                    buffer,
 5530                                    actions: CodeActionContents::new(
 5531                                        resolved_tasks,
 5532                                        code_actions,
 5533                                        debug_scenarios,
 5534                                        task_context.unwrap_or_default(),
 5535                                    ),
 5536                                    selected_item: Default::default(),
 5537                                    scroll_handle: UniformListScrollHandle::default(),
 5538                                    deployed_from,
 5539                                }));
 5540                            if spawn_straight_away {
 5541                                if let Some(task) = editor.confirm_code_action(
 5542                                    &ConfirmCodeAction { item_ix: Some(0) },
 5543                                    window,
 5544                                    cx,
 5545                                ) {
 5546                                    cx.notify();
 5547                                    return task;
 5548                                }
 5549                            }
 5550                            cx.notify();
 5551                            Task::ready(Ok(()))
 5552                        }) {
 5553                            task.await
 5554                        } else {
 5555                            Ok(())
 5556                        }
 5557                    }))
 5558                } else {
 5559                    Some(Task::ready(Ok(())))
 5560                }
 5561            })?;
 5562            if let Some(task) = spawned_test_task {
 5563                task.await?;
 5564            }
 5565
 5566            anyhow::Ok(())
 5567        })
 5568        .detach_and_log_err(cx);
 5569    }
 5570
 5571    pub fn confirm_code_action(
 5572        &mut self,
 5573        action: &ConfirmCodeAction,
 5574        window: &mut Window,
 5575        cx: &mut Context<Self>,
 5576    ) -> Option<Task<Result<()>>> {
 5577        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5578
 5579        let actions_menu =
 5580            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5581                menu
 5582            } else {
 5583                return None;
 5584            };
 5585
 5586        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5587        let action = actions_menu.actions.get(action_ix)?;
 5588        let title = action.label();
 5589        let buffer = actions_menu.buffer;
 5590        let workspace = self.workspace()?;
 5591
 5592        match action {
 5593            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5594                workspace.update(cx, |workspace, cx| {
 5595                    workspace.schedule_resolved_task(
 5596                        task_source_kind,
 5597                        resolved_task,
 5598                        false,
 5599                        window,
 5600                        cx,
 5601                    );
 5602
 5603                    Some(Task::ready(Ok(())))
 5604                })
 5605            }
 5606            CodeActionsItem::CodeAction {
 5607                excerpt_id,
 5608                action,
 5609                provider,
 5610            } => {
 5611                let apply_code_action =
 5612                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5613                let workspace = workspace.downgrade();
 5614                Some(cx.spawn_in(window, async move |editor, cx| {
 5615                    let project_transaction = apply_code_action.await?;
 5616                    Self::open_project_transaction(
 5617                        &editor,
 5618                        workspace,
 5619                        project_transaction,
 5620                        title,
 5621                        cx,
 5622                    )
 5623                    .await
 5624                }))
 5625            }
 5626            CodeActionsItem::DebugScenario(scenario) => {
 5627                let context = actions_menu.actions.context.clone();
 5628
 5629                workspace.update(cx, |workspace, cx| {
 5630                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5631                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5632                });
 5633                Some(Task::ready(Ok(())))
 5634            }
 5635        }
 5636    }
 5637
 5638    pub async fn open_project_transaction(
 5639        this: &WeakEntity<Editor>,
 5640        workspace: WeakEntity<Workspace>,
 5641        transaction: ProjectTransaction,
 5642        title: String,
 5643        cx: &mut AsyncWindowContext,
 5644    ) -> Result<()> {
 5645        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5646        cx.update(|_, cx| {
 5647            entries.sort_unstable_by_key(|(buffer, _)| {
 5648                buffer.read(cx).file().map(|f| f.path().clone())
 5649            });
 5650        })?;
 5651
 5652        // If the project transaction's edits are all contained within this editor, then
 5653        // avoid opening a new editor to display them.
 5654
 5655        if let Some((buffer, transaction)) = entries.first() {
 5656            if entries.len() == 1 {
 5657                let excerpt = this.update(cx, |editor, cx| {
 5658                    editor
 5659                        .buffer()
 5660                        .read(cx)
 5661                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5662                })?;
 5663                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5664                    if excerpted_buffer == *buffer {
 5665                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5666                            let excerpt_range = excerpt_range.to_offset(buffer);
 5667                            buffer
 5668                                .edited_ranges_for_transaction::<usize>(transaction)
 5669                                .all(|range| {
 5670                                    excerpt_range.start <= range.start
 5671                                        && excerpt_range.end >= range.end
 5672                                })
 5673                        })?;
 5674
 5675                        if all_edits_within_excerpt {
 5676                            return Ok(());
 5677                        }
 5678                    }
 5679                }
 5680            }
 5681        } else {
 5682            return Ok(());
 5683        }
 5684
 5685        let mut ranges_to_highlight = Vec::new();
 5686        let excerpt_buffer = cx.new(|cx| {
 5687            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5688            for (buffer_handle, transaction) in &entries {
 5689                let edited_ranges = buffer_handle
 5690                    .read(cx)
 5691                    .edited_ranges_for_transaction::<Point>(transaction)
 5692                    .collect::<Vec<_>>();
 5693                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5694                    PathKey::for_buffer(buffer_handle, cx),
 5695                    buffer_handle.clone(),
 5696                    edited_ranges,
 5697                    DEFAULT_MULTIBUFFER_CONTEXT,
 5698                    cx,
 5699                );
 5700
 5701                ranges_to_highlight.extend(ranges);
 5702            }
 5703            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5704            multibuffer
 5705        })?;
 5706
 5707        workspace.update_in(cx, |workspace, window, cx| {
 5708            let project = workspace.project().clone();
 5709            let editor =
 5710                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5711            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5712            editor.update(cx, |editor, cx| {
 5713                editor.highlight_background::<Self>(
 5714                    &ranges_to_highlight,
 5715                    |theme| theme.editor_highlighted_line_background,
 5716                    cx,
 5717                );
 5718            });
 5719        })?;
 5720
 5721        Ok(())
 5722    }
 5723
 5724    pub fn clear_code_action_providers(&mut self) {
 5725        self.code_action_providers.clear();
 5726        self.available_code_actions.take();
 5727    }
 5728
 5729    pub fn add_code_action_provider(
 5730        &mut self,
 5731        provider: Rc<dyn CodeActionProvider>,
 5732        window: &mut Window,
 5733        cx: &mut Context<Self>,
 5734    ) {
 5735        if self
 5736            .code_action_providers
 5737            .iter()
 5738            .any(|existing_provider| existing_provider.id() == provider.id())
 5739        {
 5740            return;
 5741        }
 5742
 5743        self.code_action_providers.push(provider);
 5744        self.refresh_code_actions(window, cx);
 5745    }
 5746
 5747    pub fn remove_code_action_provider(
 5748        &mut self,
 5749        id: Arc<str>,
 5750        window: &mut Window,
 5751        cx: &mut Context<Self>,
 5752    ) {
 5753        self.code_action_providers
 5754            .retain(|provider| provider.id() != id);
 5755        self.refresh_code_actions(window, cx);
 5756    }
 5757
 5758    pub fn code_actions_enabled(&self, cx: &App) -> bool {
 5759        !self.code_action_providers.is_empty()
 5760            && EditorSettings::get_global(cx).toolbar.code_actions
 5761    }
 5762
 5763    pub fn has_available_code_actions(&self) -> bool {
 5764        self.available_code_actions
 5765            .as_ref()
 5766            .is_some_and(|(_, actions)| !actions.is_empty())
 5767    }
 5768
 5769    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5770        &self.context_menu
 5771    }
 5772
 5773    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5774        let newest_selection = self.selections.newest_anchor().clone();
 5775        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5776        let buffer = self.buffer.read(cx);
 5777        if newest_selection.head().diff_base_anchor.is_some() {
 5778            return None;
 5779        }
 5780        let (start_buffer, start) =
 5781            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5782        let (end_buffer, end) =
 5783            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5784        if start_buffer != end_buffer {
 5785            return None;
 5786        }
 5787
 5788        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5789            cx.background_executor()
 5790                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5791                .await;
 5792
 5793            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5794                let providers = this.code_action_providers.clone();
 5795                let tasks = this
 5796                    .code_action_providers
 5797                    .iter()
 5798                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5799                    .collect::<Vec<_>>();
 5800                (providers, tasks)
 5801            })?;
 5802
 5803            let mut actions = Vec::new();
 5804            for (provider, provider_actions) in
 5805                providers.into_iter().zip(future::join_all(tasks).await)
 5806            {
 5807                if let Some(provider_actions) = provider_actions.log_err() {
 5808                    actions.extend(provider_actions.into_iter().map(|action| {
 5809                        AvailableCodeAction {
 5810                            excerpt_id: newest_selection.start.excerpt_id,
 5811                            action,
 5812                            provider: provider.clone(),
 5813                        }
 5814                    }));
 5815                }
 5816            }
 5817
 5818            this.update(cx, |this, cx| {
 5819                this.available_code_actions = if actions.is_empty() {
 5820                    None
 5821                } else {
 5822                    Some((
 5823                        Location {
 5824                            buffer: start_buffer,
 5825                            range: start..end,
 5826                        },
 5827                        actions.into(),
 5828                    ))
 5829                };
 5830                cx.notify();
 5831            })
 5832        }));
 5833        None
 5834    }
 5835
 5836    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5837        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5838            self.show_git_blame_inline = false;
 5839
 5840            self.show_git_blame_inline_delay_task =
 5841                Some(cx.spawn_in(window, async move |this, cx| {
 5842                    cx.background_executor().timer(delay).await;
 5843
 5844                    this.update(cx, |this, cx| {
 5845                        this.show_git_blame_inline = true;
 5846                        cx.notify();
 5847                    })
 5848                    .log_err();
 5849                }));
 5850        }
 5851    }
 5852
 5853    fn show_blame_popover(
 5854        &mut self,
 5855        blame_entry: &BlameEntry,
 5856        position: gpui::Point<Pixels>,
 5857        cx: &mut Context<Self>,
 5858    ) {
 5859        if let Some(state) = &mut self.inline_blame_popover {
 5860            state.hide_task.take();
 5861            cx.notify();
 5862        } else {
 5863            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5864            let show_task = cx.spawn(async move |editor, cx| {
 5865                cx.background_executor()
 5866                    .timer(std::time::Duration::from_millis(delay))
 5867                    .await;
 5868                editor
 5869                    .update(cx, |editor, cx| {
 5870                        if let Some(state) = &mut editor.inline_blame_popover {
 5871                            state.show_task = None;
 5872                            cx.notify();
 5873                        }
 5874                    })
 5875                    .ok();
 5876            });
 5877            let Some(blame) = self.blame.as_ref() else {
 5878                return;
 5879            };
 5880            let blame = blame.read(cx);
 5881            let details = blame.details_for_entry(&blame_entry);
 5882            let markdown = cx.new(|cx| {
 5883                Markdown::new(
 5884                    details
 5885                        .as_ref()
 5886                        .map(|message| message.message.clone())
 5887                        .unwrap_or_default(),
 5888                    None,
 5889                    None,
 5890                    cx,
 5891                )
 5892            });
 5893            self.inline_blame_popover = Some(InlineBlamePopover {
 5894                position,
 5895                show_task: Some(show_task),
 5896                hide_task: None,
 5897                popover_bounds: None,
 5898                popover_state: InlineBlamePopoverState {
 5899                    scroll_handle: ScrollHandle::new(),
 5900                    commit_message: details,
 5901                    markdown,
 5902                },
 5903            });
 5904        }
 5905    }
 5906
 5907    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5908        if let Some(state) = &mut self.inline_blame_popover {
 5909            if state.show_task.is_some() {
 5910                self.inline_blame_popover.take();
 5911                cx.notify();
 5912            } else {
 5913                let hide_task = cx.spawn(async move |editor, cx| {
 5914                    cx.background_executor()
 5915                        .timer(std::time::Duration::from_millis(100))
 5916                        .await;
 5917                    editor
 5918                        .update(cx, |editor, cx| {
 5919                            editor.inline_blame_popover.take();
 5920                            cx.notify();
 5921                        })
 5922                        .ok();
 5923                });
 5924                state.hide_task = Some(hide_task);
 5925            }
 5926        }
 5927    }
 5928
 5929    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5930        if self.pending_rename.is_some() {
 5931            return None;
 5932        }
 5933
 5934        let provider = self.semantics_provider.clone()?;
 5935        let buffer = self.buffer.read(cx);
 5936        let newest_selection = self.selections.newest_anchor().clone();
 5937        let cursor_position = newest_selection.head();
 5938        let (cursor_buffer, cursor_buffer_position) =
 5939            buffer.text_anchor_for_position(cursor_position, cx)?;
 5940        let (tail_buffer, tail_buffer_position) =
 5941            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5942        if cursor_buffer != tail_buffer {
 5943            return None;
 5944        }
 5945
 5946        let snapshot = cursor_buffer.read(cx).snapshot();
 5947        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5948        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5949        if start_word_range != end_word_range {
 5950            self.document_highlights_task.take();
 5951            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5952            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5953            return None;
 5954        }
 5955
 5956        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5957        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5958            cx.background_executor()
 5959                .timer(Duration::from_millis(debounce))
 5960                .await;
 5961
 5962            let highlights = if let Some(highlights) = cx
 5963                .update(|cx| {
 5964                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5965                })
 5966                .ok()
 5967                .flatten()
 5968            {
 5969                highlights.await.log_err()
 5970            } else {
 5971                None
 5972            };
 5973
 5974            if let Some(highlights) = highlights {
 5975                this.update(cx, |this, cx| {
 5976                    if this.pending_rename.is_some() {
 5977                        return;
 5978                    }
 5979
 5980                    let buffer_id = cursor_position.buffer_id;
 5981                    let buffer = this.buffer.read(cx);
 5982                    if !buffer
 5983                        .text_anchor_for_position(cursor_position, cx)
 5984                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5985                    {
 5986                        return;
 5987                    }
 5988
 5989                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5990                    let mut write_ranges = Vec::new();
 5991                    let mut read_ranges = Vec::new();
 5992                    for highlight in highlights {
 5993                        for (excerpt_id, excerpt_range) in
 5994                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5995                        {
 5996                            let start = highlight
 5997                                .range
 5998                                .start
 5999                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6000                            let end = highlight
 6001                                .range
 6002                                .end
 6003                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6004                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6005                                continue;
 6006                            }
 6007
 6008                            let range = Anchor {
 6009                                buffer_id,
 6010                                excerpt_id,
 6011                                text_anchor: start,
 6012                                diff_base_anchor: None,
 6013                            }..Anchor {
 6014                                buffer_id,
 6015                                excerpt_id,
 6016                                text_anchor: end,
 6017                                diff_base_anchor: None,
 6018                            };
 6019                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6020                                write_ranges.push(range);
 6021                            } else {
 6022                                read_ranges.push(range);
 6023                            }
 6024                        }
 6025                    }
 6026
 6027                    this.highlight_background::<DocumentHighlightRead>(
 6028                        &read_ranges,
 6029                        |theme| theme.editor_document_highlight_read_background,
 6030                        cx,
 6031                    );
 6032                    this.highlight_background::<DocumentHighlightWrite>(
 6033                        &write_ranges,
 6034                        |theme| theme.editor_document_highlight_write_background,
 6035                        cx,
 6036                    );
 6037                    cx.notify();
 6038                })
 6039                .log_err();
 6040            }
 6041        }));
 6042        None
 6043    }
 6044
 6045    fn prepare_highlight_query_from_selection(
 6046        &mut self,
 6047        cx: &mut Context<Editor>,
 6048    ) -> Option<(String, Range<Anchor>)> {
 6049        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6050            return None;
 6051        }
 6052        if !EditorSettings::get_global(cx).selection_highlight {
 6053            return None;
 6054        }
 6055        if self.selections.count() != 1 || self.selections.line_mode {
 6056            return None;
 6057        }
 6058        let selection = self.selections.newest::<Point>(cx);
 6059        if selection.is_empty() || selection.start.row != selection.end.row {
 6060            return None;
 6061        }
 6062        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6063        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6064        let query = multi_buffer_snapshot
 6065            .text_for_range(selection_anchor_range.clone())
 6066            .collect::<String>();
 6067        if query.trim().is_empty() {
 6068            return None;
 6069        }
 6070        Some((query, selection_anchor_range))
 6071    }
 6072
 6073    fn update_selection_occurrence_highlights(
 6074        &mut self,
 6075        query_text: String,
 6076        query_range: Range<Anchor>,
 6077        multi_buffer_range_to_query: Range<Point>,
 6078        use_debounce: bool,
 6079        window: &mut Window,
 6080        cx: &mut Context<Editor>,
 6081    ) -> Task<()> {
 6082        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6083        cx.spawn_in(window, async move |editor, cx| {
 6084            if use_debounce {
 6085                cx.background_executor()
 6086                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6087                    .await;
 6088            }
 6089            let match_task = cx.background_spawn(async move {
 6090                let buffer_ranges = multi_buffer_snapshot
 6091                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6092                    .into_iter()
 6093                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6094                let mut match_ranges = Vec::new();
 6095                let Ok(regex) = project::search::SearchQuery::text(
 6096                    query_text.clone(),
 6097                    false,
 6098                    false,
 6099                    false,
 6100                    Default::default(),
 6101                    Default::default(),
 6102                    false,
 6103                    None,
 6104                ) else {
 6105                    return Vec::default();
 6106                };
 6107                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6108                    match_ranges.extend(
 6109                        regex
 6110                            .search(&buffer_snapshot, Some(search_range.clone()))
 6111                            .await
 6112                            .into_iter()
 6113                            .filter_map(|match_range| {
 6114                                let match_start = buffer_snapshot
 6115                                    .anchor_after(search_range.start + match_range.start);
 6116                                let match_end = buffer_snapshot
 6117                                    .anchor_before(search_range.start + match_range.end);
 6118                                let match_anchor_range = Anchor::range_in_buffer(
 6119                                    excerpt_id,
 6120                                    buffer_snapshot.remote_id(),
 6121                                    match_start..match_end,
 6122                                );
 6123                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6124                            }),
 6125                    );
 6126                }
 6127                match_ranges
 6128            });
 6129            let match_ranges = match_task.await;
 6130            editor
 6131                .update_in(cx, |editor, _, cx| {
 6132                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6133                    if !match_ranges.is_empty() {
 6134                        editor.highlight_background::<SelectedTextHighlight>(
 6135                            &match_ranges,
 6136                            |theme| theme.editor_document_highlight_bracket_background,
 6137                            cx,
 6138                        )
 6139                    }
 6140                })
 6141                .log_err();
 6142        })
 6143    }
 6144
 6145    fn refresh_selected_text_highlights(
 6146        &mut self,
 6147        on_buffer_edit: bool,
 6148        window: &mut Window,
 6149        cx: &mut Context<Editor>,
 6150    ) {
 6151        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6152        else {
 6153            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6154            self.quick_selection_highlight_task.take();
 6155            self.debounced_selection_highlight_task.take();
 6156            return;
 6157        };
 6158        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6159        if on_buffer_edit
 6160            || self
 6161                .quick_selection_highlight_task
 6162                .as_ref()
 6163                .map_or(true, |(prev_anchor_range, _)| {
 6164                    prev_anchor_range != &query_range
 6165                })
 6166        {
 6167            let multi_buffer_visible_start = self
 6168                .scroll_manager
 6169                .anchor()
 6170                .anchor
 6171                .to_point(&multi_buffer_snapshot);
 6172            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6173                multi_buffer_visible_start
 6174                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6175                Bias::Left,
 6176            );
 6177            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6178            self.quick_selection_highlight_task = Some((
 6179                query_range.clone(),
 6180                self.update_selection_occurrence_highlights(
 6181                    query_text.clone(),
 6182                    query_range.clone(),
 6183                    multi_buffer_visible_range,
 6184                    false,
 6185                    window,
 6186                    cx,
 6187                ),
 6188            ));
 6189        }
 6190        if on_buffer_edit
 6191            || self
 6192                .debounced_selection_highlight_task
 6193                .as_ref()
 6194                .map_or(true, |(prev_anchor_range, _)| {
 6195                    prev_anchor_range != &query_range
 6196                })
 6197        {
 6198            let multi_buffer_start = multi_buffer_snapshot
 6199                .anchor_before(0)
 6200                .to_point(&multi_buffer_snapshot);
 6201            let multi_buffer_end = multi_buffer_snapshot
 6202                .anchor_after(multi_buffer_snapshot.len())
 6203                .to_point(&multi_buffer_snapshot);
 6204            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6205            self.debounced_selection_highlight_task = Some((
 6206                query_range.clone(),
 6207                self.update_selection_occurrence_highlights(
 6208                    query_text,
 6209                    query_range,
 6210                    multi_buffer_full_range,
 6211                    true,
 6212                    window,
 6213                    cx,
 6214                ),
 6215            ));
 6216        }
 6217    }
 6218
 6219    pub fn refresh_inline_completion(
 6220        &mut self,
 6221        debounce: bool,
 6222        user_requested: bool,
 6223        window: &mut Window,
 6224        cx: &mut Context<Self>,
 6225    ) -> Option<()> {
 6226        let provider = self.edit_prediction_provider()?;
 6227        let cursor = self.selections.newest_anchor().head();
 6228        let (buffer, cursor_buffer_position) =
 6229            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6230
 6231        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6232            self.discard_inline_completion(false, cx);
 6233            return None;
 6234        }
 6235
 6236        if !user_requested
 6237            && (!self.should_show_edit_predictions()
 6238                || !self.is_focused(window)
 6239                || buffer.read(cx).is_empty())
 6240        {
 6241            self.discard_inline_completion(false, cx);
 6242            return None;
 6243        }
 6244
 6245        self.update_visible_inline_completion(window, cx);
 6246        provider.refresh(
 6247            self.project.clone(),
 6248            buffer,
 6249            cursor_buffer_position,
 6250            debounce,
 6251            cx,
 6252        );
 6253        Some(())
 6254    }
 6255
 6256    fn show_edit_predictions_in_menu(&self) -> bool {
 6257        match self.edit_prediction_settings {
 6258            EditPredictionSettings::Disabled => false,
 6259            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6260        }
 6261    }
 6262
 6263    pub fn edit_predictions_enabled(&self) -> bool {
 6264        match self.edit_prediction_settings {
 6265            EditPredictionSettings::Disabled => false,
 6266            EditPredictionSettings::Enabled { .. } => true,
 6267        }
 6268    }
 6269
 6270    fn edit_prediction_requires_modifier(&self) -> bool {
 6271        match self.edit_prediction_settings {
 6272            EditPredictionSettings::Disabled => false,
 6273            EditPredictionSettings::Enabled {
 6274                preview_requires_modifier,
 6275                ..
 6276            } => preview_requires_modifier,
 6277        }
 6278    }
 6279
 6280    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6281        if self.edit_prediction_provider.is_none() {
 6282            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6283        } else {
 6284            let selection = self.selections.newest_anchor();
 6285            let cursor = selection.head();
 6286
 6287            if let Some((buffer, cursor_buffer_position)) =
 6288                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6289            {
 6290                self.edit_prediction_settings =
 6291                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6292            }
 6293        }
 6294    }
 6295
 6296    fn edit_prediction_settings_at_position(
 6297        &self,
 6298        buffer: &Entity<Buffer>,
 6299        buffer_position: language::Anchor,
 6300        cx: &App,
 6301    ) -> EditPredictionSettings {
 6302        if !self.mode.is_full()
 6303            || !self.show_inline_completions_override.unwrap_or(true)
 6304            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6305        {
 6306            return EditPredictionSettings::Disabled;
 6307        }
 6308
 6309        let buffer = buffer.read(cx);
 6310
 6311        let file = buffer.file();
 6312
 6313        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6314            return EditPredictionSettings::Disabled;
 6315        };
 6316
 6317        let by_provider = matches!(
 6318            self.menu_inline_completions_policy,
 6319            MenuInlineCompletionsPolicy::ByProvider
 6320        );
 6321
 6322        let show_in_menu = by_provider
 6323            && self
 6324                .edit_prediction_provider
 6325                .as_ref()
 6326                .map_or(false, |provider| {
 6327                    provider.provider.show_completions_in_menu()
 6328                });
 6329
 6330        let preview_requires_modifier =
 6331            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6332
 6333        EditPredictionSettings::Enabled {
 6334            show_in_menu,
 6335            preview_requires_modifier,
 6336        }
 6337    }
 6338
 6339    fn should_show_edit_predictions(&self) -> bool {
 6340        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6341    }
 6342
 6343    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6344        matches!(
 6345            self.edit_prediction_preview,
 6346            EditPredictionPreview::Active { .. }
 6347        )
 6348    }
 6349
 6350    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6351        let cursor = self.selections.newest_anchor().head();
 6352        if let Some((buffer, cursor_position)) =
 6353            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6354        {
 6355            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6356        } else {
 6357            false
 6358        }
 6359    }
 6360
 6361    pub fn supports_minimap(&self, cx: &App) -> bool {
 6362        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6363    }
 6364
 6365    fn edit_predictions_enabled_in_buffer(
 6366        &self,
 6367        buffer: &Entity<Buffer>,
 6368        buffer_position: language::Anchor,
 6369        cx: &App,
 6370    ) -> bool {
 6371        maybe!({
 6372            if self.read_only(cx) {
 6373                return Some(false);
 6374            }
 6375            let provider = self.edit_prediction_provider()?;
 6376            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6377                return Some(false);
 6378            }
 6379            let buffer = buffer.read(cx);
 6380            let Some(file) = buffer.file() else {
 6381                return Some(true);
 6382            };
 6383            let settings = all_language_settings(Some(file), cx);
 6384            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6385        })
 6386        .unwrap_or(false)
 6387    }
 6388
 6389    fn cycle_inline_completion(
 6390        &mut self,
 6391        direction: Direction,
 6392        window: &mut Window,
 6393        cx: &mut Context<Self>,
 6394    ) -> Option<()> {
 6395        let provider = self.edit_prediction_provider()?;
 6396        let cursor = self.selections.newest_anchor().head();
 6397        let (buffer, cursor_buffer_position) =
 6398            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6399        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6400            return None;
 6401        }
 6402
 6403        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6404        self.update_visible_inline_completion(window, cx);
 6405
 6406        Some(())
 6407    }
 6408
 6409    pub fn show_inline_completion(
 6410        &mut self,
 6411        _: &ShowEditPrediction,
 6412        window: &mut Window,
 6413        cx: &mut Context<Self>,
 6414    ) {
 6415        if !self.has_active_inline_completion() {
 6416            self.refresh_inline_completion(false, true, window, cx);
 6417            return;
 6418        }
 6419
 6420        self.update_visible_inline_completion(window, cx);
 6421    }
 6422
 6423    pub fn display_cursor_names(
 6424        &mut self,
 6425        _: &DisplayCursorNames,
 6426        window: &mut Window,
 6427        cx: &mut Context<Self>,
 6428    ) {
 6429        self.show_cursor_names(window, cx);
 6430    }
 6431
 6432    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6433        self.show_cursor_names = true;
 6434        cx.notify();
 6435        cx.spawn_in(window, async move |this, cx| {
 6436            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6437            this.update(cx, |this, cx| {
 6438                this.show_cursor_names = false;
 6439                cx.notify()
 6440            })
 6441            .ok()
 6442        })
 6443        .detach();
 6444    }
 6445
 6446    pub fn next_edit_prediction(
 6447        &mut self,
 6448        _: &NextEditPrediction,
 6449        window: &mut Window,
 6450        cx: &mut Context<Self>,
 6451    ) {
 6452        if self.has_active_inline_completion() {
 6453            self.cycle_inline_completion(Direction::Next, window, cx);
 6454        } else {
 6455            let is_copilot_disabled = self
 6456                .refresh_inline_completion(false, true, window, cx)
 6457                .is_none();
 6458            if is_copilot_disabled {
 6459                cx.propagate();
 6460            }
 6461        }
 6462    }
 6463
 6464    pub fn previous_edit_prediction(
 6465        &mut self,
 6466        _: &PreviousEditPrediction,
 6467        window: &mut Window,
 6468        cx: &mut Context<Self>,
 6469    ) {
 6470        if self.has_active_inline_completion() {
 6471            self.cycle_inline_completion(Direction::Prev, window, cx);
 6472        } else {
 6473            let is_copilot_disabled = self
 6474                .refresh_inline_completion(false, true, window, cx)
 6475                .is_none();
 6476            if is_copilot_disabled {
 6477                cx.propagate();
 6478            }
 6479        }
 6480    }
 6481
 6482    pub fn accept_edit_prediction(
 6483        &mut self,
 6484        _: &AcceptEditPrediction,
 6485        window: &mut Window,
 6486        cx: &mut Context<Self>,
 6487    ) {
 6488        if self.show_edit_predictions_in_menu() {
 6489            self.hide_context_menu(window, cx);
 6490        }
 6491
 6492        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6493            return;
 6494        };
 6495
 6496        self.report_inline_completion_event(
 6497            active_inline_completion.completion_id.clone(),
 6498            true,
 6499            cx,
 6500        );
 6501
 6502        match &active_inline_completion.completion {
 6503            InlineCompletion::Move { target, .. } => {
 6504                let target = *target;
 6505
 6506                if let Some(position_map) = &self.last_position_map {
 6507                    if position_map
 6508                        .visible_row_range
 6509                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6510                        || !self.edit_prediction_requires_modifier()
 6511                    {
 6512                        self.unfold_ranges(&[target..target], true, false, cx);
 6513                        // Note that this is also done in vim's handler of the Tab action.
 6514                        self.change_selections(
 6515                            Some(Autoscroll::newest()),
 6516                            window,
 6517                            cx,
 6518                            |selections| {
 6519                                selections.select_anchor_ranges([target..target]);
 6520                            },
 6521                        );
 6522                        self.clear_row_highlights::<EditPredictionPreview>();
 6523
 6524                        self.edit_prediction_preview
 6525                            .set_previous_scroll_position(None);
 6526                    } else {
 6527                        self.edit_prediction_preview
 6528                            .set_previous_scroll_position(Some(
 6529                                position_map.snapshot.scroll_anchor,
 6530                            ));
 6531
 6532                        self.highlight_rows::<EditPredictionPreview>(
 6533                            target..target,
 6534                            cx.theme().colors().editor_highlighted_line_background,
 6535                            RowHighlightOptions {
 6536                                autoscroll: true,
 6537                                ..Default::default()
 6538                            },
 6539                            cx,
 6540                        );
 6541                        self.request_autoscroll(Autoscroll::fit(), cx);
 6542                    }
 6543                }
 6544            }
 6545            InlineCompletion::Edit { edits, .. } => {
 6546                if let Some(provider) = self.edit_prediction_provider() {
 6547                    provider.accept(cx);
 6548                }
 6549
 6550                // Store the transaction ID and selections before applying the edit
 6551                let transaction_id_prev =
 6552                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6553
 6554                let snapshot = self.buffer.read(cx).snapshot(cx);
 6555                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6556
 6557                self.buffer.update(cx, |buffer, cx| {
 6558                    buffer.edit(edits.iter().cloned(), None, cx)
 6559                });
 6560
 6561                self.change_selections(None, window, cx, |s| {
 6562                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6563                });
 6564
 6565                let selections = self.selections.disjoint_anchors();
 6566                if let Some(transaction_id_now) =
 6567                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6568                {
 6569                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6570                    if has_new_transaction {
 6571                        self.selection_history
 6572                            .insert_transaction(transaction_id_now, selections);
 6573                    }
 6574                }
 6575
 6576                self.update_visible_inline_completion(window, cx);
 6577                if self.active_inline_completion.is_none() {
 6578                    self.refresh_inline_completion(true, true, window, cx);
 6579                }
 6580
 6581                cx.notify();
 6582            }
 6583        }
 6584
 6585        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6586    }
 6587
 6588    pub fn accept_partial_inline_completion(
 6589        &mut self,
 6590        _: &AcceptPartialEditPrediction,
 6591        window: &mut Window,
 6592        cx: &mut Context<Self>,
 6593    ) {
 6594        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6595            return;
 6596        };
 6597        if self.selections.count() != 1 {
 6598            return;
 6599        }
 6600
 6601        self.report_inline_completion_event(
 6602            active_inline_completion.completion_id.clone(),
 6603            true,
 6604            cx,
 6605        );
 6606
 6607        match &active_inline_completion.completion {
 6608            InlineCompletion::Move { target, .. } => {
 6609                let target = *target;
 6610                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6611                    selections.select_anchor_ranges([target..target]);
 6612                });
 6613            }
 6614            InlineCompletion::Edit { edits, .. } => {
 6615                // Find an insertion that starts at the cursor position.
 6616                let snapshot = self.buffer.read(cx).snapshot(cx);
 6617                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6618                let insertion = edits.iter().find_map(|(range, text)| {
 6619                    let range = range.to_offset(&snapshot);
 6620                    if range.is_empty() && range.start == cursor_offset {
 6621                        Some(text)
 6622                    } else {
 6623                        None
 6624                    }
 6625                });
 6626
 6627                if let Some(text) = insertion {
 6628                    let mut partial_completion = text
 6629                        .chars()
 6630                        .by_ref()
 6631                        .take_while(|c| c.is_alphabetic())
 6632                        .collect::<String>();
 6633                    if partial_completion.is_empty() {
 6634                        partial_completion = text
 6635                            .chars()
 6636                            .by_ref()
 6637                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6638                            .collect::<String>();
 6639                    }
 6640
 6641                    cx.emit(EditorEvent::InputHandled {
 6642                        utf16_range_to_replace: None,
 6643                        text: partial_completion.clone().into(),
 6644                    });
 6645
 6646                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6647
 6648                    self.refresh_inline_completion(true, true, window, cx);
 6649                    cx.notify();
 6650                } else {
 6651                    self.accept_edit_prediction(&Default::default(), window, cx);
 6652                }
 6653            }
 6654        }
 6655    }
 6656
 6657    fn discard_inline_completion(
 6658        &mut self,
 6659        should_report_inline_completion_event: bool,
 6660        cx: &mut Context<Self>,
 6661    ) -> bool {
 6662        if should_report_inline_completion_event {
 6663            let completion_id = self
 6664                .active_inline_completion
 6665                .as_ref()
 6666                .and_then(|active_completion| active_completion.completion_id.clone());
 6667
 6668            self.report_inline_completion_event(completion_id, false, cx);
 6669        }
 6670
 6671        if let Some(provider) = self.edit_prediction_provider() {
 6672            provider.discard(cx);
 6673        }
 6674
 6675        self.take_active_inline_completion(cx)
 6676    }
 6677
 6678    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6679        let Some(provider) = self.edit_prediction_provider() else {
 6680            return;
 6681        };
 6682
 6683        let Some((_, buffer, _)) = self
 6684            .buffer
 6685            .read(cx)
 6686            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6687        else {
 6688            return;
 6689        };
 6690
 6691        let extension = buffer
 6692            .read(cx)
 6693            .file()
 6694            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6695
 6696        let event_type = match accepted {
 6697            true => "Edit Prediction Accepted",
 6698            false => "Edit Prediction Discarded",
 6699        };
 6700        telemetry::event!(
 6701            event_type,
 6702            provider = provider.name(),
 6703            prediction_id = id,
 6704            suggestion_accepted = accepted,
 6705            file_extension = extension,
 6706        );
 6707    }
 6708
 6709    pub fn has_active_inline_completion(&self) -> bool {
 6710        self.active_inline_completion.is_some()
 6711    }
 6712
 6713    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6714        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6715            return false;
 6716        };
 6717
 6718        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6719        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6720        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6721        true
 6722    }
 6723
 6724    /// Returns true when we're displaying the edit prediction popover below the cursor
 6725    /// like we are not previewing and the LSP autocomplete menu is visible
 6726    /// or we are in `when_holding_modifier` mode.
 6727    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6728        if self.edit_prediction_preview_is_active()
 6729            || !self.show_edit_predictions_in_menu()
 6730            || !self.edit_predictions_enabled()
 6731        {
 6732            return false;
 6733        }
 6734
 6735        if self.has_visible_completions_menu() {
 6736            return true;
 6737        }
 6738
 6739        has_completion && self.edit_prediction_requires_modifier()
 6740    }
 6741
 6742    fn handle_modifiers_changed(
 6743        &mut self,
 6744        modifiers: Modifiers,
 6745        position_map: &PositionMap,
 6746        window: &mut Window,
 6747        cx: &mut Context<Self>,
 6748    ) {
 6749        if self.show_edit_predictions_in_menu() {
 6750            self.update_edit_prediction_preview(&modifiers, window, cx);
 6751        }
 6752
 6753        self.update_selection_mode(&modifiers, position_map, window, cx);
 6754
 6755        let mouse_position = window.mouse_position();
 6756        if !position_map.text_hitbox.is_hovered(window) {
 6757            return;
 6758        }
 6759
 6760        self.update_hovered_link(
 6761            position_map.point_for_position(mouse_position),
 6762            &position_map.snapshot,
 6763            modifiers,
 6764            window,
 6765            cx,
 6766        )
 6767    }
 6768
 6769    fn update_selection_mode(
 6770        &mut self,
 6771        modifiers: &Modifiers,
 6772        position_map: &PositionMap,
 6773        window: &mut Window,
 6774        cx: &mut Context<Self>,
 6775    ) {
 6776        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6777            return;
 6778        }
 6779
 6780        let mouse_position = window.mouse_position();
 6781        let point_for_position = position_map.point_for_position(mouse_position);
 6782        let position = point_for_position.previous_valid;
 6783
 6784        self.select(
 6785            SelectPhase::BeginColumnar {
 6786                position,
 6787                reset: false,
 6788                goal_column: point_for_position.exact_unclipped.column(),
 6789            },
 6790            window,
 6791            cx,
 6792        );
 6793    }
 6794
 6795    fn update_edit_prediction_preview(
 6796        &mut self,
 6797        modifiers: &Modifiers,
 6798        window: &mut Window,
 6799        cx: &mut Context<Self>,
 6800    ) {
 6801        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6802        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6803            return;
 6804        };
 6805
 6806        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6807            if matches!(
 6808                self.edit_prediction_preview,
 6809                EditPredictionPreview::Inactive { .. }
 6810            ) {
 6811                self.edit_prediction_preview = EditPredictionPreview::Active {
 6812                    previous_scroll_position: None,
 6813                    since: Instant::now(),
 6814                };
 6815
 6816                self.update_visible_inline_completion(window, cx);
 6817                cx.notify();
 6818            }
 6819        } else if let EditPredictionPreview::Active {
 6820            previous_scroll_position,
 6821            since,
 6822        } = self.edit_prediction_preview
 6823        {
 6824            if let (Some(previous_scroll_position), Some(position_map)) =
 6825                (previous_scroll_position, self.last_position_map.as_ref())
 6826            {
 6827                self.set_scroll_position(
 6828                    previous_scroll_position
 6829                        .scroll_position(&position_map.snapshot.display_snapshot),
 6830                    window,
 6831                    cx,
 6832                );
 6833            }
 6834
 6835            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6836                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6837            };
 6838            self.clear_row_highlights::<EditPredictionPreview>();
 6839            self.update_visible_inline_completion(window, cx);
 6840            cx.notify();
 6841        }
 6842    }
 6843
 6844    fn update_visible_inline_completion(
 6845        &mut self,
 6846        _window: &mut Window,
 6847        cx: &mut Context<Self>,
 6848    ) -> Option<()> {
 6849        let selection = self.selections.newest_anchor();
 6850        let cursor = selection.head();
 6851        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6852        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6853        let excerpt_id = cursor.excerpt_id;
 6854
 6855        let show_in_menu = self.show_edit_predictions_in_menu();
 6856        let completions_menu_has_precedence = !show_in_menu
 6857            && (self.context_menu.borrow().is_some()
 6858                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6859
 6860        if completions_menu_has_precedence
 6861            || !offset_selection.is_empty()
 6862            || self
 6863                .active_inline_completion
 6864                .as_ref()
 6865                .map_or(false, |completion| {
 6866                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6867                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6868                    !invalidation_range.contains(&offset_selection.head())
 6869                })
 6870        {
 6871            self.discard_inline_completion(false, cx);
 6872            return None;
 6873        }
 6874
 6875        self.take_active_inline_completion(cx);
 6876        let Some(provider) = self.edit_prediction_provider() else {
 6877            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6878            return None;
 6879        };
 6880
 6881        let (buffer, cursor_buffer_position) =
 6882            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6883
 6884        self.edit_prediction_settings =
 6885            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6886
 6887        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6888
 6889        if self.edit_prediction_indent_conflict {
 6890            let cursor_point = cursor.to_point(&multibuffer);
 6891
 6892            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6893
 6894            if let Some((_, indent)) = indents.iter().next() {
 6895                if indent.len == cursor_point.column {
 6896                    self.edit_prediction_indent_conflict = false;
 6897                }
 6898            }
 6899        }
 6900
 6901        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6902        let edits = inline_completion
 6903            .edits
 6904            .into_iter()
 6905            .flat_map(|(range, new_text)| {
 6906                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6907                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6908                Some((start..end, new_text))
 6909            })
 6910            .collect::<Vec<_>>();
 6911        if edits.is_empty() {
 6912            return None;
 6913        }
 6914
 6915        let first_edit_start = edits.first().unwrap().0.start;
 6916        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6917        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6918
 6919        let last_edit_end = edits.last().unwrap().0.end;
 6920        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6921        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6922
 6923        let cursor_row = cursor.to_point(&multibuffer).row;
 6924
 6925        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6926
 6927        let mut inlay_ids = Vec::new();
 6928        let invalidation_row_range;
 6929        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6930            Some(cursor_row..edit_end_row)
 6931        } else if cursor_row > edit_end_row {
 6932            Some(edit_start_row..cursor_row)
 6933        } else {
 6934            None
 6935        };
 6936        let is_move =
 6937            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6938        let completion = if is_move {
 6939            invalidation_row_range =
 6940                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6941            let target = first_edit_start;
 6942            InlineCompletion::Move { target, snapshot }
 6943        } else {
 6944            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6945                && !self.inline_completions_hidden_for_vim_mode;
 6946
 6947            if show_completions_in_buffer {
 6948                if edits
 6949                    .iter()
 6950                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6951                {
 6952                    let mut inlays = Vec::new();
 6953                    for (range, new_text) in &edits {
 6954                        let inlay = Inlay::inline_completion(
 6955                            post_inc(&mut self.next_inlay_id),
 6956                            range.start,
 6957                            new_text.as_str(),
 6958                        );
 6959                        inlay_ids.push(inlay.id);
 6960                        inlays.push(inlay);
 6961                    }
 6962
 6963                    self.splice_inlays(&[], inlays, cx);
 6964                } else {
 6965                    let background_color = cx.theme().status().deleted_background;
 6966                    self.highlight_text::<InlineCompletionHighlight>(
 6967                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6968                        HighlightStyle {
 6969                            background_color: Some(background_color),
 6970                            ..Default::default()
 6971                        },
 6972                        cx,
 6973                    );
 6974                }
 6975            }
 6976
 6977            invalidation_row_range = edit_start_row..edit_end_row;
 6978
 6979            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6980                if provider.show_tab_accept_marker() {
 6981                    EditDisplayMode::TabAccept
 6982                } else {
 6983                    EditDisplayMode::Inline
 6984                }
 6985            } else {
 6986                EditDisplayMode::DiffPopover
 6987            };
 6988
 6989            InlineCompletion::Edit {
 6990                edits,
 6991                edit_preview: inline_completion.edit_preview,
 6992                display_mode,
 6993                snapshot,
 6994            }
 6995        };
 6996
 6997        let invalidation_range = multibuffer
 6998            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6999            ..multibuffer.anchor_after(Point::new(
 7000                invalidation_row_range.end,
 7001                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7002            ));
 7003
 7004        self.stale_inline_completion_in_menu = None;
 7005        self.active_inline_completion = Some(InlineCompletionState {
 7006            inlay_ids,
 7007            completion,
 7008            completion_id: inline_completion.id,
 7009            invalidation_range,
 7010        });
 7011
 7012        cx.notify();
 7013
 7014        Some(())
 7015    }
 7016
 7017    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7018        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7019    }
 7020
 7021    fn clear_tasks(&mut self) {
 7022        self.tasks.clear()
 7023    }
 7024
 7025    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7026        if self.tasks.insert(key, value).is_some() {
 7027            // This case should hopefully be rare, but just in case...
 7028            log::error!(
 7029                "multiple different run targets found on a single line, only the last target will be rendered"
 7030            )
 7031        }
 7032    }
 7033
 7034    /// Get all display points of breakpoints that will be rendered within editor
 7035    ///
 7036    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7037    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7038    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7039    fn active_breakpoints(
 7040        &self,
 7041        range: Range<DisplayRow>,
 7042        window: &mut Window,
 7043        cx: &mut Context<Self>,
 7044    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7045        let mut breakpoint_display_points = HashMap::default();
 7046
 7047        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7048            return breakpoint_display_points;
 7049        };
 7050
 7051        let snapshot = self.snapshot(window, cx);
 7052
 7053        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7054        let Some(project) = self.project.as_ref() else {
 7055            return breakpoint_display_points;
 7056        };
 7057
 7058        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7059            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7060
 7061        for (buffer_snapshot, range, excerpt_id) in
 7062            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7063        {
 7064            let Some(buffer) = project.read_with(cx, |this, cx| {
 7065                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7066            }) else {
 7067                continue;
 7068            };
 7069            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7070                &buffer,
 7071                Some(
 7072                    buffer_snapshot.anchor_before(range.start)
 7073                        ..buffer_snapshot.anchor_after(range.end),
 7074                ),
 7075                buffer_snapshot,
 7076                cx,
 7077            );
 7078            for (breakpoint, state) in breakpoints {
 7079                let multi_buffer_anchor =
 7080                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7081                let position = multi_buffer_anchor
 7082                    .to_point(&multi_buffer_snapshot)
 7083                    .to_display_point(&snapshot);
 7084
 7085                breakpoint_display_points.insert(
 7086                    position.row(),
 7087                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7088                );
 7089            }
 7090        }
 7091
 7092        breakpoint_display_points
 7093    }
 7094
 7095    fn breakpoint_context_menu(
 7096        &self,
 7097        anchor: Anchor,
 7098        window: &mut Window,
 7099        cx: &mut Context<Self>,
 7100    ) -> Entity<ui::ContextMenu> {
 7101        let weak_editor = cx.weak_entity();
 7102        let focus_handle = self.focus_handle(cx);
 7103
 7104        let row = self
 7105            .buffer
 7106            .read(cx)
 7107            .snapshot(cx)
 7108            .summary_for_anchor::<Point>(&anchor)
 7109            .row;
 7110
 7111        let breakpoint = self
 7112            .breakpoint_at_row(row, window, cx)
 7113            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7114
 7115        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7116            "Edit Log Breakpoint"
 7117        } else {
 7118            "Set Log Breakpoint"
 7119        };
 7120
 7121        let condition_breakpoint_msg = if breakpoint
 7122            .as_ref()
 7123            .is_some_and(|bp| bp.1.condition.is_some())
 7124        {
 7125            "Edit Condition Breakpoint"
 7126        } else {
 7127            "Set Condition Breakpoint"
 7128        };
 7129
 7130        let hit_condition_breakpoint_msg = if breakpoint
 7131            .as_ref()
 7132            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7133        {
 7134            "Edit Hit Condition Breakpoint"
 7135        } else {
 7136            "Set Hit Condition Breakpoint"
 7137        };
 7138
 7139        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7140            "Unset Breakpoint"
 7141        } else {
 7142            "Set Breakpoint"
 7143        };
 7144
 7145        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7146            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7147
 7148        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7149            BreakpointState::Enabled => Some("Disable"),
 7150            BreakpointState::Disabled => Some("Enable"),
 7151        });
 7152
 7153        let (anchor, breakpoint) =
 7154            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7155
 7156        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7157            menu.on_blur_subscription(Subscription::new(|| {}))
 7158                .context(focus_handle)
 7159                .when(run_to_cursor, |this| {
 7160                    let weak_editor = weak_editor.clone();
 7161                    this.entry("Run to cursor", None, move |window, cx| {
 7162                        weak_editor
 7163                            .update(cx, |editor, cx| {
 7164                                editor.change_selections(None, window, cx, |s| {
 7165                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7166                                });
 7167                            })
 7168                            .ok();
 7169
 7170                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7171                    })
 7172                    .separator()
 7173                })
 7174                .when_some(toggle_state_msg, |this, msg| {
 7175                    this.entry(msg, None, {
 7176                        let weak_editor = weak_editor.clone();
 7177                        let breakpoint = breakpoint.clone();
 7178                        move |_window, cx| {
 7179                            weak_editor
 7180                                .update(cx, |this, cx| {
 7181                                    this.edit_breakpoint_at_anchor(
 7182                                        anchor,
 7183                                        breakpoint.as_ref().clone(),
 7184                                        BreakpointEditAction::InvertState,
 7185                                        cx,
 7186                                    );
 7187                                })
 7188                                .log_err();
 7189                        }
 7190                    })
 7191                })
 7192                .entry(set_breakpoint_msg, None, {
 7193                    let weak_editor = weak_editor.clone();
 7194                    let breakpoint = breakpoint.clone();
 7195                    move |_window, cx| {
 7196                        weak_editor
 7197                            .update(cx, |this, cx| {
 7198                                this.edit_breakpoint_at_anchor(
 7199                                    anchor,
 7200                                    breakpoint.as_ref().clone(),
 7201                                    BreakpointEditAction::Toggle,
 7202                                    cx,
 7203                                );
 7204                            })
 7205                            .log_err();
 7206                    }
 7207                })
 7208                .entry(log_breakpoint_msg, None, {
 7209                    let breakpoint = breakpoint.clone();
 7210                    let weak_editor = weak_editor.clone();
 7211                    move |window, cx| {
 7212                        weak_editor
 7213                            .update(cx, |this, cx| {
 7214                                this.add_edit_breakpoint_block(
 7215                                    anchor,
 7216                                    breakpoint.as_ref(),
 7217                                    BreakpointPromptEditAction::Log,
 7218                                    window,
 7219                                    cx,
 7220                                );
 7221                            })
 7222                            .log_err();
 7223                    }
 7224                })
 7225                .entry(condition_breakpoint_msg, None, {
 7226                    let breakpoint = breakpoint.clone();
 7227                    let weak_editor = weak_editor.clone();
 7228                    move |window, cx| {
 7229                        weak_editor
 7230                            .update(cx, |this, cx| {
 7231                                this.add_edit_breakpoint_block(
 7232                                    anchor,
 7233                                    breakpoint.as_ref(),
 7234                                    BreakpointPromptEditAction::Condition,
 7235                                    window,
 7236                                    cx,
 7237                                );
 7238                            })
 7239                            .log_err();
 7240                    }
 7241                })
 7242                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7243                    weak_editor
 7244                        .update(cx, |this, cx| {
 7245                            this.add_edit_breakpoint_block(
 7246                                anchor,
 7247                                breakpoint.as_ref(),
 7248                                BreakpointPromptEditAction::HitCondition,
 7249                                window,
 7250                                cx,
 7251                            );
 7252                        })
 7253                        .log_err();
 7254                })
 7255        })
 7256    }
 7257
 7258    fn render_breakpoint(
 7259        &self,
 7260        position: Anchor,
 7261        row: DisplayRow,
 7262        breakpoint: &Breakpoint,
 7263        state: Option<BreakpointSessionState>,
 7264        cx: &mut Context<Self>,
 7265    ) -> IconButton {
 7266        let is_rejected = state.is_some_and(|s| !s.verified);
 7267        // Is it a breakpoint that shows up when hovering over gutter?
 7268        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7269            (false, false),
 7270            |PhantomBreakpointIndicator {
 7271                 is_active,
 7272                 display_row,
 7273                 collides_with_existing_breakpoint,
 7274             }| {
 7275                (
 7276                    is_active && display_row == row,
 7277                    collides_with_existing_breakpoint,
 7278                )
 7279            },
 7280        );
 7281
 7282        let (color, icon) = {
 7283            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7284                (false, false) => ui::IconName::DebugBreakpoint,
 7285                (true, false) => ui::IconName::DebugLogBreakpoint,
 7286                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7287                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7288            };
 7289
 7290            let color = if is_phantom {
 7291                Color::Hint
 7292            } else if is_rejected {
 7293                Color::Disabled
 7294            } else {
 7295                Color::Debugger
 7296            };
 7297
 7298            (color, icon)
 7299        };
 7300
 7301        let breakpoint = Arc::from(breakpoint.clone());
 7302
 7303        let alt_as_text = gpui::Keystroke {
 7304            modifiers: Modifiers::secondary_key(),
 7305            ..Default::default()
 7306        };
 7307        let primary_action_text = if breakpoint.is_disabled() {
 7308            "Enable breakpoint"
 7309        } else if is_phantom && !collides_with_existing {
 7310            "Set breakpoint"
 7311        } else {
 7312            "Unset breakpoint"
 7313        };
 7314        let focus_handle = self.focus_handle.clone();
 7315
 7316        let meta = if is_rejected {
 7317            SharedString::from("No executable code is associated with this line.")
 7318        } else if collides_with_existing && !breakpoint.is_disabled() {
 7319            SharedString::from(format!(
 7320                "{alt_as_text}-click to disable,\nright-click for more options."
 7321            ))
 7322        } else {
 7323            SharedString::from("Right-click for more options.")
 7324        };
 7325        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7326            .icon_size(IconSize::XSmall)
 7327            .size(ui::ButtonSize::None)
 7328            .when(is_rejected, |this| {
 7329                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7330            })
 7331            .icon_color(color)
 7332            .style(ButtonStyle::Transparent)
 7333            .on_click(cx.listener({
 7334                let breakpoint = breakpoint.clone();
 7335
 7336                move |editor, event: &ClickEvent, window, cx| {
 7337                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7338                        BreakpointEditAction::InvertState
 7339                    } else {
 7340                        BreakpointEditAction::Toggle
 7341                    };
 7342
 7343                    window.focus(&editor.focus_handle(cx));
 7344                    editor.edit_breakpoint_at_anchor(
 7345                        position,
 7346                        breakpoint.as_ref().clone(),
 7347                        edit_action,
 7348                        cx,
 7349                    );
 7350                }
 7351            }))
 7352            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7353                editor.set_breakpoint_context_menu(
 7354                    row,
 7355                    Some(position),
 7356                    event.down.position,
 7357                    window,
 7358                    cx,
 7359                );
 7360            }))
 7361            .tooltip(move |window, cx| {
 7362                Tooltip::with_meta_in(
 7363                    primary_action_text,
 7364                    Some(&ToggleBreakpoint),
 7365                    meta.clone(),
 7366                    &focus_handle,
 7367                    window,
 7368                    cx,
 7369                )
 7370            })
 7371    }
 7372
 7373    fn build_tasks_context(
 7374        project: &Entity<Project>,
 7375        buffer: &Entity<Buffer>,
 7376        buffer_row: u32,
 7377        tasks: &Arc<RunnableTasks>,
 7378        cx: &mut Context<Self>,
 7379    ) -> Task<Option<task::TaskContext>> {
 7380        let position = Point::new(buffer_row, tasks.column);
 7381        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7382        let location = Location {
 7383            buffer: buffer.clone(),
 7384            range: range_start..range_start,
 7385        };
 7386        // Fill in the environmental variables from the tree-sitter captures
 7387        let mut captured_task_variables = TaskVariables::default();
 7388        for (capture_name, value) in tasks.extra_variables.clone() {
 7389            captured_task_variables.insert(
 7390                task::VariableName::Custom(capture_name.into()),
 7391                value.clone(),
 7392            );
 7393        }
 7394        project.update(cx, |project, cx| {
 7395            project.task_store().update(cx, |task_store, cx| {
 7396                task_store.task_context_for_location(captured_task_variables, location, cx)
 7397            })
 7398        })
 7399    }
 7400
 7401    pub fn spawn_nearest_task(
 7402        &mut self,
 7403        action: &SpawnNearestTask,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) {
 7407        let Some((workspace, _)) = self.workspace.clone() else {
 7408            return;
 7409        };
 7410        let Some(project) = self.project.clone() else {
 7411            return;
 7412        };
 7413
 7414        // Try to find a closest, enclosing node using tree-sitter that has a
 7415        // task
 7416        let Some((buffer, buffer_row, tasks)) = self
 7417            .find_enclosing_node_task(cx)
 7418            // Or find the task that's closest in row-distance.
 7419            .or_else(|| self.find_closest_task(cx))
 7420        else {
 7421            return;
 7422        };
 7423
 7424        let reveal_strategy = action.reveal;
 7425        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7426        cx.spawn_in(window, async move |_, cx| {
 7427            let context = task_context.await?;
 7428            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7429
 7430            let resolved = &mut resolved_task.resolved;
 7431            resolved.reveal = reveal_strategy;
 7432
 7433            workspace
 7434                .update_in(cx, |workspace, window, cx| {
 7435                    workspace.schedule_resolved_task(
 7436                        task_source_kind,
 7437                        resolved_task,
 7438                        false,
 7439                        window,
 7440                        cx,
 7441                    );
 7442                })
 7443                .ok()
 7444        })
 7445        .detach();
 7446    }
 7447
 7448    fn find_closest_task(
 7449        &mut self,
 7450        cx: &mut Context<Self>,
 7451    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7452        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7453
 7454        let ((buffer_id, row), tasks) = self
 7455            .tasks
 7456            .iter()
 7457            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7458
 7459        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7460        let tasks = Arc::new(tasks.to_owned());
 7461        Some((buffer, *row, tasks))
 7462    }
 7463
 7464    fn find_enclosing_node_task(
 7465        &mut self,
 7466        cx: &mut Context<Self>,
 7467    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7468        let snapshot = self.buffer.read(cx).snapshot(cx);
 7469        let offset = self.selections.newest::<usize>(cx).head();
 7470        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7471        let buffer_id = excerpt.buffer().remote_id();
 7472
 7473        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7474        let mut cursor = layer.node().walk();
 7475
 7476        while cursor.goto_first_child_for_byte(offset).is_some() {
 7477            if cursor.node().end_byte() == offset {
 7478                cursor.goto_next_sibling();
 7479            }
 7480        }
 7481
 7482        // Ascend to the smallest ancestor that contains the range and has a task.
 7483        loop {
 7484            let node = cursor.node();
 7485            let node_range = node.byte_range();
 7486            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7487
 7488            // Check if this node contains our offset
 7489            if node_range.start <= offset && node_range.end >= offset {
 7490                // If it contains offset, check for task
 7491                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7492                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7493                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7494                }
 7495            }
 7496
 7497            if !cursor.goto_parent() {
 7498                break;
 7499            }
 7500        }
 7501        None
 7502    }
 7503
 7504    fn render_run_indicator(
 7505        &self,
 7506        _style: &EditorStyle,
 7507        is_active: bool,
 7508        row: DisplayRow,
 7509        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7510        cx: &mut Context<Self>,
 7511    ) -> IconButton {
 7512        let color = Color::Muted;
 7513        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7514
 7515        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7516            .shape(ui::IconButtonShape::Square)
 7517            .icon_size(IconSize::XSmall)
 7518            .icon_color(color)
 7519            .toggle_state(is_active)
 7520            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7521                let quick_launch = e.down.button == MouseButton::Left;
 7522                window.focus(&editor.focus_handle(cx));
 7523                editor.toggle_code_actions(
 7524                    &ToggleCodeActions {
 7525                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7526                        quick_launch,
 7527                    },
 7528                    window,
 7529                    cx,
 7530                );
 7531            }))
 7532            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7533                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7534            }))
 7535    }
 7536
 7537    pub fn context_menu_visible(&self) -> bool {
 7538        !self.edit_prediction_preview_is_active()
 7539            && self
 7540                .context_menu
 7541                .borrow()
 7542                .as_ref()
 7543                .map_or(false, |menu| menu.visible())
 7544    }
 7545
 7546    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7547        self.context_menu
 7548            .borrow()
 7549            .as_ref()
 7550            .map(|menu| menu.origin())
 7551    }
 7552
 7553    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7554        self.context_menu_options = Some(options);
 7555    }
 7556
 7557    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7558    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7559
 7560    fn render_edit_prediction_popover(
 7561        &mut self,
 7562        text_bounds: &Bounds<Pixels>,
 7563        content_origin: gpui::Point<Pixels>,
 7564        right_margin: Pixels,
 7565        editor_snapshot: &EditorSnapshot,
 7566        visible_row_range: Range<DisplayRow>,
 7567        scroll_top: f32,
 7568        scroll_bottom: f32,
 7569        line_layouts: &[LineWithInvisibles],
 7570        line_height: Pixels,
 7571        scroll_pixel_position: gpui::Point<Pixels>,
 7572        newest_selection_head: Option<DisplayPoint>,
 7573        editor_width: Pixels,
 7574        style: &EditorStyle,
 7575        window: &mut Window,
 7576        cx: &mut App,
 7577    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7578        if self.mode().is_minimap() {
 7579            return None;
 7580        }
 7581        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7582
 7583        if self.edit_prediction_visible_in_cursor_popover(true) {
 7584            return None;
 7585        }
 7586
 7587        match &active_inline_completion.completion {
 7588            InlineCompletion::Move { target, .. } => {
 7589                let target_display_point = target.to_display_point(editor_snapshot);
 7590
 7591                if self.edit_prediction_requires_modifier() {
 7592                    if !self.edit_prediction_preview_is_active() {
 7593                        return None;
 7594                    }
 7595
 7596                    self.render_edit_prediction_modifier_jump_popover(
 7597                        text_bounds,
 7598                        content_origin,
 7599                        visible_row_range,
 7600                        line_layouts,
 7601                        line_height,
 7602                        scroll_pixel_position,
 7603                        newest_selection_head,
 7604                        target_display_point,
 7605                        window,
 7606                        cx,
 7607                    )
 7608                } else {
 7609                    self.render_edit_prediction_eager_jump_popover(
 7610                        text_bounds,
 7611                        content_origin,
 7612                        editor_snapshot,
 7613                        visible_row_range,
 7614                        scroll_top,
 7615                        scroll_bottom,
 7616                        line_height,
 7617                        scroll_pixel_position,
 7618                        target_display_point,
 7619                        editor_width,
 7620                        window,
 7621                        cx,
 7622                    )
 7623                }
 7624            }
 7625            InlineCompletion::Edit {
 7626                display_mode: EditDisplayMode::Inline,
 7627                ..
 7628            } => None,
 7629            InlineCompletion::Edit {
 7630                display_mode: EditDisplayMode::TabAccept,
 7631                edits,
 7632                ..
 7633            } => {
 7634                let range = &edits.first()?.0;
 7635                let target_display_point = range.end.to_display_point(editor_snapshot);
 7636
 7637                self.render_edit_prediction_end_of_line_popover(
 7638                    "Accept",
 7639                    editor_snapshot,
 7640                    visible_row_range,
 7641                    target_display_point,
 7642                    line_height,
 7643                    scroll_pixel_position,
 7644                    content_origin,
 7645                    editor_width,
 7646                    window,
 7647                    cx,
 7648                )
 7649            }
 7650            InlineCompletion::Edit {
 7651                edits,
 7652                edit_preview,
 7653                display_mode: EditDisplayMode::DiffPopover,
 7654                snapshot,
 7655            } => self.render_edit_prediction_diff_popover(
 7656                text_bounds,
 7657                content_origin,
 7658                right_margin,
 7659                editor_snapshot,
 7660                visible_row_range,
 7661                line_layouts,
 7662                line_height,
 7663                scroll_pixel_position,
 7664                newest_selection_head,
 7665                editor_width,
 7666                style,
 7667                edits,
 7668                edit_preview,
 7669                snapshot,
 7670                window,
 7671                cx,
 7672            ),
 7673        }
 7674    }
 7675
 7676    fn render_edit_prediction_modifier_jump_popover(
 7677        &mut self,
 7678        text_bounds: &Bounds<Pixels>,
 7679        content_origin: gpui::Point<Pixels>,
 7680        visible_row_range: Range<DisplayRow>,
 7681        line_layouts: &[LineWithInvisibles],
 7682        line_height: Pixels,
 7683        scroll_pixel_position: gpui::Point<Pixels>,
 7684        newest_selection_head: Option<DisplayPoint>,
 7685        target_display_point: DisplayPoint,
 7686        window: &mut Window,
 7687        cx: &mut App,
 7688    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7689        let scrolled_content_origin =
 7690            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7691
 7692        const SCROLL_PADDING_Y: Pixels = px(12.);
 7693
 7694        if target_display_point.row() < visible_row_range.start {
 7695            return self.render_edit_prediction_scroll_popover(
 7696                |_| SCROLL_PADDING_Y,
 7697                IconName::ArrowUp,
 7698                visible_row_range,
 7699                line_layouts,
 7700                newest_selection_head,
 7701                scrolled_content_origin,
 7702                window,
 7703                cx,
 7704            );
 7705        } else if target_display_point.row() >= visible_row_range.end {
 7706            return self.render_edit_prediction_scroll_popover(
 7707                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7708                IconName::ArrowDown,
 7709                visible_row_range,
 7710                line_layouts,
 7711                newest_selection_head,
 7712                scrolled_content_origin,
 7713                window,
 7714                cx,
 7715            );
 7716        }
 7717
 7718        const POLE_WIDTH: Pixels = px(2.);
 7719
 7720        let line_layout =
 7721            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7722        let target_column = target_display_point.column() as usize;
 7723
 7724        let target_x = line_layout.x_for_index(target_column);
 7725        let target_y =
 7726            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7727
 7728        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7729
 7730        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7731        border_color.l += 0.001;
 7732
 7733        let mut element = v_flex()
 7734            .items_end()
 7735            .when(flag_on_right, |el| el.items_start())
 7736            .child(if flag_on_right {
 7737                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7738                    .rounded_bl(px(0.))
 7739                    .rounded_tl(px(0.))
 7740                    .border_l_2()
 7741                    .border_color(border_color)
 7742            } else {
 7743                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7744                    .rounded_br(px(0.))
 7745                    .rounded_tr(px(0.))
 7746                    .border_r_2()
 7747                    .border_color(border_color)
 7748            })
 7749            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7750            .into_any();
 7751
 7752        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7753
 7754        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7755            - point(
 7756                if flag_on_right {
 7757                    POLE_WIDTH
 7758                } else {
 7759                    size.width - POLE_WIDTH
 7760                },
 7761                size.height - line_height,
 7762            );
 7763
 7764        origin.x = origin.x.max(content_origin.x);
 7765
 7766        element.prepaint_at(origin, window, cx);
 7767
 7768        Some((element, origin))
 7769    }
 7770
 7771    fn render_edit_prediction_scroll_popover(
 7772        &mut self,
 7773        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7774        scroll_icon: IconName,
 7775        visible_row_range: Range<DisplayRow>,
 7776        line_layouts: &[LineWithInvisibles],
 7777        newest_selection_head: Option<DisplayPoint>,
 7778        scrolled_content_origin: gpui::Point<Pixels>,
 7779        window: &mut Window,
 7780        cx: &mut App,
 7781    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7782        let mut element = self
 7783            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7784            .into_any();
 7785
 7786        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7787
 7788        let cursor = newest_selection_head?;
 7789        let cursor_row_layout =
 7790            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7791        let cursor_column = cursor.column() as usize;
 7792
 7793        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7794
 7795        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7796
 7797        element.prepaint_at(origin, window, cx);
 7798        Some((element, origin))
 7799    }
 7800
 7801    fn render_edit_prediction_eager_jump_popover(
 7802        &mut self,
 7803        text_bounds: &Bounds<Pixels>,
 7804        content_origin: gpui::Point<Pixels>,
 7805        editor_snapshot: &EditorSnapshot,
 7806        visible_row_range: Range<DisplayRow>,
 7807        scroll_top: f32,
 7808        scroll_bottom: f32,
 7809        line_height: Pixels,
 7810        scroll_pixel_position: gpui::Point<Pixels>,
 7811        target_display_point: DisplayPoint,
 7812        editor_width: Pixels,
 7813        window: &mut Window,
 7814        cx: &mut App,
 7815    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7816        if target_display_point.row().as_f32() < scroll_top {
 7817            let mut element = self
 7818                .render_edit_prediction_line_popover(
 7819                    "Jump to Edit",
 7820                    Some(IconName::ArrowUp),
 7821                    window,
 7822                    cx,
 7823                )?
 7824                .into_any();
 7825
 7826            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7827            let offset = point(
 7828                (text_bounds.size.width - size.width) / 2.,
 7829                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7830            );
 7831
 7832            let origin = text_bounds.origin + offset;
 7833            element.prepaint_at(origin, window, cx);
 7834            Some((element, origin))
 7835        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7836            let mut element = self
 7837                .render_edit_prediction_line_popover(
 7838                    "Jump to Edit",
 7839                    Some(IconName::ArrowDown),
 7840                    window,
 7841                    cx,
 7842                )?
 7843                .into_any();
 7844
 7845            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7846            let offset = point(
 7847                (text_bounds.size.width - size.width) / 2.,
 7848                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7849            );
 7850
 7851            let origin = text_bounds.origin + offset;
 7852            element.prepaint_at(origin, window, cx);
 7853            Some((element, origin))
 7854        } else {
 7855            self.render_edit_prediction_end_of_line_popover(
 7856                "Jump to Edit",
 7857                editor_snapshot,
 7858                visible_row_range,
 7859                target_display_point,
 7860                line_height,
 7861                scroll_pixel_position,
 7862                content_origin,
 7863                editor_width,
 7864                window,
 7865                cx,
 7866            )
 7867        }
 7868    }
 7869
 7870    fn render_edit_prediction_end_of_line_popover(
 7871        self: &mut Editor,
 7872        label: &'static str,
 7873        editor_snapshot: &EditorSnapshot,
 7874        visible_row_range: Range<DisplayRow>,
 7875        target_display_point: DisplayPoint,
 7876        line_height: Pixels,
 7877        scroll_pixel_position: gpui::Point<Pixels>,
 7878        content_origin: gpui::Point<Pixels>,
 7879        editor_width: Pixels,
 7880        window: &mut Window,
 7881        cx: &mut App,
 7882    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7883        let target_line_end = DisplayPoint::new(
 7884            target_display_point.row(),
 7885            editor_snapshot.line_len(target_display_point.row()),
 7886        );
 7887
 7888        let mut element = self
 7889            .render_edit_prediction_line_popover(label, None, window, cx)?
 7890            .into_any();
 7891
 7892        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7893
 7894        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7895
 7896        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7897        let mut origin = start_point
 7898            + line_origin
 7899            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7900        origin.x = origin.x.max(content_origin.x);
 7901
 7902        let max_x = content_origin.x + editor_width - size.width;
 7903
 7904        if origin.x > max_x {
 7905            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7906
 7907            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7908                origin.y += offset;
 7909                IconName::ArrowUp
 7910            } else {
 7911                origin.y -= offset;
 7912                IconName::ArrowDown
 7913            };
 7914
 7915            element = self
 7916                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7917                .into_any();
 7918
 7919            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7920
 7921            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7922        }
 7923
 7924        element.prepaint_at(origin, window, cx);
 7925        Some((element, origin))
 7926    }
 7927
 7928    fn render_edit_prediction_diff_popover(
 7929        self: &Editor,
 7930        text_bounds: &Bounds<Pixels>,
 7931        content_origin: gpui::Point<Pixels>,
 7932        right_margin: Pixels,
 7933        editor_snapshot: &EditorSnapshot,
 7934        visible_row_range: Range<DisplayRow>,
 7935        line_layouts: &[LineWithInvisibles],
 7936        line_height: Pixels,
 7937        scroll_pixel_position: gpui::Point<Pixels>,
 7938        newest_selection_head: Option<DisplayPoint>,
 7939        editor_width: Pixels,
 7940        style: &EditorStyle,
 7941        edits: &Vec<(Range<Anchor>, String)>,
 7942        edit_preview: &Option<language::EditPreview>,
 7943        snapshot: &language::BufferSnapshot,
 7944        window: &mut Window,
 7945        cx: &mut App,
 7946    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7947        let edit_start = edits
 7948            .first()
 7949            .unwrap()
 7950            .0
 7951            .start
 7952            .to_display_point(editor_snapshot);
 7953        let edit_end = edits
 7954            .last()
 7955            .unwrap()
 7956            .0
 7957            .end
 7958            .to_display_point(editor_snapshot);
 7959
 7960        let is_visible = visible_row_range.contains(&edit_start.row())
 7961            || visible_row_range.contains(&edit_end.row());
 7962        if !is_visible {
 7963            return None;
 7964        }
 7965
 7966        let highlighted_edits =
 7967            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7968
 7969        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7970        let line_count = highlighted_edits.text.lines().count();
 7971
 7972        const BORDER_WIDTH: Pixels = px(1.);
 7973
 7974        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7975        let has_keybind = keybind.is_some();
 7976
 7977        let mut element = h_flex()
 7978            .items_start()
 7979            .child(
 7980                h_flex()
 7981                    .bg(cx.theme().colors().editor_background)
 7982                    .border(BORDER_WIDTH)
 7983                    .shadow_sm()
 7984                    .border_color(cx.theme().colors().border)
 7985                    .rounded_l_lg()
 7986                    .when(line_count > 1, |el| el.rounded_br_lg())
 7987                    .pr_1()
 7988                    .child(styled_text),
 7989            )
 7990            .child(
 7991                h_flex()
 7992                    .h(line_height + BORDER_WIDTH * 2.)
 7993                    .px_1p5()
 7994                    .gap_1()
 7995                    // Workaround: For some reason, there's a gap if we don't do this
 7996                    .ml(-BORDER_WIDTH)
 7997                    .shadow(vec![gpui::BoxShadow {
 7998                        color: gpui::black().opacity(0.05),
 7999                        offset: point(px(1.), px(1.)),
 8000                        blur_radius: px(2.),
 8001                        spread_radius: px(0.),
 8002                    }])
 8003                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8004                    .border(BORDER_WIDTH)
 8005                    .border_color(cx.theme().colors().border)
 8006                    .rounded_r_lg()
 8007                    .id("edit_prediction_diff_popover_keybind")
 8008                    .when(!has_keybind, |el| {
 8009                        let status_colors = cx.theme().status();
 8010
 8011                        el.bg(status_colors.error_background)
 8012                            .border_color(status_colors.error.opacity(0.6))
 8013                            .child(Icon::new(IconName::Info).color(Color::Error))
 8014                            .cursor_default()
 8015                            .hoverable_tooltip(move |_window, cx| {
 8016                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8017                            })
 8018                    })
 8019                    .children(keybind),
 8020            )
 8021            .into_any();
 8022
 8023        let longest_row =
 8024            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8025        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8026            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8027        } else {
 8028            layout_line(
 8029                longest_row,
 8030                editor_snapshot,
 8031                style,
 8032                editor_width,
 8033                |_| false,
 8034                window,
 8035                cx,
 8036            )
 8037            .width
 8038        };
 8039
 8040        let viewport_bounds =
 8041            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8042                right: -right_margin,
 8043                ..Default::default()
 8044            });
 8045
 8046        let x_after_longest =
 8047            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8048                - scroll_pixel_position.x;
 8049
 8050        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8051
 8052        // Fully visible if it can be displayed within the window (allow overlapping other
 8053        // panes). However, this is only allowed if the popover starts within text_bounds.
 8054        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8055            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8056
 8057        let mut origin = if can_position_to_the_right {
 8058            point(
 8059                x_after_longest,
 8060                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8061                    - scroll_pixel_position.y,
 8062            )
 8063        } else {
 8064            let cursor_row = newest_selection_head.map(|head| head.row());
 8065            let above_edit = edit_start
 8066                .row()
 8067                .0
 8068                .checked_sub(line_count as u32)
 8069                .map(DisplayRow);
 8070            let below_edit = Some(edit_end.row() + 1);
 8071            let above_cursor =
 8072                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8073            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8074
 8075            // Place the edit popover adjacent to the edit if there is a location
 8076            // available that is onscreen and does not obscure the cursor. Otherwise,
 8077            // place it adjacent to the cursor.
 8078            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8079                .into_iter()
 8080                .flatten()
 8081                .find(|&start_row| {
 8082                    let end_row = start_row + line_count as u32;
 8083                    visible_row_range.contains(&start_row)
 8084                        && visible_row_range.contains(&end_row)
 8085                        && cursor_row.map_or(true, |cursor_row| {
 8086                            !((start_row..end_row).contains(&cursor_row))
 8087                        })
 8088                })?;
 8089
 8090            content_origin
 8091                + point(
 8092                    -scroll_pixel_position.x,
 8093                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8094                )
 8095        };
 8096
 8097        origin.x -= BORDER_WIDTH;
 8098
 8099        window.defer_draw(element, origin, 1);
 8100
 8101        // Do not return an element, since it will already be drawn due to defer_draw.
 8102        None
 8103    }
 8104
 8105    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8106        px(30.)
 8107    }
 8108
 8109    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8110        if self.read_only(cx) {
 8111            cx.theme().players().read_only()
 8112        } else {
 8113            self.style.as_ref().unwrap().local_player
 8114        }
 8115    }
 8116
 8117    fn render_edit_prediction_accept_keybind(
 8118        &self,
 8119        window: &mut Window,
 8120        cx: &App,
 8121    ) -> Option<AnyElement> {
 8122        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8123        let accept_keystroke = accept_binding.keystroke()?;
 8124
 8125        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8126
 8127        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8128            Color::Accent
 8129        } else {
 8130            Color::Muted
 8131        };
 8132
 8133        h_flex()
 8134            .px_0p5()
 8135            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8136            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8137            .text_size(TextSize::XSmall.rems(cx))
 8138            .child(h_flex().children(ui::render_modifiers(
 8139                &accept_keystroke.modifiers,
 8140                PlatformStyle::platform(),
 8141                Some(modifiers_color),
 8142                Some(IconSize::XSmall.rems().into()),
 8143                true,
 8144            )))
 8145            .when(is_platform_style_mac, |parent| {
 8146                parent.child(accept_keystroke.key.clone())
 8147            })
 8148            .when(!is_platform_style_mac, |parent| {
 8149                parent.child(
 8150                    Key::new(
 8151                        util::capitalize(&accept_keystroke.key),
 8152                        Some(Color::Default),
 8153                    )
 8154                    .size(Some(IconSize::XSmall.rems().into())),
 8155                )
 8156            })
 8157            .into_any()
 8158            .into()
 8159    }
 8160
 8161    fn render_edit_prediction_line_popover(
 8162        &self,
 8163        label: impl Into<SharedString>,
 8164        icon: Option<IconName>,
 8165        window: &mut Window,
 8166        cx: &App,
 8167    ) -> Option<Stateful<Div>> {
 8168        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8169
 8170        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8171        let has_keybind = keybind.is_some();
 8172
 8173        let result = h_flex()
 8174            .id("ep-line-popover")
 8175            .py_0p5()
 8176            .pl_1()
 8177            .pr(padding_right)
 8178            .gap_1()
 8179            .rounded_md()
 8180            .border_1()
 8181            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8182            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8183            .shadow_sm()
 8184            .when(!has_keybind, |el| {
 8185                let status_colors = cx.theme().status();
 8186
 8187                el.bg(status_colors.error_background)
 8188                    .border_color(status_colors.error.opacity(0.6))
 8189                    .pl_2()
 8190                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8191                    .cursor_default()
 8192                    .hoverable_tooltip(move |_window, cx| {
 8193                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8194                    })
 8195            })
 8196            .children(keybind)
 8197            .child(
 8198                Label::new(label)
 8199                    .size(LabelSize::Small)
 8200                    .when(!has_keybind, |el| {
 8201                        el.color(cx.theme().status().error.into()).strikethrough()
 8202                    }),
 8203            )
 8204            .when(!has_keybind, |el| {
 8205                el.child(
 8206                    h_flex().ml_1().child(
 8207                        Icon::new(IconName::Info)
 8208                            .size(IconSize::Small)
 8209                            .color(cx.theme().status().error.into()),
 8210                    ),
 8211                )
 8212            })
 8213            .when_some(icon, |element, icon| {
 8214                element.child(
 8215                    div()
 8216                        .mt(px(1.5))
 8217                        .child(Icon::new(icon).size(IconSize::Small)),
 8218                )
 8219            });
 8220
 8221        Some(result)
 8222    }
 8223
 8224    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8225        let accent_color = cx.theme().colors().text_accent;
 8226        let editor_bg_color = cx.theme().colors().editor_background;
 8227        editor_bg_color.blend(accent_color.opacity(0.1))
 8228    }
 8229
 8230    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8231        let accent_color = cx.theme().colors().text_accent;
 8232        let editor_bg_color = cx.theme().colors().editor_background;
 8233        editor_bg_color.blend(accent_color.opacity(0.6))
 8234    }
 8235
 8236    fn render_edit_prediction_cursor_popover(
 8237        &self,
 8238        min_width: Pixels,
 8239        max_width: Pixels,
 8240        cursor_point: Point,
 8241        style: &EditorStyle,
 8242        accept_keystroke: Option<&gpui::Keystroke>,
 8243        _window: &Window,
 8244        cx: &mut Context<Editor>,
 8245    ) -> Option<AnyElement> {
 8246        let provider = self.edit_prediction_provider.as_ref()?;
 8247
 8248        if provider.provider.needs_terms_acceptance(cx) {
 8249            return Some(
 8250                h_flex()
 8251                    .min_w(min_width)
 8252                    .flex_1()
 8253                    .px_2()
 8254                    .py_1()
 8255                    .gap_3()
 8256                    .elevation_2(cx)
 8257                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8258                    .id("accept-terms")
 8259                    .cursor_pointer()
 8260                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8261                    .on_click(cx.listener(|this, _event, window, cx| {
 8262                        cx.stop_propagation();
 8263                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8264                        window.dispatch_action(
 8265                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8266                            cx,
 8267                        );
 8268                    }))
 8269                    .child(
 8270                        h_flex()
 8271                            .flex_1()
 8272                            .gap_2()
 8273                            .child(Icon::new(IconName::ZedPredict))
 8274                            .child(Label::new("Accept Terms of Service"))
 8275                            .child(div().w_full())
 8276                            .child(
 8277                                Icon::new(IconName::ArrowUpRight)
 8278                                    .color(Color::Muted)
 8279                                    .size(IconSize::Small),
 8280                            )
 8281                            .into_any_element(),
 8282                    )
 8283                    .into_any(),
 8284            );
 8285        }
 8286
 8287        let is_refreshing = provider.provider.is_refreshing(cx);
 8288
 8289        fn pending_completion_container() -> Div {
 8290            h_flex()
 8291                .h_full()
 8292                .flex_1()
 8293                .gap_2()
 8294                .child(Icon::new(IconName::ZedPredict))
 8295        }
 8296
 8297        let completion = match &self.active_inline_completion {
 8298            Some(prediction) => {
 8299                if !self.has_visible_completions_menu() {
 8300                    const RADIUS: Pixels = px(6.);
 8301                    const BORDER_WIDTH: Pixels = px(1.);
 8302
 8303                    return Some(
 8304                        h_flex()
 8305                            .elevation_2(cx)
 8306                            .border(BORDER_WIDTH)
 8307                            .border_color(cx.theme().colors().border)
 8308                            .when(accept_keystroke.is_none(), |el| {
 8309                                el.border_color(cx.theme().status().error)
 8310                            })
 8311                            .rounded(RADIUS)
 8312                            .rounded_tl(px(0.))
 8313                            .overflow_hidden()
 8314                            .child(div().px_1p5().child(match &prediction.completion {
 8315                                InlineCompletion::Move { target, snapshot } => {
 8316                                    use text::ToPoint as _;
 8317                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8318                                    {
 8319                                        Icon::new(IconName::ZedPredictDown)
 8320                                    } else {
 8321                                        Icon::new(IconName::ZedPredictUp)
 8322                                    }
 8323                                }
 8324                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8325                            }))
 8326                            .child(
 8327                                h_flex()
 8328                                    .gap_1()
 8329                                    .py_1()
 8330                                    .px_2()
 8331                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8332                                    .border_l_1()
 8333                                    .border_color(cx.theme().colors().border)
 8334                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8335                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8336                                        el.child(
 8337                                            Label::new("Hold")
 8338                                                .size(LabelSize::Small)
 8339                                                .when(accept_keystroke.is_none(), |el| {
 8340                                                    el.strikethrough()
 8341                                                })
 8342                                                .line_height_style(LineHeightStyle::UiLabel),
 8343                                        )
 8344                                    })
 8345                                    .id("edit_prediction_cursor_popover_keybind")
 8346                                    .when(accept_keystroke.is_none(), |el| {
 8347                                        let status_colors = cx.theme().status();
 8348
 8349                                        el.bg(status_colors.error_background)
 8350                                            .border_color(status_colors.error.opacity(0.6))
 8351                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8352                                            .cursor_default()
 8353                                            .hoverable_tooltip(move |_window, cx| {
 8354                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8355                                                    .into()
 8356                                            })
 8357                                    })
 8358                                    .when_some(
 8359                                        accept_keystroke.as_ref(),
 8360                                        |el, accept_keystroke| {
 8361                                            el.child(h_flex().children(ui::render_modifiers(
 8362                                                &accept_keystroke.modifiers,
 8363                                                PlatformStyle::platform(),
 8364                                                Some(Color::Default),
 8365                                                Some(IconSize::XSmall.rems().into()),
 8366                                                false,
 8367                                            )))
 8368                                        },
 8369                                    ),
 8370                            )
 8371                            .into_any(),
 8372                    );
 8373                }
 8374
 8375                self.render_edit_prediction_cursor_popover_preview(
 8376                    prediction,
 8377                    cursor_point,
 8378                    style,
 8379                    cx,
 8380                )?
 8381            }
 8382
 8383            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8384                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8385                    stale_completion,
 8386                    cursor_point,
 8387                    style,
 8388                    cx,
 8389                )?,
 8390
 8391                None => {
 8392                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8393                }
 8394            },
 8395
 8396            None => pending_completion_container().child(Label::new("No Prediction")),
 8397        };
 8398
 8399        let completion = if is_refreshing {
 8400            completion
 8401                .with_animation(
 8402                    "loading-completion",
 8403                    Animation::new(Duration::from_secs(2))
 8404                        .repeat()
 8405                        .with_easing(pulsating_between(0.4, 0.8)),
 8406                    |label, delta| label.opacity(delta),
 8407                )
 8408                .into_any_element()
 8409        } else {
 8410            completion.into_any_element()
 8411        };
 8412
 8413        let has_completion = self.active_inline_completion.is_some();
 8414
 8415        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8416        Some(
 8417            h_flex()
 8418                .min_w(min_width)
 8419                .max_w(max_width)
 8420                .flex_1()
 8421                .elevation_2(cx)
 8422                .border_color(cx.theme().colors().border)
 8423                .child(
 8424                    div()
 8425                        .flex_1()
 8426                        .py_1()
 8427                        .px_2()
 8428                        .overflow_hidden()
 8429                        .child(completion),
 8430                )
 8431                .when_some(accept_keystroke, |el, accept_keystroke| {
 8432                    if !accept_keystroke.modifiers.modified() {
 8433                        return el;
 8434                    }
 8435
 8436                    el.child(
 8437                        h_flex()
 8438                            .h_full()
 8439                            .border_l_1()
 8440                            .rounded_r_lg()
 8441                            .border_color(cx.theme().colors().border)
 8442                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8443                            .gap_1()
 8444                            .py_1()
 8445                            .px_2()
 8446                            .child(
 8447                                h_flex()
 8448                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8449                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8450                                    .child(h_flex().children(ui::render_modifiers(
 8451                                        &accept_keystroke.modifiers,
 8452                                        PlatformStyle::platform(),
 8453                                        Some(if !has_completion {
 8454                                            Color::Muted
 8455                                        } else {
 8456                                            Color::Default
 8457                                        }),
 8458                                        None,
 8459                                        false,
 8460                                    ))),
 8461                            )
 8462                            .child(Label::new("Preview").into_any_element())
 8463                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8464                    )
 8465                })
 8466                .into_any(),
 8467        )
 8468    }
 8469
 8470    fn render_edit_prediction_cursor_popover_preview(
 8471        &self,
 8472        completion: &InlineCompletionState,
 8473        cursor_point: Point,
 8474        style: &EditorStyle,
 8475        cx: &mut Context<Editor>,
 8476    ) -> Option<Div> {
 8477        use text::ToPoint as _;
 8478
 8479        fn render_relative_row_jump(
 8480            prefix: impl Into<String>,
 8481            current_row: u32,
 8482            target_row: u32,
 8483        ) -> Div {
 8484            let (row_diff, arrow) = if target_row < current_row {
 8485                (current_row - target_row, IconName::ArrowUp)
 8486            } else {
 8487                (target_row - current_row, IconName::ArrowDown)
 8488            };
 8489
 8490            h_flex()
 8491                .child(
 8492                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8493                        .color(Color::Muted)
 8494                        .size(LabelSize::Small),
 8495                )
 8496                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8497        }
 8498
 8499        match &completion.completion {
 8500            InlineCompletion::Move {
 8501                target, snapshot, ..
 8502            } => Some(
 8503                h_flex()
 8504                    .px_2()
 8505                    .gap_2()
 8506                    .flex_1()
 8507                    .child(
 8508                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8509                            Icon::new(IconName::ZedPredictDown)
 8510                        } else {
 8511                            Icon::new(IconName::ZedPredictUp)
 8512                        },
 8513                    )
 8514                    .child(Label::new("Jump to Edit")),
 8515            ),
 8516
 8517            InlineCompletion::Edit {
 8518                edits,
 8519                edit_preview,
 8520                snapshot,
 8521                display_mode: _,
 8522            } => {
 8523                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8524
 8525                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8526                    &snapshot,
 8527                    &edits,
 8528                    edit_preview.as_ref()?,
 8529                    true,
 8530                    cx,
 8531                )
 8532                .first_line_preview();
 8533
 8534                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8535                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8536
 8537                let preview = h_flex()
 8538                    .gap_1()
 8539                    .min_w_16()
 8540                    .child(styled_text)
 8541                    .when(has_more_lines, |parent| parent.child(""));
 8542
 8543                let left = if first_edit_row != cursor_point.row {
 8544                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8545                        .into_any_element()
 8546                } else {
 8547                    Icon::new(IconName::ZedPredict).into_any_element()
 8548                };
 8549
 8550                Some(
 8551                    h_flex()
 8552                        .h_full()
 8553                        .flex_1()
 8554                        .gap_2()
 8555                        .pr_1()
 8556                        .overflow_x_hidden()
 8557                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8558                        .child(left)
 8559                        .child(preview),
 8560                )
 8561            }
 8562        }
 8563    }
 8564
 8565    pub fn render_context_menu(
 8566        &self,
 8567        style: &EditorStyle,
 8568        max_height_in_lines: u32,
 8569        window: &mut Window,
 8570        cx: &mut Context<Editor>,
 8571    ) -> Option<AnyElement> {
 8572        let menu = self.context_menu.borrow();
 8573        let menu = menu.as_ref()?;
 8574        if !menu.visible() {
 8575            return None;
 8576        };
 8577        Some(menu.render(style, max_height_in_lines, window, cx))
 8578    }
 8579
 8580    fn render_context_menu_aside(
 8581        &mut self,
 8582        max_size: Size<Pixels>,
 8583        window: &mut Window,
 8584        cx: &mut Context<Editor>,
 8585    ) -> Option<AnyElement> {
 8586        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8587            if menu.visible() {
 8588                menu.render_aside(self, max_size, window, cx)
 8589            } else {
 8590                None
 8591            }
 8592        })
 8593    }
 8594
 8595    fn hide_context_menu(
 8596        &mut self,
 8597        window: &mut Window,
 8598        cx: &mut Context<Self>,
 8599    ) -> Option<CodeContextMenu> {
 8600        cx.notify();
 8601        self.completion_tasks.clear();
 8602        let context_menu = self.context_menu.borrow_mut().take();
 8603        self.stale_inline_completion_in_menu.take();
 8604        self.update_visible_inline_completion(window, cx);
 8605        context_menu
 8606    }
 8607
 8608    fn show_snippet_choices(
 8609        &mut self,
 8610        choices: &Vec<String>,
 8611        selection: Range<Anchor>,
 8612        cx: &mut Context<Self>,
 8613    ) {
 8614        if selection.start.buffer_id.is_none() {
 8615            return;
 8616        }
 8617        let buffer_id = selection.start.buffer_id.unwrap();
 8618        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8619        let id = post_inc(&mut self.next_completion_id);
 8620        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8621
 8622        if let Some(buffer) = buffer {
 8623            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8624                CompletionsMenu::new_snippet_choices(
 8625                    id,
 8626                    true,
 8627                    choices,
 8628                    selection,
 8629                    buffer,
 8630                    snippet_sort_order,
 8631                ),
 8632            ));
 8633        }
 8634    }
 8635
 8636    pub fn insert_snippet(
 8637        &mut self,
 8638        insertion_ranges: &[Range<usize>],
 8639        snippet: Snippet,
 8640        window: &mut Window,
 8641        cx: &mut Context<Self>,
 8642    ) -> Result<()> {
 8643        struct Tabstop<T> {
 8644            is_end_tabstop: bool,
 8645            ranges: Vec<Range<T>>,
 8646            choices: Option<Vec<String>>,
 8647        }
 8648
 8649        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8650            let snippet_text: Arc<str> = snippet.text.clone().into();
 8651            let edits = insertion_ranges
 8652                .iter()
 8653                .cloned()
 8654                .map(|range| (range, snippet_text.clone()));
 8655            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8656
 8657            let snapshot = &*buffer.read(cx);
 8658            let snippet = &snippet;
 8659            snippet
 8660                .tabstops
 8661                .iter()
 8662                .map(|tabstop| {
 8663                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8664                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8665                    });
 8666                    let mut tabstop_ranges = tabstop
 8667                        .ranges
 8668                        .iter()
 8669                        .flat_map(|tabstop_range| {
 8670                            let mut delta = 0_isize;
 8671                            insertion_ranges.iter().map(move |insertion_range| {
 8672                                let insertion_start = insertion_range.start as isize + delta;
 8673                                delta +=
 8674                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8675
 8676                                let start = ((insertion_start + tabstop_range.start) as usize)
 8677                                    .min(snapshot.len());
 8678                                let end = ((insertion_start + tabstop_range.end) as usize)
 8679                                    .min(snapshot.len());
 8680                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8681                            })
 8682                        })
 8683                        .collect::<Vec<_>>();
 8684                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8685
 8686                    Tabstop {
 8687                        is_end_tabstop,
 8688                        ranges: tabstop_ranges,
 8689                        choices: tabstop.choices.clone(),
 8690                    }
 8691                })
 8692                .collect::<Vec<_>>()
 8693        });
 8694        if let Some(tabstop) = tabstops.first() {
 8695            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8696                s.select_ranges(tabstop.ranges.iter().cloned());
 8697            });
 8698
 8699            if let Some(choices) = &tabstop.choices {
 8700                if let Some(selection) = tabstop.ranges.first() {
 8701                    self.show_snippet_choices(choices, selection.clone(), cx)
 8702                }
 8703            }
 8704
 8705            // If we're already at the last tabstop and it's at the end of the snippet,
 8706            // we're done, we don't need to keep the state around.
 8707            if !tabstop.is_end_tabstop {
 8708                let choices = tabstops
 8709                    .iter()
 8710                    .map(|tabstop| tabstop.choices.clone())
 8711                    .collect();
 8712
 8713                let ranges = tabstops
 8714                    .into_iter()
 8715                    .map(|tabstop| tabstop.ranges)
 8716                    .collect::<Vec<_>>();
 8717
 8718                self.snippet_stack.push(SnippetState {
 8719                    active_index: 0,
 8720                    ranges,
 8721                    choices,
 8722                });
 8723            }
 8724
 8725            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8726            if self.autoclose_regions.is_empty() {
 8727                let snapshot = self.buffer.read(cx).snapshot(cx);
 8728                for selection in &mut self.selections.all::<Point>(cx) {
 8729                    let selection_head = selection.head();
 8730                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8731                        continue;
 8732                    };
 8733
 8734                    let mut bracket_pair = None;
 8735                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8736                    let prev_chars = snapshot
 8737                        .reversed_chars_at(selection_head)
 8738                        .collect::<String>();
 8739                    for (pair, enabled) in scope.brackets() {
 8740                        if enabled
 8741                            && pair.close
 8742                            && prev_chars.starts_with(pair.start.as_str())
 8743                            && next_chars.starts_with(pair.end.as_str())
 8744                        {
 8745                            bracket_pair = Some(pair.clone());
 8746                            break;
 8747                        }
 8748                    }
 8749                    if let Some(pair) = bracket_pair {
 8750                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8751                        let autoclose_enabled =
 8752                            self.use_autoclose && snapshot_settings.use_autoclose;
 8753                        if autoclose_enabled {
 8754                            let start = snapshot.anchor_after(selection_head);
 8755                            let end = snapshot.anchor_after(selection_head);
 8756                            self.autoclose_regions.push(AutocloseRegion {
 8757                                selection_id: selection.id,
 8758                                range: start..end,
 8759                                pair,
 8760                            });
 8761                        }
 8762                    }
 8763                }
 8764            }
 8765        }
 8766        Ok(())
 8767    }
 8768
 8769    pub fn move_to_next_snippet_tabstop(
 8770        &mut self,
 8771        window: &mut Window,
 8772        cx: &mut Context<Self>,
 8773    ) -> bool {
 8774        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8775    }
 8776
 8777    pub fn move_to_prev_snippet_tabstop(
 8778        &mut self,
 8779        window: &mut Window,
 8780        cx: &mut Context<Self>,
 8781    ) -> bool {
 8782        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8783    }
 8784
 8785    pub fn move_to_snippet_tabstop(
 8786        &mut self,
 8787        bias: Bias,
 8788        window: &mut Window,
 8789        cx: &mut Context<Self>,
 8790    ) -> bool {
 8791        if let Some(mut snippet) = self.snippet_stack.pop() {
 8792            match bias {
 8793                Bias::Left => {
 8794                    if snippet.active_index > 0 {
 8795                        snippet.active_index -= 1;
 8796                    } else {
 8797                        self.snippet_stack.push(snippet);
 8798                        return false;
 8799                    }
 8800                }
 8801                Bias::Right => {
 8802                    if snippet.active_index + 1 < snippet.ranges.len() {
 8803                        snippet.active_index += 1;
 8804                    } else {
 8805                        self.snippet_stack.push(snippet);
 8806                        return false;
 8807                    }
 8808                }
 8809            }
 8810            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8811                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8812                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8813                });
 8814
 8815                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8816                    if let Some(selection) = current_ranges.first() {
 8817                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8818                    }
 8819                }
 8820
 8821                // If snippet state is not at the last tabstop, push it back on the stack
 8822                if snippet.active_index + 1 < snippet.ranges.len() {
 8823                    self.snippet_stack.push(snippet);
 8824                }
 8825                return true;
 8826            }
 8827        }
 8828
 8829        false
 8830    }
 8831
 8832    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8833        self.transact(window, cx, |this, window, cx| {
 8834            this.select_all(&SelectAll, window, cx);
 8835            this.insert("", window, cx);
 8836        });
 8837    }
 8838
 8839    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8840        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8841        self.transact(window, cx, |this, window, cx| {
 8842            this.select_autoclose_pair(window, cx);
 8843            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8844            if !this.linked_edit_ranges.is_empty() {
 8845                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8846                let snapshot = this.buffer.read(cx).snapshot(cx);
 8847
 8848                for selection in selections.iter() {
 8849                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8850                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8851                    if selection_start.buffer_id != selection_end.buffer_id {
 8852                        continue;
 8853                    }
 8854                    if let Some(ranges) =
 8855                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8856                    {
 8857                        for (buffer, entries) in ranges {
 8858                            linked_ranges.entry(buffer).or_default().extend(entries);
 8859                        }
 8860                    }
 8861                }
 8862            }
 8863
 8864            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8865            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8866            for selection in &mut selections {
 8867                if selection.is_empty() {
 8868                    let old_head = selection.head();
 8869                    let mut new_head =
 8870                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8871                            .to_point(&display_map);
 8872                    if let Some((buffer, line_buffer_range)) = display_map
 8873                        .buffer_snapshot
 8874                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8875                    {
 8876                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8877                        let indent_len = match indent_size.kind {
 8878                            IndentKind::Space => {
 8879                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8880                            }
 8881                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8882                        };
 8883                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8884                            let indent_len = indent_len.get();
 8885                            new_head = cmp::min(
 8886                                new_head,
 8887                                MultiBufferPoint::new(
 8888                                    old_head.row,
 8889                                    ((old_head.column - 1) / indent_len) * indent_len,
 8890                                ),
 8891                            );
 8892                        }
 8893                    }
 8894
 8895                    selection.set_head(new_head, SelectionGoal::None);
 8896                }
 8897            }
 8898
 8899            this.signature_help_state.set_backspace_pressed(true);
 8900            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8901                s.select(selections)
 8902            });
 8903            this.insert("", window, cx);
 8904            let empty_str: Arc<str> = Arc::from("");
 8905            for (buffer, edits) in linked_ranges {
 8906                let snapshot = buffer.read(cx).snapshot();
 8907                use text::ToPoint as TP;
 8908
 8909                let edits = edits
 8910                    .into_iter()
 8911                    .map(|range| {
 8912                        let end_point = TP::to_point(&range.end, &snapshot);
 8913                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8914
 8915                        if end_point == start_point {
 8916                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8917                                .saturating_sub(1);
 8918                            start_point =
 8919                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8920                        };
 8921
 8922                        (start_point..end_point, empty_str.clone())
 8923                    })
 8924                    .sorted_by_key(|(range, _)| range.start)
 8925                    .collect::<Vec<_>>();
 8926                buffer.update(cx, |this, cx| {
 8927                    this.edit(edits, None, cx);
 8928                })
 8929            }
 8930            this.refresh_inline_completion(true, false, window, cx);
 8931            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8932        });
 8933    }
 8934
 8935    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8936        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8937        self.transact(window, cx, |this, window, cx| {
 8938            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8939                s.move_with(|map, selection| {
 8940                    if selection.is_empty() {
 8941                        let cursor = movement::right(map, selection.head());
 8942                        selection.end = cursor;
 8943                        selection.reversed = true;
 8944                        selection.goal = SelectionGoal::None;
 8945                    }
 8946                })
 8947            });
 8948            this.insert("", window, cx);
 8949            this.refresh_inline_completion(true, false, window, cx);
 8950        });
 8951    }
 8952
 8953    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8954        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8955        if self.move_to_prev_snippet_tabstop(window, cx) {
 8956            return;
 8957        }
 8958        self.outdent(&Outdent, window, cx);
 8959    }
 8960
 8961    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8962        if self.move_to_next_snippet_tabstop(window, cx) {
 8963            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8964            return;
 8965        }
 8966        if self.read_only(cx) {
 8967            return;
 8968        }
 8969        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8970        let mut selections = self.selections.all_adjusted(cx);
 8971        let buffer = self.buffer.read(cx);
 8972        let snapshot = buffer.snapshot(cx);
 8973        let rows_iter = selections.iter().map(|s| s.head().row);
 8974        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8975
 8976        let has_some_cursor_in_whitespace = selections
 8977            .iter()
 8978            .filter(|selection| selection.is_empty())
 8979            .any(|selection| {
 8980                let cursor = selection.head();
 8981                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8982                cursor.column < current_indent.len
 8983            });
 8984
 8985        let mut edits = Vec::new();
 8986        let mut prev_edited_row = 0;
 8987        let mut row_delta = 0;
 8988        for selection in &mut selections {
 8989            if selection.start.row != prev_edited_row {
 8990                row_delta = 0;
 8991            }
 8992            prev_edited_row = selection.end.row;
 8993
 8994            // If the selection is non-empty, then increase the indentation of the selected lines.
 8995            if !selection.is_empty() {
 8996                row_delta =
 8997                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8998                continue;
 8999            }
 9000
 9001            let cursor = selection.head();
 9002            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9003            if let Some(suggested_indent) =
 9004                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9005            {
 9006                // Don't do anything if already at suggested indent
 9007                // and there is any other cursor which is not
 9008                if has_some_cursor_in_whitespace
 9009                    && cursor.column == current_indent.len
 9010                    && current_indent.len == suggested_indent.len
 9011                {
 9012                    continue;
 9013                }
 9014
 9015                // Adjust line and move cursor to suggested indent
 9016                // if cursor is not at suggested indent
 9017                if cursor.column < suggested_indent.len
 9018                    && cursor.column <= current_indent.len
 9019                    && current_indent.len <= suggested_indent.len
 9020                {
 9021                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9022                    selection.end = selection.start;
 9023                    if row_delta == 0 {
 9024                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9025                            cursor.row,
 9026                            current_indent,
 9027                            suggested_indent,
 9028                        ));
 9029                        row_delta = suggested_indent.len - current_indent.len;
 9030                    }
 9031                    continue;
 9032                }
 9033
 9034                // If current indent is more than suggested indent
 9035                // only move cursor to current indent and skip indent
 9036                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9037                    selection.start = Point::new(cursor.row, current_indent.len);
 9038                    selection.end = selection.start;
 9039                    continue;
 9040                }
 9041            }
 9042
 9043            // Otherwise, insert a hard or soft tab.
 9044            let settings = buffer.language_settings_at(cursor, cx);
 9045            let tab_size = if settings.hard_tabs {
 9046                IndentSize::tab()
 9047            } else {
 9048                let tab_size = settings.tab_size.get();
 9049                let indent_remainder = snapshot
 9050                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9051                    .flat_map(str::chars)
 9052                    .fold(row_delta % tab_size, |counter: u32, c| {
 9053                        if c == '\t' {
 9054                            0
 9055                        } else {
 9056                            (counter + 1) % tab_size
 9057                        }
 9058                    });
 9059
 9060                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9061                IndentSize::spaces(chars_to_next_tab_stop)
 9062            };
 9063            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9064            selection.end = selection.start;
 9065            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9066            row_delta += tab_size.len;
 9067        }
 9068
 9069        self.transact(window, cx, |this, window, cx| {
 9070            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9071            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9072                s.select(selections)
 9073            });
 9074            this.refresh_inline_completion(true, false, window, cx);
 9075        });
 9076    }
 9077
 9078    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9079        if self.read_only(cx) {
 9080            return;
 9081        }
 9082        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9083        let mut selections = self.selections.all::<Point>(cx);
 9084        let mut prev_edited_row = 0;
 9085        let mut row_delta = 0;
 9086        let mut edits = Vec::new();
 9087        let buffer = self.buffer.read(cx);
 9088        let snapshot = buffer.snapshot(cx);
 9089        for selection in &mut selections {
 9090            if selection.start.row != prev_edited_row {
 9091                row_delta = 0;
 9092            }
 9093            prev_edited_row = selection.end.row;
 9094
 9095            row_delta =
 9096                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9097        }
 9098
 9099        self.transact(window, cx, |this, window, cx| {
 9100            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9101            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9102                s.select(selections)
 9103            });
 9104        });
 9105    }
 9106
 9107    fn indent_selection(
 9108        buffer: &MultiBuffer,
 9109        snapshot: &MultiBufferSnapshot,
 9110        selection: &mut Selection<Point>,
 9111        edits: &mut Vec<(Range<Point>, String)>,
 9112        delta_for_start_row: u32,
 9113        cx: &App,
 9114    ) -> u32 {
 9115        let settings = buffer.language_settings_at(selection.start, cx);
 9116        let tab_size = settings.tab_size.get();
 9117        let indent_kind = if settings.hard_tabs {
 9118            IndentKind::Tab
 9119        } else {
 9120            IndentKind::Space
 9121        };
 9122        let mut start_row = selection.start.row;
 9123        let mut end_row = selection.end.row + 1;
 9124
 9125        // If a selection ends at the beginning of a line, don't indent
 9126        // that last line.
 9127        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9128            end_row -= 1;
 9129        }
 9130
 9131        // Avoid re-indenting a row that has already been indented by a
 9132        // previous selection, but still update this selection's column
 9133        // to reflect that indentation.
 9134        if delta_for_start_row > 0 {
 9135            start_row += 1;
 9136            selection.start.column += delta_for_start_row;
 9137            if selection.end.row == selection.start.row {
 9138                selection.end.column += delta_for_start_row;
 9139            }
 9140        }
 9141
 9142        let mut delta_for_end_row = 0;
 9143        let has_multiple_rows = start_row + 1 != end_row;
 9144        for row in start_row..end_row {
 9145            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9146            let indent_delta = match (current_indent.kind, indent_kind) {
 9147                (IndentKind::Space, IndentKind::Space) => {
 9148                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9149                    IndentSize::spaces(columns_to_next_tab_stop)
 9150                }
 9151                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9152                (_, IndentKind::Tab) => IndentSize::tab(),
 9153            };
 9154
 9155            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9156                0
 9157            } else {
 9158                selection.start.column
 9159            };
 9160            let row_start = Point::new(row, start);
 9161            edits.push((
 9162                row_start..row_start,
 9163                indent_delta.chars().collect::<String>(),
 9164            ));
 9165
 9166            // Update this selection's endpoints to reflect the indentation.
 9167            if row == selection.start.row {
 9168                selection.start.column += indent_delta.len;
 9169            }
 9170            if row == selection.end.row {
 9171                selection.end.column += indent_delta.len;
 9172                delta_for_end_row = indent_delta.len;
 9173            }
 9174        }
 9175
 9176        if selection.start.row == selection.end.row {
 9177            delta_for_start_row + delta_for_end_row
 9178        } else {
 9179            delta_for_end_row
 9180        }
 9181    }
 9182
 9183    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9184        if self.read_only(cx) {
 9185            return;
 9186        }
 9187        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9189        let selections = self.selections.all::<Point>(cx);
 9190        let mut deletion_ranges = Vec::new();
 9191        let mut last_outdent = None;
 9192        {
 9193            let buffer = self.buffer.read(cx);
 9194            let snapshot = buffer.snapshot(cx);
 9195            for selection in &selections {
 9196                let settings = buffer.language_settings_at(selection.start, cx);
 9197                let tab_size = settings.tab_size.get();
 9198                let mut rows = selection.spanned_rows(false, &display_map);
 9199
 9200                // Avoid re-outdenting a row that has already been outdented by a
 9201                // previous selection.
 9202                if let Some(last_row) = last_outdent {
 9203                    if last_row == rows.start {
 9204                        rows.start = rows.start.next_row();
 9205                    }
 9206                }
 9207                let has_multiple_rows = rows.len() > 1;
 9208                for row in rows.iter_rows() {
 9209                    let indent_size = snapshot.indent_size_for_line(row);
 9210                    if indent_size.len > 0 {
 9211                        let deletion_len = match indent_size.kind {
 9212                            IndentKind::Space => {
 9213                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9214                                if columns_to_prev_tab_stop == 0 {
 9215                                    tab_size
 9216                                } else {
 9217                                    columns_to_prev_tab_stop
 9218                                }
 9219                            }
 9220                            IndentKind::Tab => 1,
 9221                        };
 9222                        let start = if has_multiple_rows
 9223                            || deletion_len > selection.start.column
 9224                            || indent_size.len < selection.start.column
 9225                        {
 9226                            0
 9227                        } else {
 9228                            selection.start.column - deletion_len
 9229                        };
 9230                        deletion_ranges.push(
 9231                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9232                        );
 9233                        last_outdent = Some(row);
 9234                    }
 9235                }
 9236            }
 9237        }
 9238
 9239        self.transact(window, cx, |this, window, cx| {
 9240            this.buffer.update(cx, |buffer, cx| {
 9241                let empty_str: Arc<str> = Arc::default();
 9242                buffer.edit(
 9243                    deletion_ranges
 9244                        .into_iter()
 9245                        .map(|range| (range, empty_str.clone())),
 9246                    None,
 9247                    cx,
 9248                );
 9249            });
 9250            let selections = this.selections.all::<usize>(cx);
 9251            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9252                s.select(selections)
 9253            });
 9254        });
 9255    }
 9256
 9257    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9258        if self.read_only(cx) {
 9259            return;
 9260        }
 9261        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9262        let selections = self
 9263            .selections
 9264            .all::<usize>(cx)
 9265            .into_iter()
 9266            .map(|s| s.range());
 9267
 9268        self.transact(window, cx, |this, window, cx| {
 9269            this.buffer.update(cx, |buffer, cx| {
 9270                buffer.autoindent_ranges(selections, cx);
 9271            });
 9272            let selections = this.selections.all::<usize>(cx);
 9273            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9274                s.select(selections)
 9275            });
 9276        });
 9277    }
 9278
 9279    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9280        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9281        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9282        let selections = self.selections.all::<Point>(cx);
 9283
 9284        let mut new_cursors = Vec::new();
 9285        let mut edit_ranges = Vec::new();
 9286        let mut selections = selections.iter().peekable();
 9287        while let Some(selection) = selections.next() {
 9288            let mut rows = selection.spanned_rows(false, &display_map);
 9289            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9290
 9291            // Accumulate contiguous regions of rows that we want to delete.
 9292            while let Some(next_selection) = selections.peek() {
 9293                let next_rows = next_selection.spanned_rows(false, &display_map);
 9294                if next_rows.start <= rows.end {
 9295                    rows.end = next_rows.end;
 9296                    selections.next().unwrap();
 9297                } else {
 9298                    break;
 9299                }
 9300            }
 9301
 9302            let buffer = &display_map.buffer_snapshot;
 9303            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9304            let edit_end;
 9305            let cursor_buffer_row;
 9306            if buffer.max_point().row >= rows.end.0 {
 9307                // If there's a line after the range, delete the \n from the end of the row range
 9308                // and position the cursor on the next line.
 9309                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9310                cursor_buffer_row = rows.end;
 9311            } else {
 9312                // If there isn't a line after the range, delete the \n from the line before the
 9313                // start of the row range and position the cursor there.
 9314                edit_start = edit_start.saturating_sub(1);
 9315                edit_end = buffer.len();
 9316                cursor_buffer_row = rows.start.previous_row();
 9317            }
 9318
 9319            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9320            *cursor.column_mut() =
 9321                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9322
 9323            new_cursors.push((
 9324                selection.id,
 9325                buffer.anchor_after(cursor.to_point(&display_map)),
 9326            ));
 9327            edit_ranges.push(edit_start..edit_end);
 9328        }
 9329
 9330        self.transact(window, cx, |this, window, cx| {
 9331            let buffer = this.buffer.update(cx, |buffer, cx| {
 9332                let empty_str: Arc<str> = Arc::default();
 9333                buffer.edit(
 9334                    edit_ranges
 9335                        .into_iter()
 9336                        .map(|range| (range, empty_str.clone())),
 9337                    None,
 9338                    cx,
 9339                );
 9340                buffer.snapshot(cx)
 9341            });
 9342            let new_selections = new_cursors
 9343                .into_iter()
 9344                .map(|(id, cursor)| {
 9345                    let cursor = cursor.to_point(&buffer);
 9346                    Selection {
 9347                        id,
 9348                        start: cursor,
 9349                        end: cursor,
 9350                        reversed: false,
 9351                        goal: SelectionGoal::None,
 9352                    }
 9353                })
 9354                .collect();
 9355
 9356            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9357                s.select(new_selections);
 9358            });
 9359        });
 9360    }
 9361
 9362    pub fn join_lines_impl(
 9363        &mut self,
 9364        insert_whitespace: bool,
 9365        window: &mut Window,
 9366        cx: &mut Context<Self>,
 9367    ) {
 9368        if self.read_only(cx) {
 9369            return;
 9370        }
 9371        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9372        for selection in self.selections.all::<Point>(cx) {
 9373            let start = MultiBufferRow(selection.start.row);
 9374            // Treat single line selections as if they include the next line. Otherwise this action
 9375            // would do nothing for single line selections individual cursors.
 9376            let end = if selection.start.row == selection.end.row {
 9377                MultiBufferRow(selection.start.row + 1)
 9378            } else {
 9379                MultiBufferRow(selection.end.row)
 9380            };
 9381
 9382            if let Some(last_row_range) = row_ranges.last_mut() {
 9383                if start <= last_row_range.end {
 9384                    last_row_range.end = end;
 9385                    continue;
 9386                }
 9387            }
 9388            row_ranges.push(start..end);
 9389        }
 9390
 9391        let snapshot = self.buffer.read(cx).snapshot(cx);
 9392        let mut cursor_positions = Vec::new();
 9393        for row_range in &row_ranges {
 9394            let anchor = snapshot.anchor_before(Point::new(
 9395                row_range.end.previous_row().0,
 9396                snapshot.line_len(row_range.end.previous_row()),
 9397            ));
 9398            cursor_positions.push(anchor..anchor);
 9399        }
 9400
 9401        self.transact(window, cx, |this, window, cx| {
 9402            for row_range in row_ranges.into_iter().rev() {
 9403                for row in row_range.iter_rows().rev() {
 9404                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9405                    let next_line_row = row.next_row();
 9406                    let indent = snapshot.indent_size_for_line(next_line_row);
 9407                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9408
 9409                    let replace =
 9410                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9411                            " "
 9412                        } else {
 9413                            ""
 9414                        };
 9415
 9416                    this.buffer.update(cx, |buffer, cx| {
 9417                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9418                    });
 9419                }
 9420            }
 9421
 9422            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9423                s.select_anchor_ranges(cursor_positions)
 9424            });
 9425        });
 9426    }
 9427
 9428    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9429        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9430        self.join_lines_impl(true, window, cx);
 9431    }
 9432
 9433    pub fn sort_lines_case_sensitive(
 9434        &mut self,
 9435        _: &SortLinesCaseSensitive,
 9436        window: &mut Window,
 9437        cx: &mut Context<Self>,
 9438    ) {
 9439        self.manipulate_lines(window, cx, |lines| lines.sort())
 9440    }
 9441
 9442    pub fn sort_lines_case_insensitive(
 9443        &mut self,
 9444        _: &SortLinesCaseInsensitive,
 9445        window: &mut Window,
 9446        cx: &mut Context<Self>,
 9447    ) {
 9448        self.manipulate_lines(window, cx, |lines| {
 9449            lines.sort_by_key(|line| line.to_lowercase())
 9450        })
 9451    }
 9452
 9453    pub fn unique_lines_case_insensitive(
 9454        &mut self,
 9455        _: &UniqueLinesCaseInsensitive,
 9456        window: &mut Window,
 9457        cx: &mut Context<Self>,
 9458    ) {
 9459        self.manipulate_lines(window, cx, |lines| {
 9460            let mut seen = HashSet::default();
 9461            lines.retain(|line| seen.insert(line.to_lowercase()));
 9462        })
 9463    }
 9464
 9465    pub fn unique_lines_case_sensitive(
 9466        &mut self,
 9467        _: &UniqueLinesCaseSensitive,
 9468        window: &mut Window,
 9469        cx: &mut Context<Self>,
 9470    ) {
 9471        self.manipulate_lines(window, cx, |lines| {
 9472            let mut seen = HashSet::default();
 9473            lines.retain(|line| seen.insert(*line));
 9474        })
 9475    }
 9476
 9477    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9478        let Some(project) = self.project.clone() else {
 9479            return;
 9480        };
 9481        self.reload(project, window, cx)
 9482            .detach_and_notify_err(window, cx);
 9483    }
 9484
 9485    pub fn restore_file(
 9486        &mut self,
 9487        _: &::git::RestoreFile,
 9488        window: &mut Window,
 9489        cx: &mut Context<Self>,
 9490    ) {
 9491        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9492        let mut buffer_ids = HashSet::default();
 9493        let snapshot = self.buffer().read(cx).snapshot(cx);
 9494        for selection in self.selections.all::<usize>(cx) {
 9495            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9496        }
 9497
 9498        let buffer = self.buffer().read(cx);
 9499        let ranges = buffer_ids
 9500            .into_iter()
 9501            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9502            .collect::<Vec<_>>();
 9503
 9504        self.restore_hunks_in_ranges(ranges, window, cx);
 9505    }
 9506
 9507    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9508        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9509        let selections = self
 9510            .selections
 9511            .all(cx)
 9512            .into_iter()
 9513            .map(|s| s.range())
 9514            .collect();
 9515        self.restore_hunks_in_ranges(selections, window, cx);
 9516    }
 9517
 9518    pub fn restore_hunks_in_ranges(
 9519        &mut self,
 9520        ranges: Vec<Range<Point>>,
 9521        window: &mut Window,
 9522        cx: &mut Context<Editor>,
 9523    ) {
 9524        let mut revert_changes = HashMap::default();
 9525        let chunk_by = self
 9526            .snapshot(window, cx)
 9527            .hunks_for_ranges(ranges)
 9528            .into_iter()
 9529            .chunk_by(|hunk| hunk.buffer_id);
 9530        for (buffer_id, hunks) in &chunk_by {
 9531            let hunks = hunks.collect::<Vec<_>>();
 9532            for hunk in &hunks {
 9533                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9534            }
 9535            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9536        }
 9537        drop(chunk_by);
 9538        if !revert_changes.is_empty() {
 9539            self.transact(window, cx, |editor, window, cx| {
 9540                editor.restore(revert_changes, window, cx);
 9541            });
 9542        }
 9543    }
 9544
 9545    pub fn open_active_item_in_terminal(
 9546        &mut self,
 9547        _: &OpenInTerminal,
 9548        window: &mut Window,
 9549        cx: &mut Context<Self>,
 9550    ) {
 9551        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9552            let project_path = buffer.read(cx).project_path(cx)?;
 9553            let project = self.project.as_ref()?.read(cx);
 9554            let entry = project.entry_for_path(&project_path, cx)?;
 9555            let parent = match &entry.canonical_path {
 9556                Some(canonical_path) => canonical_path.to_path_buf(),
 9557                None => project.absolute_path(&project_path, cx)?,
 9558            }
 9559            .parent()?
 9560            .to_path_buf();
 9561            Some(parent)
 9562        }) {
 9563            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9564        }
 9565    }
 9566
 9567    fn set_breakpoint_context_menu(
 9568        &mut self,
 9569        display_row: DisplayRow,
 9570        position: Option<Anchor>,
 9571        clicked_point: gpui::Point<Pixels>,
 9572        window: &mut Window,
 9573        cx: &mut Context<Self>,
 9574    ) {
 9575        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9576            return;
 9577        }
 9578        let source = self
 9579            .buffer
 9580            .read(cx)
 9581            .snapshot(cx)
 9582            .anchor_before(Point::new(display_row.0, 0u32));
 9583
 9584        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9585
 9586        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9587            self,
 9588            source,
 9589            clicked_point,
 9590            context_menu,
 9591            window,
 9592            cx,
 9593        );
 9594    }
 9595
 9596    fn add_edit_breakpoint_block(
 9597        &mut self,
 9598        anchor: Anchor,
 9599        breakpoint: &Breakpoint,
 9600        edit_action: BreakpointPromptEditAction,
 9601        window: &mut Window,
 9602        cx: &mut Context<Self>,
 9603    ) {
 9604        let weak_editor = cx.weak_entity();
 9605        let bp_prompt = cx.new(|cx| {
 9606            BreakpointPromptEditor::new(
 9607                weak_editor,
 9608                anchor,
 9609                breakpoint.clone(),
 9610                edit_action,
 9611                window,
 9612                cx,
 9613            )
 9614        });
 9615
 9616        let height = bp_prompt.update(cx, |this, cx| {
 9617            this.prompt
 9618                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9619        });
 9620        let cloned_prompt = bp_prompt.clone();
 9621        let blocks = vec![BlockProperties {
 9622            style: BlockStyle::Sticky,
 9623            placement: BlockPlacement::Above(anchor),
 9624            height: Some(height),
 9625            render: Arc::new(move |cx| {
 9626                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9627                cloned_prompt.clone().into_any_element()
 9628            }),
 9629            priority: 0,
 9630            render_in_minimap: true,
 9631        }];
 9632
 9633        let focus_handle = bp_prompt.focus_handle(cx);
 9634        window.focus(&focus_handle);
 9635
 9636        let block_ids = self.insert_blocks(blocks, None, cx);
 9637        bp_prompt.update(cx, |prompt, _| {
 9638            prompt.add_block_ids(block_ids);
 9639        });
 9640    }
 9641
 9642    pub(crate) fn breakpoint_at_row(
 9643        &self,
 9644        row: u32,
 9645        window: &mut Window,
 9646        cx: &mut Context<Self>,
 9647    ) -> Option<(Anchor, Breakpoint)> {
 9648        let snapshot = self.snapshot(window, cx);
 9649        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9650
 9651        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9652    }
 9653
 9654    pub(crate) fn breakpoint_at_anchor(
 9655        &self,
 9656        breakpoint_position: Anchor,
 9657        snapshot: &EditorSnapshot,
 9658        cx: &mut Context<Self>,
 9659    ) -> Option<(Anchor, Breakpoint)> {
 9660        let project = self.project.clone()?;
 9661
 9662        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9663            snapshot
 9664                .buffer_snapshot
 9665                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9666        })?;
 9667
 9668        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9669        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9670        let buffer_snapshot = buffer.read(cx).snapshot();
 9671
 9672        let row = buffer_snapshot
 9673            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9674            .row;
 9675
 9676        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9677        let anchor_end = snapshot
 9678            .buffer_snapshot
 9679            .anchor_after(Point::new(row, line_len));
 9680
 9681        let bp = self
 9682            .breakpoint_store
 9683            .as_ref()?
 9684            .read_with(cx, |breakpoint_store, cx| {
 9685                breakpoint_store
 9686                    .breakpoints(
 9687                        &buffer,
 9688                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9689                        &buffer_snapshot,
 9690                        cx,
 9691                    )
 9692                    .next()
 9693                    .and_then(|(bp, _)| {
 9694                        let breakpoint_row = buffer_snapshot
 9695                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9696                            .row;
 9697
 9698                        if breakpoint_row == row {
 9699                            snapshot
 9700                                .buffer_snapshot
 9701                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9702                                .map(|position| (position, bp.bp.clone()))
 9703                        } else {
 9704                            None
 9705                        }
 9706                    })
 9707            });
 9708        bp
 9709    }
 9710
 9711    pub fn edit_log_breakpoint(
 9712        &mut self,
 9713        _: &EditLogBreakpoint,
 9714        window: &mut Window,
 9715        cx: &mut Context<Self>,
 9716    ) {
 9717        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9718            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9719                message: None,
 9720                state: BreakpointState::Enabled,
 9721                condition: None,
 9722                hit_condition: None,
 9723            });
 9724
 9725            self.add_edit_breakpoint_block(
 9726                anchor,
 9727                &breakpoint,
 9728                BreakpointPromptEditAction::Log,
 9729                window,
 9730                cx,
 9731            );
 9732        }
 9733    }
 9734
 9735    fn breakpoints_at_cursors(
 9736        &self,
 9737        window: &mut Window,
 9738        cx: &mut Context<Self>,
 9739    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9740        let snapshot = self.snapshot(window, cx);
 9741        let cursors = self
 9742            .selections
 9743            .disjoint_anchors()
 9744            .into_iter()
 9745            .map(|selection| {
 9746                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9747
 9748                let breakpoint_position = self
 9749                    .breakpoint_at_row(cursor_position.row, window, cx)
 9750                    .map(|bp| bp.0)
 9751                    .unwrap_or_else(|| {
 9752                        snapshot
 9753                            .display_snapshot
 9754                            .buffer_snapshot
 9755                            .anchor_after(Point::new(cursor_position.row, 0))
 9756                    });
 9757
 9758                let breakpoint = self
 9759                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9760                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9761
 9762                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9763            })
 9764            // 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.
 9765            .collect::<HashMap<Anchor, _>>();
 9766
 9767        cursors.into_iter().collect()
 9768    }
 9769
 9770    pub fn enable_breakpoint(
 9771        &mut self,
 9772        _: &crate::actions::EnableBreakpoint,
 9773        window: &mut Window,
 9774        cx: &mut Context<Self>,
 9775    ) {
 9776        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9777            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9778                continue;
 9779            };
 9780            self.edit_breakpoint_at_anchor(
 9781                anchor,
 9782                breakpoint,
 9783                BreakpointEditAction::InvertState,
 9784                cx,
 9785            );
 9786        }
 9787    }
 9788
 9789    pub fn disable_breakpoint(
 9790        &mut self,
 9791        _: &crate::actions::DisableBreakpoint,
 9792        window: &mut Window,
 9793        cx: &mut Context<Self>,
 9794    ) {
 9795        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9796            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9797                continue;
 9798            };
 9799            self.edit_breakpoint_at_anchor(
 9800                anchor,
 9801                breakpoint,
 9802                BreakpointEditAction::InvertState,
 9803                cx,
 9804            );
 9805        }
 9806    }
 9807
 9808    pub fn toggle_breakpoint(
 9809        &mut self,
 9810        _: &crate::actions::ToggleBreakpoint,
 9811        window: &mut Window,
 9812        cx: &mut Context<Self>,
 9813    ) {
 9814        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9815            if let Some(breakpoint) = breakpoint {
 9816                self.edit_breakpoint_at_anchor(
 9817                    anchor,
 9818                    breakpoint,
 9819                    BreakpointEditAction::Toggle,
 9820                    cx,
 9821                );
 9822            } else {
 9823                self.edit_breakpoint_at_anchor(
 9824                    anchor,
 9825                    Breakpoint::new_standard(),
 9826                    BreakpointEditAction::Toggle,
 9827                    cx,
 9828                );
 9829            }
 9830        }
 9831    }
 9832
 9833    pub fn edit_breakpoint_at_anchor(
 9834        &mut self,
 9835        breakpoint_position: Anchor,
 9836        breakpoint: Breakpoint,
 9837        edit_action: BreakpointEditAction,
 9838        cx: &mut Context<Self>,
 9839    ) {
 9840        let Some(breakpoint_store) = &self.breakpoint_store else {
 9841            return;
 9842        };
 9843
 9844        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9845            if breakpoint_position == Anchor::min() {
 9846                self.buffer()
 9847                    .read(cx)
 9848                    .excerpt_buffer_ids()
 9849                    .into_iter()
 9850                    .next()
 9851            } else {
 9852                None
 9853            }
 9854        }) else {
 9855            return;
 9856        };
 9857
 9858        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9859            return;
 9860        };
 9861
 9862        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9863            breakpoint_store.toggle_breakpoint(
 9864                buffer,
 9865                BreakpointWithPosition {
 9866                    position: breakpoint_position.text_anchor,
 9867                    bp: breakpoint,
 9868                },
 9869                edit_action,
 9870                cx,
 9871            );
 9872        });
 9873
 9874        cx.notify();
 9875    }
 9876
 9877    #[cfg(any(test, feature = "test-support"))]
 9878    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9879        self.breakpoint_store.clone()
 9880    }
 9881
 9882    pub fn prepare_restore_change(
 9883        &self,
 9884        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9885        hunk: &MultiBufferDiffHunk,
 9886        cx: &mut App,
 9887    ) -> Option<()> {
 9888        if hunk.is_created_file() {
 9889            return None;
 9890        }
 9891        let buffer = self.buffer.read(cx);
 9892        let diff = buffer.diff_for(hunk.buffer_id)?;
 9893        let buffer = buffer.buffer(hunk.buffer_id)?;
 9894        let buffer = buffer.read(cx);
 9895        let original_text = diff
 9896            .read(cx)
 9897            .base_text()
 9898            .as_rope()
 9899            .slice(hunk.diff_base_byte_range.clone());
 9900        let buffer_snapshot = buffer.snapshot();
 9901        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9902        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9903            probe
 9904                .0
 9905                .start
 9906                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9907                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9908        }) {
 9909            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9910            Some(())
 9911        } else {
 9912            None
 9913        }
 9914    }
 9915
 9916    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9917        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9918    }
 9919
 9920    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9921        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9922    }
 9923
 9924    fn manipulate_lines<Fn>(
 9925        &mut self,
 9926        window: &mut Window,
 9927        cx: &mut Context<Self>,
 9928        mut callback: Fn,
 9929    ) where
 9930        Fn: FnMut(&mut Vec<&str>),
 9931    {
 9932        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9933
 9934        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9935        let buffer = self.buffer.read(cx).snapshot(cx);
 9936
 9937        let mut edits = Vec::new();
 9938
 9939        let selections = self.selections.all::<Point>(cx);
 9940        let mut selections = selections.iter().peekable();
 9941        let mut contiguous_row_selections = Vec::new();
 9942        let mut new_selections = Vec::new();
 9943        let mut added_lines = 0;
 9944        let mut removed_lines = 0;
 9945
 9946        while let Some(selection) = selections.next() {
 9947            let (start_row, end_row) = consume_contiguous_rows(
 9948                &mut contiguous_row_selections,
 9949                selection,
 9950                &display_map,
 9951                &mut selections,
 9952            );
 9953
 9954            let start_point = Point::new(start_row.0, 0);
 9955            let end_point = Point::new(
 9956                end_row.previous_row().0,
 9957                buffer.line_len(end_row.previous_row()),
 9958            );
 9959            let text = buffer
 9960                .text_for_range(start_point..end_point)
 9961                .collect::<String>();
 9962
 9963            let mut lines = text.split('\n').collect_vec();
 9964
 9965            let lines_before = lines.len();
 9966            callback(&mut lines);
 9967            let lines_after = lines.len();
 9968
 9969            edits.push((start_point..end_point, lines.join("\n")));
 9970
 9971            // Selections must change based on added and removed line count
 9972            let start_row =
 9973                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9974            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9975            new_selections.push(Selection {
 9976                id: selection.id,
 9977                start: start_row,
 9978                end: end_row,
 9979                goal: SelectionGoal::None,
 9980                reversed: selection.reversed,
 9981            });
 9982
 9983            if lines_after > lines_before {
 9984                added_lines += lines_after - lines_before;
 9985            } else if lines_before > lines_after {
 9986                removed_lines += lines_before - lines_after;
 9987            }
 9988        }
 9989
 9990        self.transact(window, cx, |this, window, cx| {
 9991            let buffer = this.buffer.update(cx, |buffer, cx| {
 9992                buffer.edit(edits, None, cx);
 9993                buffer.snapshot(cx)
 9994            });
 9995
 9996            // Recalculate offsets on newly edited buffer
 9997            let new_selections = new_selections
 9998                .iter()
 9999                .map(|s| {
10000                    let start_point = Point::new(s.start.0, 0);
10001                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10002                    Selection {
10003                        id: s.id,
10004                        start: buffer.point_to_offset(start_point),
10005                        end: buffer.point_to_offset(end_point),
10006                        goal: s.goal,
10007                        reversed: s.reversed,
10008                    }
10009                })
10010                .collect();
10011
10012            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10013                s.select(new_selections);
10014            });
10015
10016            this.request_autoscroll(Autoscroll::fit(), cx);
10017        });
10018    }
10019
10020    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10021        self.manipulate_text(window, cx, |text| {
10022            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10023            if has_upper_case_characters {
10024                text.to_lowercase()
10025            } else {
10026                text.to_uppercase()
10027            }
10028        })
10029    }
10030
10031    pub fn convert_to_upper_case(
10032        &mut self,
10033        _: &ConvertToUpperCase,
10034        window: &mut Window,
10035        cx: &mut Context<Self>,
10036    ) {
10037        self.manipulate_text(window, cx, |text| text.to_uppercase())
10038    }
10039
10040    pub fn convert_to_lower_case(
10041        &mut self,
10042        _: &ConvertToLowerCase,
10043        window: &mut Window,
10044        cx: &mut Context<Self>,
10045    ) {
10046        self.manipulate_text(window, cx, |text| text.to_lowercase())
10047    }
10048
10049    pub fn convert_to_title_case(
10050        &mut self,
10051        _: &ConvertToTitleCase,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) {
10055        self.manipulate_text(window, cx, |text| {
10056            text.split('\n')
10057                .map(|line| line.to_case(Case::Title))
10058                .join("\n")
10059        })
10060    }
10061
10062    pub fn convert_to_snake_case(
10063        &mut self,
10064        _: &ConvertToSnakeCase,
10065        window: &mut Window,
10066        cx: &mut Context<Self>,
10067    ) {
10068        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10069    }
10070
10071    pub fn convert_to_kebab_case(
10072        &mut self,
10073        _: &ConvertToKebabCase,
10074        window: &mut Window,
10075        cx: &mut Context<Self>,
10076    ) {
10077        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10078    }
10079
10080    pub fn convert_to_upper_camel_case(
10081        &mut self,
10082        _: &ConvertToUpperCamelCase,
10083        window: &mut Window,
10084        cx: &mut Context<Self>,
10085    ) {
10086        self.manipulate_text(window, cx, |text| {
10087            text.split('\n')
10088                .map(|line| line.to_case(Case::UpperCamel))
10089                .join("\n")
10090        })
10091    }
10092
10093    pub fn convert_to_lower_camel_case(
10094        &mut self,
10095        _: &ConvertToLowerCamelCase,
10096        window: &mut Window,
10097        cx: &mut Context<Self>,
10098    ) {
10099        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10100    }
10101
10102    pub fn convert_to_opposite_case(
10103        &mut self,
10104        _: &ConvertToOppositeCase,
10105        window: &mut Window,
10106        cx: &mut Context<Self>,
10107    ) {
10108        self.manipulate_text(window, cx, |text| {
10109            text.chars()
10110                .fold(String::with_capacity(text.len()), |mut t, c| {
10111                    if c.is_uppercase() {
10112                        t.extend(c.to_lowercase());
10113                    } else {
10114                        t.extend(c.to_uppercase());
10115                    }
10116                    t
10117                })
10118        })
10119    }
10120
10121    pub fn convert_to_rot13(
10122        &mut self,
10123        _: &ConvertToRot13,
10124        window: &mut Window,
10125        cx: &mut Context<Self>,
10126    ) {
10127        self.manipulate_text(window, cx, |text| {
10128            text.chars()
10129                .map(|c| match c {
10130                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10131                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10132                    _ => c,
10133                })
10134                .collect()
10135        })
10136    }
10137
10138    pub fn convert_to_rot47(
10139        &mut self,
10140        _: &ConvertToRot47,
10141        window: &mut Window,
10142        cx: &mut Context<Self>,
10143    ) {
10144        self.manipulate_text(window, cx, |text| {
10145            text.chars()
10146                .map(|c| {
10147                    let code_point = c as u32;
10148                    if code_point >= 33 && code_point <= 126 {
10149                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10150                    }
10151                    c
10152                })
10153                .collect()
10154        })
10155    }
10156
10157    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10158    where
10159        Fn: FnMut(&str) -> String,
10160    {
10161        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10162        let buffer = self.buffer.read(cx).snapshot(cx);
10163
10164        let mut new_selections = Vec::new();
10165        let mut edits = Vec::new();
10166        let mut selection_adjustment = 0i32;
10167
10168        for selection in self.selections.all::<usize>(cx) {
10169            let selection_is_empty = selection.is_empty();
10170
10171            let (start, end) = if selection_is_empty {
10172                let word_range = movement::surrounding_word(
10173                    &display_map,
10174                    selection.start.to_display_point(&display_map),
10175                );
10176                let start = word_range.start.to_offset(&display_map, Bias::Left);
10177                let end = word_range.end.to_offset(&display_map, Bias::Left);
10178                (start, end)
10179            } else {
10180                (selection.start, selection.end)
10181            };
10182
10183            let text = buffer.text_for_range(start..end).collect::<String>();
10184            let old_length = text.len() as i32;
10185            let text = callback(&text);
10186
10187            new_selections.push(Selection {
10188                start: (start as i32 - selection_adjustment) as usize,
10189                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10190                goal: SelectionGoal::None,
10191                ..selection
10192            });
10193
10194            selection_adjustment += old_length - text.len() as i32;
10195
10196            edits.push((start..end, text));
10197        }
10198
10199        self.transact(window, cx, |this, window, cx| {
10200            this.buffer.update(cx, |buffer, cx| {
10201                buffer.edit(edits, None, cx);
10202            });
10203
10204            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10205                s.select(new_selections);
10206            });
10207
10208            this.request_autoscroll(Autoscroll::fit(), cx);
10209        });
10210    }
10211
10212    pub fn duplicate(
10213        &mut self,
10214        upwards: bool,
10215        whole_lines: bool,
10216        window: &mut Window,
10217        cx: &mut Context<Self>,
10218    ) {
10219        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10220
10221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10222        let buffer = &display_map.buffer_snapshot;
10223        let selections = self.selections.all::<Point>(cx);
10224
10225        let mut edits = Vec::new();
10226        let mut selections_iter = selections.iter().peekable();
10227        while let Some(selection) = selections_iter.next() {
10228            let mut rows = selection.spanned_rows(false, &display_map);
10229            // duplicate line-wise
10230            if whole_lines || selection.start == selection.end {
10231                // Avoid duplicating the same lines twice.
10232                while let Some(next_selection) = selections_iter.peek() {
10233                    let next_rows = next_selection.spanned_rows(false, &display_map);
10234                    if next_rows.start < rows.end {
10235                        rows.end = next_rows.end;
10236                        selections_iter.next().unwrap();
10237                    } else {
10238                        break;
10239                    }
10240                }
10241
10242                // Copy the text from the selected row region and splice it either at the start
10243                // or end of the region.
10244                let start = Point::new(rows.start.0, 0);
10245                let end = Point::new(
10246                    rows.end.previous_row().0,
10247                    buffer.line_len(rows.end.previous_row()),
10248                );
10249                let text = buffer
10250                    .text_for_range(start..end)
10251                    .chain(Some("\n"))
10252                    .collect::<String>();
10253                let insert_location = if upwards {
10254                    Point::new(rows.end.0, 0)
10255                } else {
10256                    start
10257                };
10258                edits.push((insert_location..insert_location, text));
10259            } else {
10260                // duplicate character-wise
10261                let start = selection.start;
10262                let end = selection.end;
10263                let text = buffer.text_for_range(start..end).collect::<String>();
10264                edits.push((selection.end..selection.end, text));
10265            }
10266        }
10267
10268        self.transact(window, cx, |this, _, cx| {
10269            this.buffer.update(cx, |buffer, cx| {
10270                buffer.edit(edits, None, cx);
10271            });
10272
10273            this.request_autoscroll(Autoscroll::fit(), cx);
10274        });
10275    }
10276
10277    pub fn duplicate_line_up(
10278        &mut self,
10279        _: &DuplicateLineUp,
10280        window: &mut Window,
10281        cx: &mut Context<Self>,
10282    ) {
10283        self.duplicate(true, true, window, cx);
10284    }
10285
10286    pub fn duplicate_line_down(
10287        &mut self,
10288        _: &DuplicateLineDown,
10289        window: &mut Window,
10290        cx: &mut Context<Self>,
10291    ) {
10292        self.duplicate(false, true, window, cx);
10293    }
10294
10295    pub fn duplicate_selection(
10296        &mut self,
10297        _: &DuplicateSelection,
10298        window: &mut Window,
10299        cx: &mut Context<Self>,
10300    ) {
10301        self.duplicate(false, false, window, cx);
10302    }
10303
10304    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10305        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10306
10307        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10308        let buffer = self.buffer.read(cx).snapshot(cx);
10309
10310        let mut edits = Vec::new();
10311        let mut unfold_ranges = Vec::new();
10312        let mut refold_creases = Vec::new();
10313
10314        let selections = self.selections.all::<Point>(cx);
10315        let mut selections = selections.iter().peekable();
10316        let mut contiguous_row_selections = Vec::new();
10317        let mut new_selections = Vec::new();
10318
10319        while let Some(selection) = selections.next() {
10320            // Find all the selections that span a contiguous row range
10321            let (start_row, end_row) = consume_contiguous_rows(
10322                &mut contiguous_row_selections,
10323                selection,
10324                &display_map,
10325                &mut selections,
10326            );
10327
10328            // Move the text spanned by the row range to be before the line preceding the row range
10329            if start_row.0 > 0 {
10330                let range_to_move = Point::new(
10331                    start_row.previous_row().0,
10332                    buffer.line_len(start_row.previous_row()),
10333                )
10334                    ..Point::new(
10335                        end_row.previous_row().0,
10336                        buffer.line_len(end_row.previous_row()),
10337                    );
10338                let insertion_point = display_map
10339                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10340                    .0;
10341
10342                // Don't move lines across excerpts
10343                if buffer
10344                    .excerpt_containing(insertion_point..range_to_move.end)
10345                    .is_some()
10346                {
10347                    let text = buffer
10348                        .text_for_range(range_to_move.clone())
10349                        .flat_map(|s| s.chars())
10350                        .skip(1)
10351                        .chain(['\n'])
10352                        .collect::<String>();
10353
10354                    edits.push((
10355                        buffer.anchor_after(range_to_move.start)
10356                            ..buffer.anchor_before(range_to_move.end),
10357                        String::new(),
10358                    ));
10359                    let insertion_anchor = buffer.anchor_after(insertion_point);
10360                    edits.push((insertion_anchor..insertion_anchor, text));
10361
10362                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10363
10364                    // Move selections up
10365                    new_selections.extend(contiguous_row_selections.drain(..).map(
10366                        |mut selection| {
10367                            selection.start.row -= row_delta;
10368                            selection.end.row -= row_delta;
10369                            selection
10370                        },
10371                    ));
10372
10373                    // Move folds up
10374                    unfold_ranges.push(range_to_move.clone());
10375                    for fold in display_map.folds_in_range(
10376                        buffer.anchor_before(range_to_move.start)
10377                            ..buffer.anchor_after(range_to_move.end),
10378                    ) {
10379                        let mut start = fold.range.start.to_point(&buffer);
10380                        let mut end = fold.range.end.to_point(&buffer);
10381                        start.row -= row_delta;
10382                        end.row -= row_delta;
10383                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10384                    }
10385                }
10386            }
10387
10388            // If we didn't move line(s), preserve the existing selections
10389            new_selections.append(&mut contiguous_row_selections);
10390        }
10391
10392        self.transact(window, cx, |this, window, cx| {
10393            this.unfold_ranges(&unfold_ranges, true, true, cx);
10394            this.buffer.update(cx, |buffer, cx| {
10395                for (range, text) in edits {
10396                    buffer.edit([(range, text)], None, cx);
10397                }
10398            });
10399            this.fold_creases(refold_creases, true, window, cx);
10400            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10401                s.select(new_selections);
10402            })
10403        });
10404    }
10405
10406    pub fn move_line_down(
10407        &mut self,
10408        _: &MoveLineDown,
10409        window: &mut Window,
10410        cx: &mut Context<Self>,
10411    ) {
10412        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10413
10414        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10415        let buffer = self.buffer.read(cx).snapshot(cx);
10416
10417        let mut edits = Vec::new();
10418        let mut unfold_ranges = Vec::new();
10419        let mut refold_creases = Vec::new();
10420
10421        let selections = self.selections.all::<Point>(cx);
10422        let mut selections = selections.iter().peekable();
10423        let mut contiguous_row_selections = Vec::new();
10424        let mut new_selections = Vec::new();
10425
10426        while let Some(selection) = selections.next() {
10427            // Find all the selections that span a contiguous row range
10428            let (start_row, end_row) = consume_contiguous_rows(
10429                &mut contiguous_row_selections,
10430                selection,
10431                &display_map,
10432                &mut selections,
10433            );
10434
10435            // Move the text spanned by the row range to be after the last line of the row range
10436            if end_row.0 <= buffer.max_point().row {
10437                let range_to_move =
10438                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10439                let insertion_point = display_map
10440                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10441                    .0;
10442
10443                // Don't move lines across excerpt boundaries
10444                if buffer
10445                    .excerpt_containing(range_to_move.start..insertion_point)
10446                    .is_some()
10447                {
10448                    let mut text = String::from("\n");
10449                    text.extend(buffer.text_for_range(range_to_move.clone()));
10450                    text.pop(); // Drop trailing newline
10451                    edits.push((
10452                        buffer.anchor_after(range_to_move.start)
10453                            ..buffer.anchor_before(range_to_move.end),
10454                        String::new(),
10455                    ));
10456                    let insertion_anchor = buffer.anchor_after(insertion_point);
10457                    edits.push((insertion_anchor..insertion_anchor, text));
10458
10459                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10460
10461                    // Move selections down
10462                    new_selections.extend(contiguous_row_selections.drain(..).map(
10463                        |mut selection| {
10464                            selection.start.row += row_delta;
10465                            selection.end.row += row_delta;
10466                            selection
10467                        },
10468                    ));
10469
10470                    // Move folds down
10471                    unfold_ranges.push(range_to_move.clone());
10472                    for fold in display_map.folds_in_range(
10473                        buffer.anchor_before(range_to_move.start)
10474                            ..buffer.anchor_after(range_to_move.end),
10475                    ) {
10476                        let mut start = fold.range.start.to_point(&buffer);
10477                        let mut end = fold.range.end.to_point(&buffer);
10478                        start.row += row_delta;
10479                        end.row += row_delta;
10480                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10481                    }
10482                }
10483            }
10484
10485            // If we didn't move line(s), preserve the existing selections
10486            new_selections.append(&mut contiguous_row_selections);
10487        }
10488
10489        self.transact(window, cx, |this, window, cx| {
10490            this.unfold_ranges(&unfold_ranges, true, true, cx);
10491            this.buffer.update(cx, |buffer, cx| {
10492                for (range, text) in edits {
10493                    buffer.edit([(range, text)], None, cx);
10494                }
10495            });
10496            this.fold_creases(refold_creases, true, window, cx);
10497            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10498                s.select(new_selections)
10499            });
10500        });
10501    }
10502
10503    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10504        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10505        let text_layout_details = &self.text_layout_details(window);
10506        self.transact(window, cx, |this, window, cx| {
10507            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10508                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10509                s.move_with(|display_map, selection| {
10510                    if !selection.is_empty() {
10511                        return;
10512                    }
10513
10514                    let mut head = selection.head();
10515                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10516                    if head.column() == display_map.line_len(head.row()) {
10517                        transpose_offset = display_map
10518                            .buffer_snapshot
10519                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10520                    }
10521
10522                    if transpose_offset == 0 {
10523                        return;
10524                    }
10525
10526                    *head.column_mut() += 1;
10527                    head = display_map.clip_point(head, Bias::Right);
10528                    let goal = SelectionGoal::HorizontalPosition(
10529                        display_map
10530                            .x_for_display_point(head, text_layout_details)
10531                            .into(),
10532                    );
10533                    selection.collapse_to(head, goal);
10534
10535                    let transpose_start = display_map
10536                        .buffer_snapshot
10537                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10538                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10539                        let transpose_end = display_map
10540                            .buffer_snapshot
10541                            .clip_offset(transpose_offset + 1, Bias::Right);
10542                        if let Some(ch) =
10543                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10544                        {
10545                            edits.push((transpose_start..transpose_offset, String::new()));
10546                            edits.push((transpose_end..transpose_end, ch.to_string()));
10547                        }
10548                    }
10549                });
10550                edits
10551            });
10552            this.buffer
10553                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10554            let selections = this.selections.all::<usize>(cx);
10555            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10556                s.select(selections);
10557            });
10558        });
10559    }
10560
10561    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10562        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10563        self.rewrap_impl(RewrapOptions::default(), cx)
10564    }
10565
10566    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10567        let buffer = self.buffer.read(cx).snapshot(cx);
10568        let selections = self.selections.all::<Point>(cx);
10569        let mut selections = selections.iter().peekable();
10570
10571        let mut edits = Vec::new();
10572        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10573
10574        while let Some(selection) = selections.next() {
10575            let mut start_row = selection.start.row;
10576            let mut end_row = selection.end.row;
10577
10578            // Skip selections that overlap with a range that has already been rewrapped.
10579            let selection_range = start_row..end_row;
10580            if rewrapped_row_ranges
10581                .iter()
10582                .any(|range| range.overlaps(&selection_range))
10583            {
10584                continue;
10585            }
10586
10587            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10588
10589            // Since not all lines in the selection may be at the same indent
10590            // level, choose the indent size that is the most common between all
10591            // of the lines.
10592            //
10593            // If there is a tie, we use the deepest indent.
10594            let (indent_size, indent_end) = {
10595                let mut indent_size_occurrences = HashMap::default();
10596                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10597
10598                for row in start_row..=end_row {
10599                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10600                    rows_by_indent_size.entry(indent).or_default().push(row);
10601                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10602                }
10603
10604                let indent_size = indent_size_occurrences
10605                    .into_iter()
10606                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10607                    .map(|(indent, _)| indent)
10608                    .unwrap_or_default();
10609                let row = rows_by_indent_size[&indent_size][0];
10610                let indent_end = Point::new(row, indent_size.len);
10611
10612                (indent_size, indent_end)
10613            };
10614
10615            let mut line_prefix = indent_size.chars().collect::<String>();
10616
10617            let mut inside_comment = false;
10618            if let Some(comment_prefix) =
10619                buffer
10620                    .language_scope_at(selection.head())
10621                    .and_then(|language| {
10622                        language
10623                            .line_comment_prefixes()
10624                            .iter()
10625                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10626                            .cloned()
10627                    })
10628            {
10629                line_prefix.push_str(&comment_prefix);
10630                inside_comment = true;
10631            }
10632
10633            let language_settings = buffer.language_settings_at(selection.head(), cx);
10634            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10635                RewrapBehavior::InComments => inside_comment,
10636                RewrapBehavior::InSelections => !selection.is_empty(),
10637                RewrapBehavior::Anywhere => true,
10638            };
10639
10640            let should_rewrap = options.override_language_settings
10641                || allow_rewrap_based_on_language
10642                || self.hard_wrap.is_some();
10643            if !should_rewrap {
10644                continue;
10645            }
10646
10647            if selection.is_empty() {
10648                'expand_upwards: while start_row > 0 {
10649                    let prev_row = start_row - 1;
10650                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10651                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10652                    {
10653                        start_row = prev_row;
10654                    } else {
10655                        break 'expand_upwards;
10656                    }
10657                }
10658
10659                'expand_downwards: while end_row < buffer.max_point().row {
10660                    let next_row = end_row + 1;
10661                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10662                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10663                    {
10664                        end_row = next_row;
10665                    } else {
10666                        break 'expand_downwards;
10667                    }
10668                }
10669            }
10670
10671            let start = Point::new(start_row, 0);
10672            let start_offset = start.to_offset(&buffer);
10673            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10674            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10675            let Some(lines_without_prefixes) = selection_text
10676                .lines()
10677                .map(|line| {
10678                    line.strip_prefix(&line_prefix)
10679                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10680                        .with_context(|| {
10681                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10682                        })
10683                })
10684                .collect::<Result<Vec<_>, _>>()
10685                .log_err()
10686            else {
10687                continue;
10688            };
10689
10690            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10691                buffer
10692                    .language_settings_at(Point::new(start_row, 0), cx)
10693                    .preferred_line_length as usize
10694            });
10695            let wrapped_text = wrap_with_prefix(
10696                line_prefix,
10697                lines_without_prefixes.join("\n"),
10698                wrap_column,
10699                tab_size,
10700                options.preserve_existing_whitespace,
10701            );
10702
10703            // TODO: should always use char-based diff while still supporting cursor behavior that
10704            // matches vim.
10705            let mut diff_options = DiffOptions::default();
10706            if options.override_language_settings {
10707                diff_options.max_word_diff_len = 0;
10708                diff_options.max_word_diff_line_count = 0;
10709            } else {
10710                diff_options.max_word_diff_len = usize::MAX;
10711                diff_options.max_word_diff_line_count = usize::MAX;
10712            }
10713
10714            for (old_range, new_text) in
10715                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10716            {
10717                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10718                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10719                edits.push((edit_start..edit_end, new_text));
10720            }
10721
10722            rewrapped_row_ranges.push(start_row..=end_row);
10723        }
10724
10725        self.buffer
10726            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10727    }
10728
10729    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10730        let mut text = String::new();
10731        let buffer = self.buffer.read(cx).snapshot(cx);
10732        let mut selections = self.selections.all::<Point>(cx);
10733        let mut clipboard_selections = Vec::with_capacity(selections.len());
10734        {
10735            let max_point = buffer.max_point();
10736            let mut is_first = true;
10737            for selection in &mut selections {
10738                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10739                if is_entire_line {
10740                    selection.start = Point::new(selection.start.row, 0);
10741                    if !selection.is_empty() && selection.end.column == 0 {
10742                        selection.end = cmp::min(max_point, selection.end);
10743                    } else {
10744                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10745                    }
10746                    selection.goal = SelectionGoal::None;
10747                }
10748                if is_first {
10749                    is_first = false;
10750                } else {
10751                    text += "\n";
10752                }
10753                let mut len = 0;
10754                for chunk in buffer.text_for_range(selection.start..selection.end) {
10755                    text.push_str(chunk);
10756                    len += chunk.len();
10757                }
10758                clipboard_selections.push(ClipboardSelection {
10759                    len,
10760                    is_entire_line,
10761                    first_line_indent: buffer
10762                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10763                        .len,
10764                });
10765            }
10766        }
10767
10768        self.transact(window, cx, |this, window, cx| {
10769            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10770                s.select(selections);
10771            });
10772            this.insert("", window, cx);
10773        });
10774        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10775    }
10776
10777    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10778        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10779        let item = self.cut_common(window, cx);
10780        cx.write_to_clipboard(item);
10781    }
10782
10783    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10784        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10785        self.change_selections(None, window, cx, |s| {
10786            s.move_with(|snapshot, sel| {
10787                if sel.is_empty() {
10788                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10789                }
10790            });
10791        });
10792        let item = self.cut_common(window, cx);
10793        cx.set_global(KillRing(item))
10794    }
10795
10796    pub fn kill_ring_yank(
10797        &mut self,
10798        _: &KillRingYank,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) {
10802        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10803        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10804            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10805                (kill_ring.text().to_string(), kill_ring.metadata_json())
10806            } else {
10807                return;
10808            }
10809        } else {
10810            return;
10811        };
10812        self.do_paste(&text, metadata, false, window, cx);
10813    }
10814
10815    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10816        self.do_copy(true, cx);
10817    }
10818
10819    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10820        self.do_copy(false, cx);
10821    }
10822
10823    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10824        let selections = self.selections.all::<Point>(cx);
10825        let buffer = self.buffer.read(cx).read(cx);
10826        let mut text = String::new();
10827
10828        let mut clipboard_selections = Vec::with_capacity(selections.len());
10829        {
10830            let max_point = buffer.max_point();
10831            let mut is_first = true;
10832            for selection in &selections {
10833                let mut start = selection.start;
10834                let mut end = selection.end;
10835                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10836                if is_entire_line {
10837                    start = Point::new(start.row, 0);
10838                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10839                }
10840
10841                let mut trimmed_selections = Vec::new();
10842                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10843                    let row = MultiBufferRow(start.row);
10844                    let first_indent = buffer.indent_size_for_line(row);
10845                    if first_indent.len == 0 || start.column > first_indent.len {
10846                        trimmed_selections.push(start..end);
10847                    } else {
10848                        trimmed_selections.push(
10849                            Point::new(row.0, first_indent.len)
10850                                ..Point::new(row.0, buffer.line_len(row)),
10851                        );
10852                        for row in start.row + 1..=end.row {
10853                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10854                            if row == end.row {
10855                                line_len = end.column;
10856                            }
10857                            if line_len == 0 {
10858                                trimmed_selections
10859                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10860                                continue;
10861                            }
10862                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10863                            if row_indent_size.len >= first_indent.len {
10864                                trimmed_selections.push(
10865                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10866                                );
10867                            } else {
10868                                trimmed_selections.clear();
10869                                trimmed_selections.push(start..end);
10870                                break;
10871                            }
10872                        }
10873                    }
10874                } else {
10875                    trimmed_selections.push(start..end);
10876                }
10877
10878                for trimmed_range in trimmed_selections {
10879                    if is_first {
10880                        is_first = false;
10881                    } else {
10882                        text += "\n";
10883                    }
10884                    let mut len = 0;
10885                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10886                        text.push_str(chunk);
10887                        len += chunk.len();
10888                    }
10889                    clipboard_selections.push(ClipboardSelection {
10890                        len,
10891                        is_entire_line,
10892                        first_line_indent: buffer
10893                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10894                            .len,
10895                    });
10896                }
10897            }
10898        }
10899
10900        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10901            text,
10902            clipboard_selections,
10903        ));
10904    }
10905
10906    pub fn do_paste(
10907        &mut self,
10908        text: &String,
10909        clipboard_selections: Option<Vec<ClipboardSelection>>,
10910        handle_entire_lines: bool,
10911        window: &mut Window,
10912        cx: &mut Context<Self>,
10913    ) {
10914        if self.read_only(cx) {
10915            return;
10916        }
10917
10918        let clipboard_text = Cow::Borrowed(text);
10919
10920        self.transact(window, cx, |this, window, cx| {
10921            if let Some(mut clipboard_selections) = clipboard_selections {
10922                let old_selections = this.selections.all::<usize>(cx);
10923                let all_selections_were_entire_line =
10924                    clipboard_selections.iter().all(|s| s.is_entire_line);
10925                let first_selection_indent_column =
10926                    clipboard_selections.first().map(|s| s.first_line_indent);
10927                if clipboard_selections.len() != old_selections.len() {
10928                    clipboard_selections.drain(..);
10929                }
10930                let cursor_offset = this.selections.last::<usize>(cx).head();
10931                let mut auto_indent_on_paste = true;
10932
10933                this.buffer.update(cx, |buffer, cx| {
10934                    let snapshot = buffer.read(cx);
10935                    auto_indent_on_paste = snapshot
10936                        .language_settings_at(cursor_offset, cx)
10937                        .auto_indent_on_paste;
10938
10939                    let mut start_offset = 0;
10940                    let mut edits = Vec::new();
10941                    let mut original_indent_columns = Vec::new();
10942                    for (ix, selection) in old_selections.iter().enumerate() {
10943                        let to_insert;
10944                        let entire_line;
10945                        let original_indent_column;
10946                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10947                            let end_offset = start_offset + clipboard_selection.len;
10948                            to_insert = &clipboard_text[start_offset..end_offset];
10949                            entire_line = clipboard_selection.is_entire_line;
10950                            start_offset = end_offset + 1;
10951                            original_indent_column = Some(clipboard_selection.first_line_indent);
10952                        } else {
10953                            to_insert = clipboard_text.as_str();
10954                            entire_line = all_selections_were_entire_line;
10955                            original_indent_column = first_selection_indent_column
10956                        }
10957
10958                        // If the corresponding selection was empty when this slice of the
10959                        // clipboard text was written, then the entire line containing the
10960                        // selection was copied. If this selection is also currently empty,
10961                        // then paste the line before the current line of the buffer.
10962                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10963                            let column = selection.start.to_point(&snapshot).column as usize;
10964                            let line_start = selection.start - column;
10965                            line_start..line_start
10966                        } else {
10967                            selection.range()
10968                        };
10969
10970                        edits.push((range, to_insert));
10971                        original_indent_columns.push(original_indent_column);
10972                    }
10973                    drop(snapshot);
10974
10975                    buffer.edit(
10976                        edits,
10977                        if auto_indent_on_paste {
10978                            Some(AutoindentMode::Block {
10979                                original_indent_columns,
10980                            })
10981                        } else {
10982                            None
10983                        },
10984                        cx,
10985                    );
10986                });
10987
10988                let selections = this.selections.all::<usize>(cx);
10989                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10990                    s.select(selections)
10991                });
10992            } else {
10993                this.insert(&clipboard_text, window, cx);
10994            }
10995        });
10996    }
10997
10998    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10999        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11000        if let Some(item) = cx.read_from_clipboard() {
11001            let entries = item.entries();
11002
11003            match entries.first() {
11004                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11005                // of all the pasted entries.
11006                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11007                    .do_paste(
11008                        clipboard_string.text(),
11009                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11010                        true,
11011                        window,
11012                        cx,
11013                    ),
11014                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11015            }
11016        }
11017    }
11018
11019    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11020        if self.read_only(cx) {
11021            return;
11022        }
11023
11024        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11025
11026        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11027            if let Some((selections, _)) =
11028                self.selection_history.transaction(transaction_id).cloned()
11029            {
11030                self.change_selections(None, window, cx, |s| {
11031                    s.select_anchors(selections.to_vec());
11032                });
11033            } else {
11034                log::error!(
11035                    "No entry in selection_history found for undo. \
11036                     This may correspond to a bug where undo does not update the selection. \
11037                     If this is occurring, please add details to \
11038                     https://github.com/zed-industries/zed/issues/22692"
11039                );
11040            }
11041            self.request_autoscroll(Autoscroll::fit(), cx);
11042            self.unmark_text(window, cx);
11043            self.refresh_inline_completion(true, false, window, cx);
11044            cx.emit(EditorEvent::Edited { transaction_id });
11045            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11046        }
11047    }
11048
11049    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11050        if self.read_only(cx) {
11051            return;
11052        }
11053
11054        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11055
11056        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11057            if let Some((_, Some(selections))) =
11058                self.selection_history.transaction(transaction_id).cloned()
11059            {
11060                self.change_selections(None, window, cx, |s| {
11061                    s.select_anchors(selections.to_vec());
11062                });
11063            } else {
11064                log::error!(
11065                    "No entry in selection_history found for redo. \
11066                     This may correspond to a bug where undo does not update the selection. \
11067                     If this is occurring, please add details to \
11068                     https://github.com/zed-industries/zed/issues/22692"
11069                );
11070            }
11071            self.request_autoscroll(Autoscroll::fit(), cx);
11072            self.unmark_text(window, cx);
11073            self.refresh_inline_completion(true, false, window, cx);
11074            cx.emit(EditorEvent::Edited { transaction_id });
11075        }
11076    }
11077
11078    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11079        self.buffer
11080            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11081    }
11082
11083    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11084        self.buffer
11085            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11086    }
11087
11088    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11089        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11090        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11091            s.move_with(|map, selection| {
11092                let cursor = if selection.is_empty() {
11093                    movement::left(map, selection.start)
11094                } else {
11095                    selection.start
11096                };
11097                selection.collapse_to(cursor, SelectionGoal::None);
11098            });
11099        })
11100    }
11101
11102    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11103        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11104        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11105            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11106        })
11107    }
11108
11109    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11110        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11112            s.move_with(|map, selection| {
11113                let cursor = if selection.is_empty() {
11114                    movement::right(map, selection.end)
11115                } else {
11116                    selection.end
11117                };
11118                selection.collapse_to(cursor, SelectionGoal::None)
11119            });
11120        })
11121    }
11122
11123    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11125        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11126            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11127        })
11128    }
11129
11130    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11131        if self.take_rename(true, window, cx).is_some() {
11132            return;
11133        }
11134
11135        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11136            cx.propagate();
11137            return;
11138        }
11139
11140        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11141
11142        let text_layout_details = &self.text_layout_details(window);
11143        let selection_count = self.selections.count();
11144        let first_selection = self.selections.first_anchor();
11145
11146        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11147            s.move_with(|map, selection| {
11148                if !selection.is_empty() {
11149                    selection.goal = SelectionGoal::None;
11150                }
11151                let (cursor, goal) = movement::up(
11152                    map,
11153                    selection.start,
11154                    selection.goal,
11155                    false,
11156                    text_layout_details,
11157                );
11158                selection.collapse_to(cursor, goal);
11159            });
11160        });
11161
11162        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11163        {
11164            cx.propagate();
11165        }
11166    }
11167
11168    pub fn move_up_by_lines(
11169        &mut self,
11170        action: &MoveUpByLines,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        if self.take_rename(true, window, cx).is_some() {
11175            return;
11176        }
11177
11178        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11179            cx.propagate();
11180            return;
11181        }
11182
11183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11184
11185        let text_layout_details = &self.text_layout_details(window);
11186
11187        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11188            s.move_with(|map, selection| {
11189                if !selection.is_empty() {
11190                    selection.goal = SelectionGoal::None;
11191                }
11192                let (cursor, goal) = movement::up_by_rows(
11193                    map,
11194                    selection.start,
11195                    action.lines,
11196                    selection.goal,
11197                    false,
11198                    text_layout_details,
11199                );
11200                selection.collapse_to(cursor, goal);
11201            });
11202        })
11203    }
11204
11205    pub fn move_down_by_lines(
11206        &mut self,
11207        action: &MoveDownByLines,
11208        window: &mut Window,
11209        cx: &mut Context<Self>,
11210    ) {
11211        if self.take_rename(true, window, cx).is_some() {
11212            return;
11213        }
11214
11215        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11216            cx.propagate();
11217            return;
11218        }
11219
11220        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11221
11222        let text_layout_details = &self.text_layout_details(window);
11223
11224        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11225            s.move_with(|map, selection| {
11226                if !selection.is_empty() {
11227                    selection.goal = SelectionGoal::None;
11228                }
11229                let (cursor, goal) = movement::down_by_rows(
11230                    map,
11231                    selection.start,
11232                    action.lines,
11233                    selection.goal,
11234                    false,
11235                    text_layout_details,
11236                );
11237                selection.collapse_to(cursor, goal);
11238            });
11239        })
11240    }
11241
11242    pub fn select_down_by_lines(
11243        &mut self,
11244        action: &SelectDownByLines,
11245        window: &mut Window,
11246        cx: &mut Context<Self>,
11247    ) {
11248        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11249        let text_layout_details = &self.text_layout_details(window);
11250        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11251            s.move_heads_with(|map, head, goal| {
11252                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11253            })
11254        })
11255    }
11256
11257    pub fn select_up_by_lines(
11258        &mut self,
11259        action: &SelectUpByLines,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262    ) {
11263        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11264        let text_layout_details = &self.text_layout_details(window);
11265        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11266            s.move_heads_with(|map, head, goal| {
11267                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11268            })
11269        })
11270    }
11271
11272    pub fn select_page_up(
11273        &mut self,
11274        _: &SelectPageUp,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277    ) {
11278        let Some(row_count) = self.visible_row_count() else {
11279            return;
11280        };
11281
11282        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11283
11284        let text_layout_details = &self.text_layout_details(window);
11285
11286        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11287            s.move_heads_with(|map, head, goal| {
11288                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11289            })
11290        })
11291    }
11292
11293    pub fn move_page_up(
11294        &mut self,
11295        action: &MovePageUp,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298    ) {
11299        if self.take_rename(true, window, cx).is_some() {
11300            return;
11301        }
11302
11303        if self
11304            .context_menu
11305            .borrow_mut()
11306            .as_mut()
11307            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11308            .unwrap_or(false)
11309        {
11310            return;
11311        }
11312
11313        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11314            cx.propagate();
11315            return;
11316        }
11317
11318        let Some(row_count) = self.visible_row_count() else {
11319            return;
11320        };
11321
11322        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11323
11324        let autoscroll = if action.center_cursor {
11325            Autoscroll::center()
11326        } else {
11327            Autoscroll::fit()
11328        };
11329
11330        let text_layout_details = &self.text_layout_details(window);
11331
11332        self.change_selections(Some(autoscroll), 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::up_by_rows(
11338                    map,
11339                    selection.end,
11340                    row_count,
11341                    selection.goal,
11342                    false,
11343                    text_layout_details,
11344                );
11345                selection.collapse_to(cursor, goal);
11346            });
11347        });
11348    }
11349
11350    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11351        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11352        let text_layout_details = &self.text_layout_details(window);
11353        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11354            s.move_heads_with(|map, head, goal| {
11355                movement::up(map, head, goal, false, text_layout_details)
11356            })
11357        })
11358    }
11359
11360    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11361        self.take_rename(true, window, cx);
11362
11363        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11364            cx.propagate();
11365            return;
11366        }
11367
11368        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11369
11370        let text_layout_details = &self.text_layout_details(window);
11371        let selection_count = self.selections.count();
11372        let first_selection = self.selections.first_anchor();
11373
11374        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11375            s.move_with(|map, selection| {
11376                if !selection.is_empty() {
11377                    selection.goal = SelectionGoal::None;
11378                }
11379                let (cursor, goal) = movement::down(
11380                    map,
11381                    selection.end,
11382                    selection.goal,
11383                    false,
11384                    text_layout_details,
11385                );
11386                selection.collapse_to(cursor, goal);
11387            });
11388        });
11389
11390        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11391        {
11392            cx.propagate();
11393        }
11394    }
11395
11396    pub fn select_page_down(
11397        &mut self,
11398        _: &SelectPageDown,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        let Some(row_count) = self.visible_row_count() else {
11403            return;
11404        };
11405
11406        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11407
11408        let text_layout_details = &self.text_layout_details(window);
11409
11410        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11411            s.move_heads_with(|map, head, goal| {
11412                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11413            })
11414        })
11415    }
11416
11417    pub fn move_page_down(
11418        &mut self,
11419        action: &MovePageDown,
11420        window: &mut Window,
11421        cx: &mut Context<Self>,
11422    ) {
11423        if self.take_rename(true, window, cx).is_some() {
11424            return;
11425        }
11426
11427        if self
11428            .context_menu
11429            .borrow_mut()
11430            .as_mut()
11431            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11432            .unwrap_or(false)
11433        {
11434            return;
11435        }
11436
11437        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11438            cx.propagate();
11439            return;
11440        }
11441
11442        let Some(row_count) = self.visible_row_count() else {
11443            return;
11444        };
11445
11446        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11447
11448        let autoscroll = if action.center_cursor {
11449            Autoscroll::center()
11450        } else {
11451            Autoscroll::fit()
11452        };
11453
11454        let text_layout_details = &self.text_layout_details(window);
11455        self.change_selections(Some(autoscroll), window, cx, |s| {
11456            s.move_with(|map, selection| {
11457                if !selection.is_empty() {
11458                    selection.goal = SelectionGoal::None;
11459                }
11460                let (cursor, goal) = movement::down_by_rows(
11461                    map,
11462                    selection.end,
11463                    row_count,
11464                    selection.goal,
11465                    false,
11466                    text_layout_details,
11467                );
11468                selection.collapse_to(cursor, goal);
11469            });
11470        });
11471    }
11472
11473    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11474        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11475        let text_layout_details = &self.text_layout_details(window);
11476        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11477            s.move_heads_with(|map, head, goal| {
11478                movement::down(map, head, goal, false, text_layout_details)
11479            })
11480        });
11481    }
11482
11483    pub fn context_menu_first(
11484        &mut self,
11485        _: &ContextMenuFirst,
11486        _window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11490            context_menu.select_first(self.completion_provider.as_deref(), cx);
11491        }
11492    }
11493
11494    pub fn context_menu_prev(
11495        &mut self,
11496        _: &ContextMenuPrevious,
11497        _window: &mut Window,
11498        cx: &mut Context<Self>,
11499    ) {
11500        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11501            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11502        }
11503    }
11504
11505    pub fn context_menu_next(
11506        &mut self,
11507        _: &ContextMenuNext,
11508        _window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11512            context_menu.select_next(self.completion_provider.as_deref(), cx);
11513        }
11514    }
11515
11516    pub fn context_menu_last(
11517        &mut self,
11518        _: &ContextMenuLast,
11519        _window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11523            context_menu.select_last(self.completion_provider.as_deref(), cx);
11524        }
11525    }
11526
11527    pub fn move_to_previous_word_start(
11528        &mut self,
11529        _: &MoveToPreviousWordStart,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11534        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11535            s.move_cursors_with(|map, head, _| {
11536                (
11537                    movement::previous_word_start(map, head),
11538                    SelectionGoal::None,
11539                )
11540            });
11541        })
11542    }
11543
11544    pub fn move_to_previous_subword_start(
11545        &mut self,
11546        _: &MoveToPreviousSubwordStart,
11547        window: &mut Window,
11548        cx: &mut Context<Self>,
11549    ) {
11550        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11551        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11552            s.move_cursors_with(|map, head, _| {
11553                (
11554                    movement::previous_subword_start(map, head),
11555                    SelectionGoal::None,
11556                )
11557            });
11558        })
11559    }
11560
11561    pub fn select_to_previous_word_start(
11562        &mut self,
11563        _: &SelectToPreviousWordStart,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566    ) {
11567        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11568        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11569            s.move_heads_with(|map, head, _| {
11570                (
11571                    movement::previous_word_start(map, head),
11572                    SelectionGoal::None,
11573                )
11574            });
11575        })
11576    }
11577
11578    pub fn select_to_previous_subword_start(
11579        &mut self,
11580        _: &SelectToPreviousSubwordStart,
11581        window: &mut Window,
11582        cx: &mut Context<Self>,
11583    ) {
11584        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11585        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11586            s.move_heads_with(|map, head, _| {
11587                (
11588                    movement::previous_subword_start(map, head),
11589                    SelectionGoal::None,
11590                )
11591            });
11592        })
11593    }
11594
11595    pub fn delete_to_previous_word_start(
11596        &mut self,
11597        action: &DeleteToPreviousWordStart,
11598        window: &mut Window,
11599        cx: &mut Context<Self>,
11600    ) {
11601        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11602        self.transact(window, cx, |this, window, cx| {
11603            this.select_autoclose_pair(window, cx);
11604            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11605                s.move_with(|map, selection| {
11606                    if selection.is_empty() {
11607                        let cursor = if action.ignore_newlines {
11608                            movement::previous_word_start(map, selection.head())
11609                        } else {
11610                            movement::previous_word_start_or_newline(map, selection.head())
11611                        };
11612                        selection.set_head(cursor, SelectionGoal::None);
11613                    }
11614                });
11615            });
11616            this.insert("", window, cx);
11617        });
11618    }
11619
11620    pub fn delete_to_previous_subword_start(
11621        &mut self,
11622        _: &DeleteToPreviousSubwordStart,
11623        window: &mut Window,
11624        cx: &mut Context<Self>,
11625    ) {
11626        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11627        self.transact(window, cx, |this, window, cx| {
11628            this.select_autoclose_pair(window, cx);
11629            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11630                s.move_with(|map, selection| {
11631                    if selection.is_empty() {
11632                        let cursor = movement::previous_subword_start(map, selection.head());
11633                        selection.set_head(cursor, SelectionGoal::None);
11634                    }
11635                });
11636            });
11637            this.insert("", window, cx);
11638        });
11639    }
11640
11641    pub fn move_to_next_word_end(
11642        &mut self,
11643        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
11650                (movement::next_word_end(map, head), SelectionGoal::None)
11651            });
11652        })
11653    }
11654
11655    pub fn move_to_next_subword_end(
11656        &mut self,
11657        _: &MoveToNextSubwordEnd,
11658        window: &mut Window,
11659        cx: &mut Context<Self>,
11660    ) {
11661        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11662        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11663            s.move_cursors_with(|map, head, _| {
11664                (movement::next_subword_end(map, head), SelectionGoal::None)
11665            });
11666        })
11667    }
11668
11669    pub fn select_to_next_word_end(
11670        &mut self,
11671        _: &SelectToNextWordEnd,
11672        window: &mut Window,
11673        cx: &mut Context<Self>,
11674    ) {
11675        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11676        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11677            s.move_heads_with(|map, head, _| {
11678                (movement::next_word_end(map, head), SelectionGoal::None)
11679            });
11680        })
11681    }
11682
11683    pub fn select_to_next_subword_end(
11684        &mut self,
11685        _: &SelectToNextSubwordEnd,
11686        window: &mut Window,
11687        cx: &mut Context<Self>,
11688    ) {
11689        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11690        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11691            s.move_heads_with(|map, head, _| {
11692                (movement::next_subword_end(map, head), SelectionGoal::None)
11693            });
11694        })
11695    }
11696
11697    pub fn delete_to_next_word_end(
11698        &mut self,
11699        action: &DeleteToNextWordEnd,
11700        window: &mut Window,
11701        cx: &mut Context<Self>,
11702    ) {
11703        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11704        self.transact(window, cx, |this, window, cx| {
11705            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11706                s.move_with(|map, selection| {
11707                    if selection.is_empty() {
11708                        let cursor = if action.ignore_newlines {
11709                            movement::next_word_end(map, selection.head())
11710                        } else {
11711                            movement::next_word_end_or_newline(map, selection.head())
11712                        };
11713                        selection.set_head(cursor, SelectionGoal::None);
11714                    }
11715                });
11716            });
11717            this.insert("", window, cx);
11718        });
11719    }
11720
11721    pub fn delete_to_next_subword_end(
11722        &mut self,
11723        _: &DeleteToNextSubwordEnd,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11728        self.transact(window, cx, |this, window, cx| {
11729            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11730                s.move_with(|map, selection| {
11731                    if selection.is_empty() {
11732                        let cursor = movement::next_subword_end(map, selection.head());
11733                        selection.set_head(cursor, SelectionGoal::None);
11734                    }
11735                });
11736            });
11737            this.insert("", window, cx);
11738        });
11739    }
11740
11741    pub fn move_to_beginning_of_line(
11742        &mut self,
11743        action: &MoveToBeginningOfLine,
11744        window: &mut Window,
11745        cx: &mut Context<Self>,
11746    ) {
11747        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11748        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11749            s.move_cursors_with(|map, head, _| {
11750                (
11751                    movement::indented_line_beginning(
11752                        map,
11753                        head,
11754                        action.stop_at_soft_wraps,
11755                        action.stop_at_indent,
11756                    ),
11757                    SelectionGoal::None,
11758                )
11759            });
11760        })
11761    }
11762
11763    pub fn select_to_beginning_of_line(
11764        &mut self,
11765        action: &SelectToBeginningOfLine,
11766        window: &mut Window,
11767        cx: &mut Context<Self>,
11768    ) {
11769        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11770        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11771            s.move_heads_with(|map, head, _| {
11772                (
11773                    movement::indented_line_beginning(
11774                        map,
11775                        head,
11776                        action.stop_at_soft_wraps,
11777                        action.stop_at_indent,
11778                    ),
11779                    SelectionGoal::None,
11780                )
11781            });
11782        });
11783    }
11784
11785    pub fn delete_to_beginning_of_line(
11786        &mut self,
11787        action: &DeleteToBeginningOfLine,
11788        window: &mut Window,
11789        cx: &mut Context<Self>,
11790    ) {
11791        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11792        self.transact(window, cx, |this, window, cx| {
11793            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11794                s.move_with(|_, selection| {
11795                    selection.reversed = true;
11796                });
11797            });
11798
11799            this.select_to_beginning_of_line(
11800                &SelectToBeginningOfLine {
11801                    stop_at_soft_wraps: false,
11802                    stop_at_indent: action.stop_at_indent,
11803                },
11804                window,
11805                cx,
11806            );
11807            this.backspace(&Backspace, window, cx);
11808        });
11809    }
11810
11811    pub fn move_to_end_of_line(
11812        &mut self,
11813        action: &MoveToEndOfLine,
11814        window: &mut Window,
11815        cx: &mut Context<Self>,
11816    ) {
11817        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11818        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11819            s.move_cursors_with(|map, head, _| {
11820                (
11821                    movement::line_end(map, head, action.stop_at_soft_wraps),
11822                    SelectionGoal::None,
11823                )
11824            });
11825        })
11826    }
11827
11828    pub fn select_to_end_of_line(
11829        &mut self,
11830        action: &SelectToEndOfLine,
11831        window: &mut Window,
11832        cx: &mut Context<Self>,
11833    ) {
11834        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11835        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11836            s.move_heads_with(|map, head, _| {
11837                (
11838                    movement::line_end(map, head, action.stop_at_soft_wraps),
11839                    SelectionGoal::None,
11840                )
11841            });
11842        })
11843    }
11844
11845    pub fn delete_to_end_of_line(
11846        &mut self,
11847        _: &DeleteToEndOfLine,
11848        window: &mut Window,
11849        cx: &mut Context<Self>,
11850    ) {
11851        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11852        self.transact(window, cx, |this, window, cx| {
11853            this.select_to_end_of_line(
11854                &SelectToEndOfLine {
11855                    stop_at_soft_wraps: false,
11856                },
11857                window,
11858                cx,
11859            );
11860            this.delete(&Delete, window, cx);
11861        });
11862    }
11863
11864    pub fn cut_to_end_of_line(
11865        &mut self,
11866        _: &CutToEndOfLine,
11867        window: &mut Window,
11868        cx: &mut Context<Self>,
11869    ) {
11870        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11871        self.transact(window, cx, |this, window, cx| {
11872            this.select_to_end_of_line(
11873                &SelectToEndOfLine {
11874                    stop_at_soft_wraps: false,
11875                },
11876                window,
11877                cx,
11878            );
11879            this.cut(&Cut, window, cx);
11880        });
11881    }
11882
11883    pub fn move_to_start_of_paragraph(
11884        &mut self,
11885        _: &MoveToStartOfParagraph,
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_with(|map, selection| {
11896                selection.collapse_to(
11897                    movement::start_of_paragraph(map, selection.head(), 1),
11898                    SelectionGoal::None,
11899                )
11900            });
11901        })
11902    }
11903
11904    pub fn move_to_end_of_paragraph(
11905        &mut self,
11906        _: &MoveToEndOfParagraph,
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_with(|map, selection| {
11917                selection.collapse_to(
11918                    movement::end_of_paragraph(map, selection.head(), 1),
11919                    SelectionGoal::None,
11920                )
11921            });
11922        })
11923    }
11924
11925    pub fn select_to_start_of_paragraph(
11926        &mut self,
11927        _: &SelectToStartOfParagraph,
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_heads_with(|map, head, _| {
11938                (
11939                    movement::start_of_paragraph(map, head, 1),
11940                    SelectionGoal::None,
11941                )
11942            });
11943        })
11944    }
11945
11946    pub fn select_to_end_of_paragraph(
11947        &mut self,
11948        _: &SelectToEndOfParagraph,
11949        window: &mut Window,
11950        cx: &mut Context<Self>,
11951    ) {
11952        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11953            cx.propagate();
11954            return;
11955        }
11956        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11957        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11958            s.move_heads_with(|map, head, _| {
11959                (
11960                    movement::end_of_paragraph(map, head, 1),
11961                    SelectionGoal::None,
11962                )
11963            });
11964        })
11965    }
11966
11967    pub fn move_to_start_of_excerpt(
11968        &mut self,
11969        _: &MoveToStartOfExcerpt,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11974            cx.propagate();
11975            return;
11976        }
11977        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11978        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11979            s.move_with(|map, selection| {
11980                selection.collapse_to(
11981                    movement::start_of_excerpt(
11982                        map,
11983                        selection.head(),
11984                        workspace::searchable::Direction::Prev,
11985                    ),
11986                    SelectionGoal::None,
11987                )
11988            });
11989        })
11990    }
11991
11992    pub fn move_to_start_of_next_excerpt(
11993        &mut self,
11994        _: &MoveToStartOfNextExcerpt,
11995        window: &mut Window,
11996        cx: &mut Context<Self>,
11997    ) {
11998        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11999            cx.propagate();
12000            return;
12001        }
12002
12003        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12004            s.move_with(|map, selection| {
12005                selection.collapse_to(
12006                    movement::start_of_excerpt(
12007                        map,
12008                        selection.head(),
12009                        workspace::searchable::Direction::Next,
12010                    ),
12011                    SelectionGoal::None,
12012                )
12013            });
12014        })
12015    }
12016
12017    pub fn move_to_end_of_excerpt(
12018        &mut self,
12019        _: &MoveToEndOfExcerpt,
12020        window: &mut Window,
12021        cx: &mut Context<Self>,
12022    ) {
12023        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12024            cx.propagate();
12025            return;
12026        }
12027        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12028        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12029            s.move_with(|map, selection| {
12030                selection.collapse_to(
12031                    movement::end_of_excerpt(
12032                        map,
12033                        selection.head(),
12034                        workspace::searchable::Direction::Next,
12035                    ),
12036                    SelectionGoal::None,
12037                )
12038            });
12039        })
12040    }
12041
12042    pub fn move_to_end_of_previous_excerpt(
12043        &mut self,
12044        _: &MoveToEndOfPreviousExcerpt,
12045        window: &mut Window,
12046        cx: &mut Context<Self>,
12047    ) {
12048        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12049            cx.propagate();
12050            return;
12051        }
12052        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12053        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12054            s.move_with(|map, selection| {
12055                selection.collapse_to(
12056                    movement::end_of_excerpt(
12057                        map,
12058                        selection.head(),
12059                        workspace::searchable::Direction::Prev,
12060                    ),
12061                    SelectionGoal::None,
12062                )
12063            });
12064        })
12065    }
12066
12067    pub fn select_to_start_of_excerpt(
12068        &mut self,
12069        _: &SelectToStartOfExcerpt,
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::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12082                    SelectionGoal::None,
12083                )
12084            });
12085        })
12086    }
12087
12088    pub fn select_to_start_of_next_excerpt(
12089        &mut self,
12090        _: &SelectToStartOfNextExcerpt,
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::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12103                    SelectionGoal::None,
12104                )
12105            });
12106        })
12107    }
12108
12109    pub fn select_to_end_of_excerpt(
12110        &mut self,
12111        _: &SelectToEndOfExcerpt,
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.move_heads_with(|map, head, _| {
12122                (
12123                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12124                    SelectionGoal::None,
12125                )
12126            });
12127        })
12128    }
12129
12130    pub fn select_to_end_of_previous_excerpt(
12131        &mut self,
12132        _: &SelectToEndOfPreviousExcerpt,
12133        window: &mut Window,
12134        cx: &mut Context<Self>,
12135    ) {
12136        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12137            cx.propagate();
12138            return;
12139        }
12140        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12141        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12142            s.move_heads_with(|map, head, _| {
12143                (
12144                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12145                    SelectionGoal::None,
12146                )
12147            });
12148        })
12149    }
12150
12151    pub fn move_to_beginning(
12152        &mut self,
12153        _: &MoveToBeginning,
12154        window: &mut Window,
12155        cx: &mut Context<Self>,
12156    ) {
12157        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12158            cx.propagate();
12159            return;
12160        }
12161        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12162        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12163            s.select_ranges(vec![0..0]);
12164        });
12165    }
12166
12167    pub fn select_to_beginning(
12168        &mut self,
12169        _: &SelectToBeginning,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) {
12173        let mut selection = self.selections.last::<Point>(cx);
12174        selection.set_head(Point::zero(), SelectionGoal::None);
12175        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12176        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12177            s.select(vec![selection]);
12178        });
12179    }
12180
12181    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12182        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12183            cx.propagate();
12184            return;
12185        }
12186        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12187        let cursor = self.buffer.read(cx).read(cx).len();
12188        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12189            s.select_ranges(vec![cursor..cursor])
12190        });
12191    }
12192
12193    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12194        self.nav_history = nav_history;
12195    }
12196
12197    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12198        self.nav_history.as_ref()
12199    }
12200
12201    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12202        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12203    }
12204
12205    fn push_to_nav_history(
12206        &mut self,
12207        cursor_anchor: Anchor,
12208        new_position: Option<Point>,
12209        is_deactivate: bool,
12210        cx: &mut Context<Self>,
12211    ) {
12212        if let Some(nav_history) = self.nav_history.as_mut() {
12213            let buffer = self.buffer.read(cx).read(cx);
12214            let cursor_position = cursor_anchor.to_point(&buffer);
12215            let scroll_state = self.scroll_manager.anchor();
12216            let scroll_top_row = scroll_state.top_row(&buffer);
12217            drop(buffer);
12218
12219            if let Some(new_position) = new_position {
12220                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12221                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12222                    return;
12223                }
12224            }
12225
12226            nav_history.push(
12227                Some(NavigationData {
12228                    cursor_anchor,
12229                    cursor_position,
12230                    scroll_anchor: scroll_state,
12231                    scroll_top_row,
12232                }),
12233                cx,
12234            );
12235            cx.emit(EditorEvent::PushedToNavHistory {
12236                anchor: cursor_anchor,
12237                is_deactivate,
12238            })
12239        }
12240    }
12241
12242    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12243        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12244        let buffer = self.buffer.read(cx).snapshot(cx);
12245        let mut selection = self.selections.first::<usize>(cx);
12246        selection.set_head(buffer.len(), SelectionGoal::None);
12247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248            s.select(vec![selection]);
12249        });
12250    }
12251
12252    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12253        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12254        let end = self.buffer.read(cx).read(cx).len();
12255        self.change_selections(None, window, cx, |s| {
12256            s.select_ranges(vec![0..end]);
12257        });
12258    }
12259
12260    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12261        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12262        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12263        let mut selections = self.selections.all::<Point>(cx);
12264        let max_point = display_map.buffer_snapshot.max_point();
12265        for selection in &mut selections {
12266            let rows = selection.spanned_rows(true, &display_map);
12267            selection.start = Point::new(rows.start.0, 0);
12268            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12269            selection.reversed = false;
12270        }
12271        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12272            s.select(selections);
12273        });
12274    }
12275
12276    pub fn split_selection_into_lines(
12277        &mut self,
12278        _: &SplitSelectionIntoLines,
12279        window: &mut Window,
12280        cx: &mut Context<Self>,
12281    ) {
12282        let selections = self
12283            .selections
12284            .all::<Point>(cx)
12285            .into_iter()
12286            .map(|selection| selection.start..selection.end)
12287            .collect::<Vec<_>>();
12288        self.unfold_ranges(&selections, true, true, cx);
12289
12290        let mut new_selection_ranges = Vec::new();
12291        {
12292            let buffer = self.buffer.read(cx).read(cx);
12293            for selection in selections {
12294                for row in selection.start.row..selection.end.row {
12295                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12296                    new_selection_ranges.push(cursor..cursor);
12297                }
12298
12299                let is_multiline_selection = selection.start.row != selection.end.row;
12300                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12301                // so this action feels more ergonomic when paired with other selection operations
12302                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12303                if !should_skip_last {
12304                    new_selection_ranges.push(selection.end..selection.end);
12305                }
12306            }
12307        }
12308        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12309            s.select_ranges(new_selection_ranges);
12310        });
12311    }
12312
12313    pub fn add_selection_above(
12314        &mut self,
12315        _: &AddSelectionAbove,
12316        window: &mut Window,
12317        cx: &mut Context<Self>,
12318    ) {
12319        self.add_selection(true, window, cx);
12320    }
12321
12322    pub fn add_selection_below(
12323        &mut self,
12324        _: &AddSelectionBelow,
12325        window: &mut Window,
12326        cx: &mut Context<Self>,
12327    ) {
12328        self.add_selection(false, window, cx);
12329    }
12330
12331    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12332        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12333
12334        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12335        let mut selections = self.selections.all::<Point>(cx);
12336        let text_layout_details = self.text_layout_details(window);
12337        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12338            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12339            let range = oldest_selection.display_range(&display_map).sorted();
12340
12341            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12342            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12343            let positions = start_x.min(end_x)..start_x.max(end_x);
12344
12345            selections.clear();
12346            let mut stack = Vec::new();
12347            for row in range.start.row().0..=range.end.row().0 {
12348                if let Some(selection) = self.selections.build_columnar_selection(
12349                    &display_map,
12350                    DisplayRow(row),
12351                    &positions,
12352                    oldest_selection.reversed,
12353                    &text_layout_details,
12354                ) {
12355                    stack.push(selection.id);
12356                    selections.push(selection);
12357                }
12358            }
12359
12360            if above {
12361                stack.reverse();
12362            }
12363
12364            AddSelectionsState { above, stack }
12365        });
12366
12367        let last_added_selection = *state.stack.last().unwrap();
12368        let mut new_selections = Vec::new();
12369        if above == state.above {
12370            let end_row = if above {
12371                DisplayRow(0)
12372            } else {
12373                display_map.max_point().row()
12374            };
12375
12376            'outer: for selection in selections {
12377                if selection.id == last_added_selection {
12378                    let range = selection.display_range(&display_map).sorted();
12379                    debug_assert_eq!(range.start.row(), range.end.row());
12380                    let mut row = range.start.row();
12381                    let positions =
12382                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12383                            px(start)..px(end)
12384                        } else {
12385                            let start_x =
12386                                display_map.x_for_display_point(range.start, &text_layout_details);
12387                            let end_x =
12388                                display_map.x_for_display_point(range.end, &text_layout_details);
12389                            start_x.min(end_x)..start_x.max(end_x)
12390                        };
12391
12392                    while row != end_row {
12393                        if above {
12394                            row.0 -= 1;
12395                        } else {
12396                            row.0 += 1;
12397                        }
12398
12399                        if let Some(new_selection) = self.selections.build_columnar_selection(
12400                            &display_map,
12401                            row,
12402                            &positions,
12403                            selection.reversed,
12404                            &text_layout_details,
12405                        ) {
12406                            state.stack.push(new_selection.id);
12407                            if above {
12408                                new_selections.push(new_selection);
12409                                new_selections.push(selection);
12410                            } else {
12411                                new_selections.push(selection);
12412                                new_selections.push(new_selection);
12413                            }
12414
12415                            continue 'outer;
12416                        }
12417                    }
12418                }
12419
12420                new_selections.push(selection);
12421            }
12422        } else {
12423            new_selections = selections;
12424            new_selections.retain(|s| s.id != last_added_selection);
12425            state.stack.pop();
12426        }
12427
12428        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12429            s.select(new_selections);
12430        });
12431        if state.stack.len() > 1 {
12432            self.add_selections_state = Some(state);
12433        }
12434    }
12435
12436    fn select_match_ranges(
12437        &mut self,
12438        range: Range<usize>,
12439        reversed: bool,
12440        replace_newest: bool,
12441        auto_scroll: Option<Autoscroll>,
12442        window: &mut Window,
12443        cx: &mut Context<Editor>,
12444    ) {
12445        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12446        self.change_selections(auto_scroll, window, cx, |s| {
12447            if replace_newest {
12448                s.delete(s.newest_anchor().id);
12449            }
12450            if reversed {
12451                s.insert_range(range.end..range.start);
12452            } else {
12453                s.insert_range(range);
12454            }
12455        });
12456    }
12457
12458    pub fn select_next_match_internal(
12459        &mut self,
12460        display_map: &DisplaySnapshot,
12461        replace_newest: bool,
12462        autoscroll: Option<Autoscroll>,
12463        window: &mut Window,
12464        cx: &mut Context<Self>,
12465    ) -> Result<()> {
12466        let buffer = &display_map.buffer_snapshot;
12467        let mut selections = self.selections.all::<usize>(cx);
12468        if let Some(mut select_next_state) = self.select_next_state.take() {
12469            let query = &select_next_state.query;
12470            if !select_next_state.done {
12471                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12472                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12473                let mut next_selected_range = None;
12474
12475                let bytes_after_last_selection =
12476                    buffer.bytes_in_range(last_selection.end..buffer.len());
12477                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12478                let query_matches = query
12479                    .stream_find_iter(bytes_after_last_selection)
12480                    .map(|result| (last_selection.end, result))
12481                    .chain(
12482                        query
12483                            .stream_find_iter(bytes_before_first_selection)
12484                            .map(|result| (0, result)),
12485                    );
12486
12487                for (start_offset, query_match) in query_matches {
12488                    let query_match = query_match.unwrap(); // can only fail due to I/O
12489                    let offset_range =
12490                        start_offset + query_match.start()..start_offset + query_match.end();
12491                    let display_range = offset_range.start.to_display_point(display_map)
12492                        ..offset_range.end.to_display_point(display_map);
12493
12494                    if !select_next_state.wordwise
12495                        || (!movement::is_inside_word(display_map, display_range.start)
12496                            && !movement::is_inside_word(display_map, display_range.end))
12497                    {
12498                        // TODO: This is n^2, because we might check all the selections
12499                        if !selections
12500                            .iter()
12501                            .any(|selection| selection.range().overlaps(&offset_range))
12502                        {
12503                            next_selected_range = Some(offset_range);
12504                            break;
12505                        }
12506                    }
12507                }
12508
12509                if let Some(next_selected_range) = next_selected_range {
12510                    self.select_match_ranges(
12511                        next_selected_range,
12512                        last_selection.reversed,
12513                        replace_newest,
12514                        autoscroll,
12515                        window,
12516                        cx,
12517                    );
12518                } else {
12519                    select_next_state.done = true;
12520                }
12521            }
12522
12523            self.select_next_state = Some(select_next_state);
12524        } else {
12525            let mut only_carets = true;
12526            let mut same_text_selected = true;
12527            let mut selected_text = None;
12528
12529            let mut selections_iter = selections.iter().peekable();
12530            while let Some(selection) = selections_iter.next() {
12531                if selection.start != selection.end {
12532                    only_carets = false;
12533                }
12534
12535                if same_text_selected {
12536                    if selected_text.is_none() {
12537                        selected_text =
12538                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12539                    }
12540
12541                    if let Some(next_selection) = selections_iter.peek() {
12542                        if next_selection.range().len() == selection.range().len() {
12543                            let next_selected_text = buffer
12544                                .text_for_range(next_selection.range())
12545                                .collect::<String>();
12546                            if Some(next_selected_text) != selected_text {
12547                                same_text_selected = false;
12548                                selected_text = None;
12549                            }
12550                        } else {
12551                            same_text_selected = false;
12552                            selected_text = None;
12553                        }
12554                    }
12555                }
12556            }
12557
12558            if only_carets {
12559                for selection in &mut selections {
12560                    let word_range = movement::surrounding_word(
12561                        display_map,
12562                        selection.start.to_display_point(display_map),
12563                    );
12564                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12565                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12566                    selection.goal = SelectionGoal::None;
12567                    selection.reversed = false;
12568                    self.select_match_ranges(
12569                        selection.start..selection.end,
12570                        selection.reversed,
12571                        replace_newest,
12572                        autoscroll,
12573                        window,
12574                        cx,
12575                    );
12576                }
12577
12578                if selections.len() == 1 {
12579                    let selection = selections
12580                        .last()
12581                        .expect("ensured that there's only one selection");
12582                    let query = buffer
12583                        .text_for_range(selection.start..selection.end)
12584                        .collect::<String>();
12585                    let is_empty = query.is_empty();
12586                    let select_state = SelectNextState {
12587                        query: AhoCorasick::new(&[query])?,
12588                        wordwise: true,
12589                        done: is_empty,
12590                    };
12591                    self.select_next_state = Some(select_state);
12592                } else {
12593                    self.select_next_state = None;
12594                }
12595            } else if let Some(selected_text) = selected_text {
12596                self.select_next_state = Some(SelectNextState {
12597                    query: AhoCorasick::new(&[selected_text])?,
12598                    wordwise: false,
12599                    done: false,
12600                });
12601                self.select_next_match_internal(
12602                    display_map,
12603                    replace_newest,
12604                    autoscroll,
12605                    window,
12606                    cx,
12607                )?;
12608            }
12609        }
12610        Ok(())
12611    }
12612
12613    pub fn select_all_matches(
12614        &mut self,
12615        _action: &SelectAllMatches,
12616        window: &mut Window,
12617        cx: &mut Context<Self>,
12618    ) -> Result<()> {
12619        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12620
12621        self.push_to_selection_history();
12622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12623
12624        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12625        let Some(select_next_state) = self.select_next_state.as_mut() else {
12626            return Ok(());
12627        };
12628        if select_next_state.done {
12629            return Ok(());
12630        }
12631
12632        let mut new_selections = Vec::new();
12633
12634        let reversed = self.selections.oldest::<usize>(cx).reversed;
12635        let buffer = &display_map.buffer_snapshot;
12636        let query_matches = select_next_state
12637            .query
12638            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12639
12640        for query_match in query_matches.into_iter() {
12641            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12642            let offset_range = if reversed {
12643                query_match.end()..query_match.start()
12644            } else {
12645                query_match.start()..query_match.end()
12646            };
12647            let display_range = offset_range.start.to_display_point(&display_map)
12648                ..offset_range.end.to_display_point(&display_map);
12649
12650            if !select_next_state.wordwise
12651                || (!movement::is_inside_word(&display_map, display_range.start)
12652                    && !movement::is_inside_word(&display_map, display_range.end))
12653            {
12654                new_selections.push(offset_range.start..offset_range.end);
12655            }
12656        }
12657
12658        select_next_state.done = true;
12659        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12660        self.change_selections(None, window, cx, |selections| {
12661            selections.select_ranges(new_selections)
12662        });
12663
12664        Ok(())
12665    }
12666
12667    pub fn select_next(
12668        &mut self,
12669        action: &SelectNext,
12670        window: &mut Window,
12671        cx: &mut Context<Self>,
12672    ) -> Result<()> {
12673        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12674        self.push_to_selection_history();
12675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12676        self.select_next_match_internal(
12677            &display_map,
12678            action.replace_newest,
12679            Some(Autoscroll::newest()),
12680            window,
12681            cx,
12682        )?;
12683        Ok(())
12684    }
12685
12686    pub fn select_previous(
12687        &mut self,
12688        action: &SelectPrevious,
12689        window: &mut Window,
12690        cx: &mut Context<Self>,
12691    ) -> Result<()> {
12692        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12693        self.push_to_selection_history();
12694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12695        let buffer = &display_map.buffer_snapshot;
12696        let mut selections = self.selections.all::<usize>(cx);
12697        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12698            let query = &select_prev_state.query;
12699            if !select_prev_state.done {
12700                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12701                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12702                let mut next_selected_range = None;
12703                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12704                let bytes_before_last_selection =
12705                    buffer.reversed_bytes_in_range(0..last_selection.start);
12706                let bytes_after_first_selection =
12707                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12708                let query_matches = query
12709                    .stream_find_iter(bytes_before_last_selection)
12710                    .map(|result| (last_selection.start, result))
12711                    .chain(
12712                        query
12713                            .stream_find_iter(bytes_after_first_selection)
12714                            .map(|result| (buffer.len(), result)),
12715                    );
12716                for (end_offset, query_match) in query_matches {
12717                    let query_match = query_match.unwrap(); // can only fail due to I/O
12718                    let offset_range =
12719                        end_offset - query_match.end()..end_offset - query_match.start();
12720                    let display_range = offset_range.start.to_display_point(&display_map)
12721                        ..offset_range.end.to_display_point(&display_map);
12722
12723                    if !select_prev_state.wordwise
12724                        || (!movement::is_inside_word(&display_map, display_range.start)
12725                            && !movement::is_inside_word(&display_map, display_range.end))
12726                    {
12727                        next_selected_range = Some(offset_range);
12728                        break;
12729                    }
12730                }
12731
12732                if let Some(next_selected_range) = next_selected_range {
12733                    self.select_match_ranges(
12734                        next_selected_range,
12735                        last_selection.reversed,
12736                        action.replace_newest,
12737                        Some(Autoscroll::newest()),
12738                        window,
12739                        cx,
12740                    );
12741                } else {
12742                    select_prev_state.done = true;
12743                }
12744            }
12745
12746            self.select_prev_state = Some(select_prev_state);
12747        } else {
12748            let mut only_carets = true;
12749            let mut same_text_selected = true;
12750            let mut selected_text = None;
12751
12752            let mut selections_iter = selections.iter().peekable();
12753            while let Some(selection) = selections_iter.next() {
12754                if selection.start != selection.end {
12755                    only_carets = false;
12756                }
12757
12758                if same_text_selected {
12759                    if selected_text.is_none() {
12760                        selected_text =
12761                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12762                    }
12763
12764                    if let Some(next_selection) = selections_iter.peek() {
12765                        if next_selection.range().len() == selection.range().len() {
12766                            let next_selected_text = buffer
12767                                .text_for_range(next_selection.range())
12768                                .collect::<String>();
12769                            if Some(next_selected_text) != selected_text {
12770                                same_text_selected = false;
12771                                selected_text = None;
12772                            }
12773                        } else {
12774                            same_text_selected = false;
12775                            selected_text = None;
12776                        }
12777                    }
12778                }
12779            }
12780
12781            if only_carets {
12782                for selection in &mut selections {
12783                    let word_range = movement::surrounding_word(
12784                        &display_map,
12785                        selection.start.to_display_point(&display_map),
12786                    );
12787                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12788                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12789                    selection.goal = SelectionGoal::None;
12790                    selection.reversed = false;
12791                    self.select_match_ranges(
12792                        selection.start..selection.end,
12793                        selection.reversed,
12794                        action.replace_newest,
12795                        Some(Autoscroll::newest()),
12796                        window,
12797                        cx,
12798                    );
12799                }
12800                if selections.len() == 1 {
12801                    let selection = selections
12802                        .last()
12803                        .expect("ensured that there's only one selection");
12804                    let query = buffer
12805                        .text_for_range(selection.start..selection.end)
12806                        .collect::<String>();
12807                    let is_empty = query.is_empty();
12808                    let select_state = SelectNextState {
12809                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12810                        wordwise: true,
12811                        done: is_empty,
12812                    };
12813                    self.select_prev_state = Some(select_state);
12814                } else {
12815                    self.select_prev_state = None;
12816                }
12817            } else if let Some(selected_text) = selected_text {
12818                self.select_prev_state = Some(SelectNextState {
12819                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12820                    wordwise: false,
12821                    done: false,
12822                });
12823                self.select_previous(action, window, cx)?;
12824            }
12825        }
12826        Ok(())
12827    }
12828
12829    pub fn find_next_match(
12830        &mut self,
12831        _: &FindNextMatch,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) -> Result<()> {
12835        let selections = self.selections.disjoint_anchors();
12836        match selections.first() {
12837            Some(first) if selections.len() >= 2 => {
12838                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12839                    s.select_ranges([first.range()]);
12840                });
12841            }
12842            _ => self.select_next(
12843                &SelectNext {
12844                    replace_newest: true,
12845                },
12846                window,
12847                cx,
12848            )?,
12849        }
12850        Ok(())
12851    }
12852
12853    pub fn find_previous_match(
12854        &mut self,
12855        _: &FindPreviousMatch,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) -> Result<()> {
12859        let selections = self.selections.disjoint_anchors();
12860        match selections.last() {
12861            Some(last) if selections.len() >= 2 => {
12862                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12863                    s.select_ranges([last.range()]);
12864                });
12865            }
12866            _ => self.select_previous(
12867                &SelectPrevious {
12868                    replace_newest: true,
12869                },
12870                window,
12871                cx,
12872            )?,
12873        }
12874        Ok(())
12875    }
12876
12877    pub fn toggle_comments(
12878        &mut self,
12879        action: &ToggleComments,
12880        window: &mut Window,
12881        cx: &mut Context<Self>,
12882    ) {
12883        if self.read_only(cx) {
12884            return;
12885        }
12886        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12887        let text_layout_details = &self.text_layout_details(window);
12888        self.transact(window, cx, |this, window, cx| {
12889            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12890            let mut edits = Vec::new();
12891            let mut selection_edit_ranges = Vec::new();
12892            let mut last_toggled_row = None;
12893            let snapshot = this.buffer.read(cx).read(cx);
12894            let empty_str: Arc<str> = Arc::default();
12895            let mut suffixes_inserted = Vec::new();
12896            let ignore_indent = action.ignore_indent;
12897
12898            fn comment_prefix_range(
12899                snapshot: &MultiBufferSnapshot,
12900                row: MultiBufferRow,
12901                comment_prefix: &str,
12902                comment_prefix_whitespace: &str,
12903                ignore_indent: bool,
12904            ) -> Range<Point> {
12905                let indent_size = if ignore_indent {
12906                    0
12907                } else {
12908                    snapshot.indent_size_for_line(row).len
12909                };
12910
12911                let start = Point::new(row.0, indent_size);
12912
12913                let mut line_bytes = snapshot
12914                    .bytes_in_range(start..snapshot.max_point())
12915                    .flatten()
12916                    .copied();
12917
12918                // If this line currently begins with the line comment prefix, then record
12919                // the range containing the prefix.
12920                if line_bytes
12921                    .by_ref()
12922                    .take(comment_prefix.len())
12923                    .eq(comment_prefix.bytes())
12924                {
12925                    // Include any whitespace that matches the comment prefix.
12926                    let matching_whitespace_len = line_bytes
12927                        .zip(comment_prefix_whitespace.bytes())
12928                        .take_while(|(a, b)| a == b)
12929                        .count() as u32;
12930                    let end = Point::new(
12931                        start.row,
12932                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12933                    );
12934                    start..end
12935                } else {
12936                    start..start
12937                }
12938            }
12939
12940            fn comment_suffix_range(
12941                snapshot: &MultiBufferSnapshot,
12942                row: MultiBufferRow,
12943                comment_suffix: &str,
12944                comment_suffix_has_leading_space: bool,
12945            ) -> Range<Point> {
12946                let end = Point::new(row.0, snapshot.line_len(row));
12947                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12948
12949                let mut line_end_bytes = snapshot
12950                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12951                    .flatten()
12952                    .copied();
12953
12954                let leading_space_len = if suffix_start_column > 0
12955                    && line_end_bytes.next() == Some(b' ')
12956                    && comment_suffix_has_leading_space
12957                {
12958                    1
12959                } else {
12960                    0
12961                };
12962
12963                // If this line currently begins with the line comment prefix, then record
12964                // the range containing the prefix.
12965                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12966                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12967                    start..end
12968                } else {
12969                    end..end
12970                }
12971            }
12972
12973            // TODO: Handle selections that cross excerpts
12974            for selection in &mut selections {
12975                let start_column = snapshot
12976                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12977                    .len;
12978                let language = if let Some(language) =
12979                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12980                {
12981                    language
12982                } else {
12983                    continue;
12984                };
12985
12986                selection_edit_ranges.clear();
12987
12988                // If multiple selections contain a given row, avoid processing that
12989                // row more than once.
12990                let mut start_row = MultiBufferRow(selection.start.row);
12991                if last_toggled_row == Some(start_row) {
12992                    start_row = start_row.next_row();
12993                }
12994                let end_row =
12995                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12996                        MultiBufferRow(selection.end.row - 1)
12997                    } else {
12998                        MultiBufferRow(selection.end.row)
12999                    };
13000                last_toggled_row = Some(end_row);
13001
13002                if start_row > end_row {
13003                    continue;
13004                }
13005
13006                // If the language has line comments, toggle those.
13007                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13008
13009                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13010                if ignore_indent {
13011                    full_comment_prefixes = full_comment_prefixes
13012                        .into_iter()
13013                        .map(|s| Arc::from(s.trim_end()))
13014                        .collect();
13015                }
13016
13017                if !full_comment_prefixes.is_empty() {
13018                    let first_prefix = full_comment_prefixes
13019                        .first()
13020                        .expect("prefixes is non-empty");
13021                    let prefix_trimmed_lengths = full_comment_prefixes
13022                        .iter()
13023                        .map(|p| p.trim_end_matches(' ').len())
13024                        .collect::<SmallVec<[usize; 4]>>();
13025
13026                    let mut all_selection_lines_are_comments = true;
13027
13028                    for row in start_row.0..=end_row.0 {
13029                        let row = MultiBufferRow(row);
13030                        if start_row < end_row && snapshot.is_line_blank(row) {
13031                            continue;
13032                        }
13033
13034                        let prefix_range = full_comment_prefixes
13035                            .iter()
13036                            .zip(prefix_trimmed_lengths.iter().copied())
13037                            .map(|(prefix, trimmed_prefix_len)| {
13038                                comment_prefix_range(
13039                                    snapshot.deref(),
13040                                    row,
13041                                    &prefix[..trimmed_prefix_len],
13042                                    &prefix[trimmed_prefix_len..],
13043                                    ignore_indent,
13044                                )
13045                            })
13046                            .max_by_key(|range| range.end.column - range.start.column)
13047                            .expect("prefixes is non-empty");
13048
13049                        if prefix_range.is_empty() {
13050                            all_selection_lines_are_comments = false;
13051                        }
13052
13053                        selection_edit_ranges.push(prefix_range);
13054                    }
13055
13056                    if all_selection_lines_are_comments {
13057                        edits.extend(
13058                            selection_edit_ranges
13059                                .iter()
13060                                .cloned()
13061                                .map(|range| (range, empty_str.clone())),
13062                        );
13063                    } else {
13064                        let min_column = selection_edit_ranges
13065                            .iter()
13066                            .map(|range| range.start.column)
13067                            .min()
13068                            .unwrap_or(0);
13069                        edits.extend(selection_edit_ranges.iter().map(|range| {
13070                            let position = Point::new(range.start.row, min_column);
13071                            (position..position, first_prefix.clone())
13072                        }));
13073                    }
13074                } else if let Some((full_comment_prefix, comment_suffix)) =
13075                    language.block_comment_delimiters()
13076                {
13077                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13078                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13079                    let prefix_range = comment_prefix_range(
13080                        snapshot.deref(),
13081                        start_row,
13082                        comment_prefix,
13083                        comment_prefix_whitespace,
13084                        ignore_indent,
13085                    );
13086                    let suffix_range = comment_suffix_range(
13087                        snapshot.deref(),
13088                        end_row,
13089                        comment_suffix.trim_start_matches(' '),
13090                        comment_suffix.starts_with(' '),
13091                    );
13092
13093                    if prefix_range.is_empty() || suffix_range.is_empty() {
13094                        edits.push((
13095                            prefix_range.start..prefix_range.start,
13096                            full_comment_prefix.clone(),
13097                        ));
13098                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13099                        suffixes_inserted.push((end_row, comment_suffix.len()));
13100                    } else {
13101                        edits.push((prefix_range, empty_str.clone()));
13102                        edits.push((suffix_range, empty_str.clone()));
13103                    }
13104                } else {
13105                    continue;
13106                }
13107            }
13108
13109            drop(snapshot);
13110            this.buffer.update(cx, |buffer, cx| {
13111                buffer.edit(edits, None, cx);
13112            });
13113
13114            // Adjust selections so that they end before any comment suffixes that
13115            // were inserted.
13116            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13117            let mut selections = this.selections.all::<Point>(cx);
13118            let snapshot = this.buffer.read(cx).read(cx);
13119            for selection in &mut selections {
13120                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13121                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13122                        Ordering::Less => {
13123                            suffixes_inserted.next();
13124                            continue;
13125                        }
13126                        Ordering::Greater => break,
13127                        Ordering::Equal => {
13128                            if selection.end.column == snapshot.line_len(row) {
13129                                if selection.is_empty() {
13130                                    selection.start.column -= suffix_len as u32;
13131                                }
13132                                selection.end.column -= suffix_len as u32;
13133                            }
13134                            break;
13135                        }
13136                    }
13137                }
13138            }
13139
13140            drop(snapshot);
13141            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13142                s.select(selections)
13143            });
13144
13145            let selections = this.selections.all::<Point>(cx);
13146            let selections_on_single_row = selections.windows(2).all(|selections| {
13147                selections[0].start.row == selections[1].start.row
13148                    && selections[0].end.row == selections[1].end.row
13149                    && selections[0].start.row == selections[0].end.row
13150            });
13151            let selections_selecting = selections
13152                .iter()
13153                .any(|selection| selection.start != selection.end);
13154            let advance_downwards = action.advance_downwards
13155                && selections_on_single_row
13156                && !selections_selecting
13157                && !matches!(this.mode, EditorMode::SingleLine { .. });
13158
13159            if advance_downwards {
13160                let snapshot = this.buffer.read(cx).snapshot(cx);
13161
13162                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13163                    s.move_cursors_with(|display_snapshot, display_point, _| {
13164                        let mut point = display_point.to_point(display_snapshot);
13165                        point.row += 1;
13166                        point = snapshot.clip_point(point, Bias::Left);
13167                        let display_point = point.to_display_point(display_snapshot);
13168                        let goal = SelectionGoal::HorizontalPosition(
13169                            display_snapshot
13170                                .x_for_display_point(display_point, text_layout_details)
13171                                .into(),
13172                        );
13173                        (display_point, goal)
13174                    })
13175                });
13176            }
13177        });
13178    }
13179
13180    pub fn select_enclosing_symbol(
13181        &mut self,
13182        _: &SelectEnclosingSymbol,
13183        window: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13187
13188        let buffer = self.buffer.read(cx).snapshot(cx);
13189        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13190
13191        fn update_selection(
13192            selection: &Selection<usize>,
13193            buffer_snap: &MultiBufferSnapshot,
13194        ) -> Option<Selection<usize>> {
13195            let cursor = selection.head();
13196            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13197            for symbol in symbols.iter().rev() {
13198                let start = symbol.range.start.to_offset(buffer_snap);
13199                let end = symbol.range.end.to_offset(buffer_snap);
13200                let new_range = start..end;
13201                if start < selection.start || end > selection.end {
13202                    return Some(Selection {
13203                        id: selection.id,
13204                        start: new_range.start,
13205                        end: new_range.end,
13206                        goal: SelectionGoal::None,
13207                        reversed: selection.reversed,
13208                    });
13209                }
13210            }
13211            None
13212        }
13213
13214        let mut selected_larger_symbol = false;
13215        let new_selections = old_selections
13216            .iter()
13217            .map(|selection| match update_selection(selection, &buffer) {
13218                Some(new_selection) => {
13219                    if new_selection.range() != selection.range() {
13220                        selected_larger_symbol = true;
13221                    }
13222                    new_selection
13223                }
13224                None => selection.clone(),
13225            })
13226            .collect::<Vec<_>>();
13227
13228        if selected_larger_symbol {
13229            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13230                s.select(new_selections);
13231            });
13232        }
13233    }
13234
13235    pub fn select_larger_syntax_node(
13236        &mut self,
13237        _: &SelectLargerSyntaxNode,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        let Some(visible_row_count) = self.visible_row_count() else {
13242            return;
13243        };
13244        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13245        if old_selections.is_empty() {
13246            return;
13247        }
13248
13249        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13250
13251        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13252        let buffer = self.buffer.read(cx).snapshot(cx);
13253
13254        let mut selected_larger_node = false;
13255        let mut new_selections = old_selections
13256            .iter()
13257            .map(|selection| {
13258                let old_range = selection.start..selection.end;
13259
13260                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13261                    // manually select word at selection
13262                    if ["string_content", "inline"].contains(&node.kind()) {
13263                        let word_range = {
13264                            let display_point = buffer
13265                                .offset_to_point(old_range.start)
13266                                .to_display_point(&display_map);
13267                            let Range { start, end } =
13268                                movement::surrounding_word(&display_map, display_point);
13269                            start.to_point(&display_map).to_offset(&buffer)
13270                                ..end.to_point(&display_map).to_offset(&buffer)
13271                        };
13272                        // ignore if word is already selected
13273                        if !word_range.is_empty() && old_range != word_range {
13274                            let last_word_range = {
13275                                let display_point = buffer
13276                                    .offset_to_point(old_range.end)
13277                                    .to_display_point(&display_map);
13278                                let Range { start, end } =
13279                                    movement::surrounding_word(&display_map, display_point);
13280                                start.to_point(&display_map).to_offset(&buffer)
13281                                    ..end.to_point(&display_map).to_offset(&buffer)
13282                            };
13283                            // only select word if start and end point belongs to same word
13284                            if word_range == last_word_range {
13285                                selected_larger_node = true;
13286                                return Selection {
13287                                    id: selection.id,
13288                                    start: word_range.start,
13289                                    end: word_range.end,
13290                                    goal: SelectionGoal::None,
13291                                    reversed: selection.reversed,
13292                                };
13293                            }
13294                        }
13295                    }
13296                }
13297
13298                let mut new_range = old_range.clone();
13299                while let Some((_node, containing_range)) =
13300                    buffer.syntax_ancestor(new_range.clone())
13301                {
13302                    new_range = match containing_range {
13303                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13304                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13305                    };
13306                    if !display_map.intersects_fold(new_range.start)
13307                        && !display_map.intersects_fold(new_range.end)
13308                    {
13309                        break;
13310                    }
13311                }
13312
13313                selected_larger_node |= new_range != old_range;
13314                Selection {
13315                    id: selection.id,
13316                    start: new_range.start,
13317                    end: new_range.end,
13318                    goal: SelectionGoal::None,
13319                    reversed: selection.reversed,
13320                }
13321            })
13322            .collect::<Vec<_>>();
13323
13324        if !selected_larger_node {
13325            return; // don't put this call in the history
13326        }
13327
13328        // scroll based on transformation done to the last selection created by the user
13329        let (last_old, last_new) = old_selections
13330            .last()
13331            .zip(new_selections.last().cloned())
13332            .expect("old_selections isn't empty");
13333
13334        // revert selection
13335        let is_selection_reversed = {
13336            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13337            new_selections.last_mut().expect("checked above").reversed =
13338                should_newest_selection_be_reversed;
13339            should_newest_selection_be_reversed
13340        };
13341
13342        if selected_larger_node {
13343            self.select_syntax_node_history.disable_clearing = true;
13344            self.change_selections(None, window, cx, |s| {
13345                s.select(new_selections.clone());
13346            });
13347            self.select_syntax_node_history.disable_clearing = false;
13348        }
13349
13350        let start_row = last_new.start.to_display_point(&display_map).row().0;
13351        let end_row = last_new.end.to_display_point(&display_map).row().0;
13352        let selection_height = end_row - start_row + 1;
13353        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13354
13355        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13356        let scroll_behavior = if fits_on_the_screen {
13357            self.request_autoscroll(Autoscroll::fit(), cx);
13358            SelectSyntaxNodeScrollBehavior::FitSelection
13359        } else if is_selection_reversed {
13360            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13361            SelectSyntaxNodeScrollBehavior::CursorTop
13362        } else {
13363            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13364            SelectSyntaxNodeScrollBehavior::CursorBottom
13365        };
13366
13367        self.select_syntax_node_history.push((
13368            old_selections,
13369            scroll_behavior,
13370            is_selection_reversed,
13371        ));
13372    }
13373
13374    pub fn select_smaller_syntax_node(
13375        &mut self,
13376        _: &SelectSmallerSyntaxNode,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13381
13382        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13383            self.select_syntax_node_history.pop()
13384        {
13385            if let Some(selection) = selections.last_mut() {
13386                selection.reversed = is_selection_reversed;
13387            }
13388
13389            self.select_syntax_node_history.disable_clearing = true;
13390            self.change_selections(None, window, cx, |s| {
13391                s.select(selections.to_vec());
13392            });
13393            self.select_syntax_node_history.disable_clearing = false;
13394
13395            match scroll_behavior {
13396                SelectSyntaxNodeScrollBehavior::CursorTop => {
13397                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13398                }
13399                SelectSyntaxNodeScrollBehavior::FitSelection => {
13400                    self.request_autoscroll(Autoscroll::fit(), cx);
13401                }
13402                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13403                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13404                }
13405            }
13406        }
13407    }
13408
13409    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13410        if !EditorSettings::get_global(cx).gutter.runnables {
13411            self.clear_tasks();
13412            return Task::ready(());
13413        }
13414        let project = self.project.as_ref().map(Entity::downgrade);
13415        let task_sources = self.lsp_task_sources(cx);
13416        cx.spawn_in(window, async move |editor, cx| {
13417            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13418            let Some(project) = project.and_then(|p| p.upgrade()) else {
13419                return;
13420            };
13421            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13422                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13423            }) else {
13424                return;
13425            };
13426
13427            let hide_runnables = project
13428                .update(cx, |project, cx| {
13429                    // Do not display any test indicators in non-dev server remote projects.
13430                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13431                })
13432                .unwrap_or(true);
13433            if hide_runnables {
13434                return;
13435            }
13436            let new_rows =
13437                cx.background_spawn({
13438                    let snapshot = display_snapshot.clone();
13439                    async move {
13440                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13441                    }
13442                })
13443                    .await;
13444            let Ok(lsp_tasks) =
13445                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13446            else {
13447                return;
13448            };
13449            let lsp_tasks = lsp_tasks.await;
13450
13451            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13452                lsp_tasks
13453                    .into_iter()
13454                    .flat_map(|(kind, tasks)| {
13455                        tasks.into_iter().filter_map(move |(location, task)| {
13456                            Some((kind.clone(), location?, task))
13457                        })
13458                    })
13459                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13460                        let buffer = location.target.buffer;
13461                        let buffer_snapshot = buffer.read(cx).snapshot();
13462                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13463                            |(excerpt_id, snapshot, _)| {
13464                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13465                                    display_snapshot
13466                                        .buffer_snapshot
13467                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13468                                } else {
13469                                    None
13470                                }
13471                            },
13472                        );
13473                        if let Some(offset) = offset {
13474                            let task_buffer_range =
13475                                location.target.range.to_point(&buffer_snapshot);
13476                            let context_buffer_range =
13477                                task_buffer_range.to_offset(&buffer_snapshot);
13478                            let context_range = BufferOffset(context_buffer_range.start)
13479                                ..BufferOffset(context_buffer_range.end);
13480
13481                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13482                                .or_insert_with(|| RunnableTasks {
13483                                    templates: Vec::new(),
13484                                    offset,
13485                                    column: task_buffer_range.start.column,
13486                                    extra_variables: HashMap::default(),
13487                                    context_range,
13488                                })
13489                                .templates
13490                                .push((kind, task.original_task().clone()));
13491                        }
13492
13493                        acc
13494                    })
13495            }) else {
13496                return;
13497            };
13498
13499            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13500            editor
13501                .update(cx, |editor, _| {
13502                    editor.clear_tasks();
13503                    for (key, mut value) in rows {
13504                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13505                            value.templates.extend(lsp_tasks.templates);
13506                        }
13507
13508                        editor.insert_tasks(key, value);
13509                    }
13510                    for (key, value) in lsp_tasks_by_rows {
13511                        editor.insert_tasks(key, value);
13512                    }
13513                })
13514                .ok();
13515        })
13516    }
13517    fn fetch_runnable_ranges(
13518        snapshot: &DisplaySnapshot,
13519        range: Range<Anchor>,
13520    ) -> Vec<language::RunnableRange> {
13521        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13522    }
13523
13524    fn runnable_rows(
13525        project: Entity<Project>,
13526        snapshot: DisplaySnapshot,
13527        runnable_ranges: Vec<RunnableRange>,
13528        mut cx: AsyncWindowContext,
13529    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13530        runnable_ranges
13531            .into_iter()
13532            .filter_map(|mut runnable| {
13533                let tasks = cx
13534                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13535                    .ok()?;
13536                if tasks.is_empty() {
13537                    return None;
13538                }
13539
13540                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13541
13542                let row = snapshot
13543                    .buffer_snapshot
13544                    .buffer_line_for_row(MultiBufferRow(point.row))?
13545                    .1
13546                    .start
13547                    .row;
13548
13549                let context_range =
13550                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13551                Some((
13552                    (runnable.buffer_id, row),
13553                    RunnableTasks {
13554                        templates: tasks,
13555                        offset: snapshot
13556                            .buffer_snapshot
13557                            .anchor_before(runnable.run_range.start),
13558                        context_range,
13559                        column: point.column,
13560                        extra_variables: runnable.extra_captures,
13561                    },
13562                ))
13563            })
13564            .collect()
13565    }
13566
13567    fn templates_with_tags(
13568        project: &Entity<Project>,
13569        runnable: &mut Runnable,
13570        cx: &mut App,
13571    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13572        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13573            let (worktree_id, file) = project
13574                .buffer_for_id(runnable.buffer, cx)
13575                .and_then(|buffer| buffer.read(cx).file())
13576                .map(|file| (file.worktree_id(cx), file.clone()))
13577                .unzip();
13578
13579            (
13580                project.task_store().read(cx).task_inventory().cloned(),
13581                worktree_id,
13582                file,
13583            )
13584        });
13585
13586        let mut templates_with_tags = mem::take(&mut runnable.tags)
13587            .into_iter()
13588            .flat_map(|RunnableTag(tag)| {
13589                inventory
13590                    .as_ref()
13591                    .into_iter()
13592                    .flat_map(|inventory| {
13593                        inventory.read(cx).list_tasks(
13594                            file.clone(),
13595                            Some(runnable.language.clone()),
13596                            worktree_id,
13597                            cx,
13598                        )
13599                    })
13600                    .filter(move |(_, template)| {
13601                        template.tags.iter().any(|source_tag| source_tag == &tag)
13602                    })
13603            })
13604            .sorted_by_key(|(kind, _)| kind.to_owned())
13605            .collect::<Vec<_>>();
13606        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13607            // Strongest source wins; if we have worktree tag binding, prefer that to
13608            // global and language bindings;
13609            // if we have a global binding, prefer that to language binding.
13610            let first_mismatch = templates_with_tags
13611                .iter()
13612                .position(|(tag_source, _)| tag_source != leading_tag_source);
13613            if let Some(index) = first_mismatch {
13614                templates_with_tags.truncate(index);
13615            }
13616        }
13617
13618        templates_with_tags
13619    }
13620
13621    pub fn move_to_enclosing_bracket(
13622        &mut self,
13623        _: &MoveToEnclosingBracket,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13628        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13629            s.move_offsets_with(|snapshot, selection| {
13630                let Some(enclosing_bracket_ranges) =
13631                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13632                else {
13633                    return;
13634                };
13635
13636                let mut best_length = usize::MAX;
13637                let mut best_inside = false;
13638                let mut best_in_bracket_range = false;
13639                let mut best_destination = None;
13640                for (open, close) in enclosing_bracket_ranges {
13641                    let close = close.to_inclusive();
13642                    let length = close.end() - open.start;
13643                    let inside = selection.start >= open.end && selection.end <= *close.start();
13644                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13645                        || close.contains(&selection.head());
13646
13647                    // If best is next to a bracket and current isn't, skip
13648                    if !in_bracket_range && best_in_bracket_range {
13649                        continue;
13650                    }
13651
13652                    // Prefer smaller lengths unless best is inside and current isn't
13653                    if length > best_length && (best_inside || !inside) {
13654                        continue;
13655                    }
13656
13657                    best_length = length;
13658                    best_inside = inside;
13659                    best_in_bracket_range = in_bracket_range;
13660                    best_destination = Some(
13661                        if close.contains(&selection.start) && close.contains(&selection.end) {
13662                            if inside { open.end } else { open.start }
13663                        } else if inside {
13664                            *close.start()
13665                        } else {
13666                            *close.end()
13667                        },
13668                    );
13669                }
13670
13671                if let Some(destination) = best_destination {
13672                    selection.collapse_to(destination, SelectionGoal::None);
13673                }
13674            })
13675        });
13676    }
13677
13678    pub fn undo_selection(
13679        &mut self,
13680        _: &UndoSelection,
13681        window: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13685        self.end_selection(window, cx);
13686        self.selection_history.mode = SelectionHistoryMode::Undoing;
13687        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13688            self.change_selections(None, window, cx, |s| {
13689                s.select_anchors(entry.selections.to_vec())
13690            });
13691            self.select_next_state = entry.select_next_state;
13692            self.select_prev_state = entry.select_prev_state;
13693            self.add_selections_state = entry.add_selections_state;
13694            self.request_autoscroll(Autoscroll::newest(), cx);
13695        }
13696        self.selection_history.mode = SelectionHistoryMode::Normal;
13697    }
13698
13699    pub fn redo_selection(
13700        &mut self,
13701        _: &RedoSelection,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13706        self.end_selection(window, cx);
13707        self.selection_history.mode = SelectionHistoryMode::Redoing;
13708        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13709            self.change_selections(None, window, cx, |s| {
13710                s.select_anchors(entry.selections.to_vec())
13711            });
13712            self.select_next_state = entry.select_next_state;
13713            self.select_prev_state = entry.select_prev_state;
13714            self.add_selections_state = entry.add_selections_state;
13715            self.request_autoscroll(Autoscroll::newest(), cx);
13716        }
13717        self.selection_history.mode = SelectionHistoryMode::Normal;
13718    }
13719
13720    pub fn expand_excerpts(
13721        &mut self,
13722        action: &ExpandExcerpts,
13723        _: &mut Window,
13724        cx: &mut Context<Self>,
13725    ) {
13726        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13727    }
13728
13729    pub fn expand_excerpts_down(
13730        &mut self,
13731        action: &ExpandExcerptsDown,
13732        _: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13736    }
13737
13738    pub fn expand_excerpts_up(
13739        &mut self,
13740        action: &ExpandExcerptsUp,
13741        _: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13745    }
13746
13747    pub fn expand_excerpts_for_direction(
13748        &mut self,
13749        lines: u32,
13750        direction: ExpandExcerptDirection,
13751
13752        cx: &mut Context<Self>,
13753    ) {
13754        let selections = self.selections.disjoint_anchors();
13755
13756        let lines = if lines == 0 {
13757            EditorSettings::get_global(cx).expand_excerpt_lines
13758        } else {
13759            lines
13760        };
13761
13762        self.buffer.update(cx, |buffer, cx| {
13763            let snapshot = buffer.snapshot(cx);
13764            let mut excerpt_ids = selections
13765                .iter()
13766                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13767                .collect::<Vec<_>>();
13768            excerpt_ids.sort();
13769            excerpt_ids.dedup();
13770            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13771        })
13772    }
13773
13774    pub fn expand_excerpt(
13775        &mut self,
13776        excerpt: ExcerptId,
13777        direction: ExpandExcerptDirection,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        let current_scroll_position = self.scroll_position(cx);
13782        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13783        let mut should_scroll_up = false;
13784
13785        if direction == ExpandExcerptDirection::Down {
13786            let multi_buffer = self.buffer.read(cx);
13787            let snapshot = multi_buffer.snapshot(cx);
13788            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13789                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13790                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13791                        let buffer_snapshot = buffer.read(cx).snapshot();
13792                        let excerpt_end_row =
13793                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13794                        let last_row = buffer_snapshot.max_point().row;
13795                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13796                        should_scroll_up = lines_below >= lines_to_expand;
13797                    }
13798                }
13799            }
13800        }
13801
13802        self.buffer.update(cx, |buffer, cx| {
13803            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13804        });
13805
13806        if should_scroll_up {
13807            let new_scroll_position =
13808                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13809            self.set_scroll_position(new_scroll_position, window, cx);
13810        }
13811    }
13812
13813    pub fn go_to_singleton_buffer_point(
13814        &mut self,
13815        point: Point,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) {
13819        self.go_to_singleton_buffer_range(point..point, window, cx);
13820    }
13821
13822    pub fn go_to_singleton_buffer_range(
13823        &mut self,
13824        range: Range<Point>,
13825        window: &mut Window,
13826        cx: &mut Context<Self>,
13827    ) {
13828        let multibuffer = self.buffer().read(cx);
13829        let Some(buffer) = multibuffer.as_singleton() else {
13830            return;
13831        };
13832        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13833            return;
13834        };
13835        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13836            return;
13837        };
13838        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13839            s.select_anchor_ranges([start..end])
13840        });
13841    }
13842
13843    pub fn go_to_diagnostic(
13844        &mut self,
13845        _: &GoToDiagnostic,
13846        window: &mut Window,
13847        cx: &mut Context<Self>,
13848    ) {
13849        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13850        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13851    }
13852
13853    pub fn go_to_prev_diagnostic(
13854        &mut self,
13855        _: &GoToPreviousDiagnostic,
13856        window: &mut Window,
13857        cx: &mut Context<Self>,
13858    ) {
13859        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13860        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13861    }
13862
13863    pub fn go_to_diagnostic_impl(
13864        &mut self,
13865        direction: Direction,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        let buffer = self.buffer.read(cx).snapshot(cx);
13870        let selection = self.selections.newest::<usize>(cx);
13871
13872        let mut active_group_id = None;
13873        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13874            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13875                active_group_id = Some(active_group.group_id);
13876            }
13877        }
13878
13879        fn filtered(
13880            snapshot: EditorSnapshot,
13881            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13882        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13883            diagnostics
13884                .filter(|entry| entry.range.start != entry.range.end)
13885                .filter(|entry| !entry.diagnostic.is_unnecessary)
13886                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13887        }
13888
13889        let snapshot = self.snapshot(window, cx);
13890        let before = filtered(
13891            snapshot.clone(),
13892            buffer
13893                .diagnostics_in_range(0..selection.start)
13894                .filter(|entry| entry.range.start <= selection.start),
13895        );
13896        let after = filtered(
13897            snapshot,
13898            buffer
13899                .diagnostics_in_range(selection.start..buffer.len())
13900                .filter(|entry| entry.range.start >= selection.start),
13901        );
13902
13903        let mut found: Option<DiagnosticEntry<usize>> = None;
13904        if direction == Direction::Prev {
13905            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13906            {
13907                for diagnostic in prev_diagnostics.into_iter().rev() {
13908                    if diagnostic.range.start != selection.start
13909                        || active_group_id
13910                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13911                    {
13912                        found = Some(diagnostic);
13913                        break 'outer;
13914                    }
13915                }
13916            }
13917        } else {
13918            for diagnostic in after.chain(before) {
13919                if diagnostic.range.start != selection.start
13920                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13921                {
13922                    found = Some(diagnostic);
13923                    break;
13924                }
13925            }
13926        }
13927        let Some(next_diagnostic) = found else {
13928            return;
13929        };
13930
13931        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13932            return;
13933        };
13934        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13935            s.select_ranges(vec![
13936                next_diagnostic.range.start..next_diagnostic.range.start,
13937            ])
13938        });
13939        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13940        self.refresh_inline_completion(false, true, window, cx);
13941    }
13942
13943    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13944        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13945        let snapshot = self.snapshot(window, cx);
13946        let selection = self.selections.newest::<Point>(cx);
13947        self.go_to_hunk_before_or_after_position(
13948            &snapshot,
13949            selection.head(),
13950            Direction::Next,
13951            window,
13952            cx,
13953        );
13954    }
13955
13956    pub fn go_to_hunk_before_or_after_position(
13957        &mut self,
13958        snapshot: &EditorSnapshot,
13959        position: Point,
13960        direction: Direction,
13961        window: &mut Window,
13962        cx: &mut Context<Editor>,
13963    ) {
13964        let row = if direction == Direction::Next {
13965            self.hunk_after_position(snapshot, position)
13966                .map(|hunk| hunk.row_range.start)
13967        } else {
13968            self.hunk_before_position(snapshot, position)
13969        };
13970
13971        if let Some(row) = row {
13972            let destination = Point::new(row.0, 0);
13973            let autoscroll = Autoscroll::center();
13974
13975            self.unfold_ranges(&[destination..destination], false, false, cx);
13976            self.change_selections(Some(autoscroll), window, cx, |s| {
13977                s.select_ranges([destination..destination]);
13978            });
13979        }
13980    }
13981
13982    fn hunk_after_position(
13983        &mut self,
13984        snapshot: &EditorSnapshot,
13985        position: Point,
13986    ) -> Option<MultiBufferDiffHunk> {
13987        snapshot
13988            .buffer_snapshot
13989            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13990            .find(|hunk| hunk.row_range.start.0 > position.row)
13991            .or_else(|| {
13992                snapshot
13993                    .buffer_snapshot
13994                    .diff_hunks_in_range(Point::zero()..position)
13995                    .find(|hunk| hunk.row_range.end.0 < position.row)
13996            })
13997    }
13998
13999    fn go_to_prev_hunk(
14000        &mut self,
14001        _: &GoToPreviousHunk,
14002        window: &mut Window,
14003        cx: &mut Context<Self>,
14004    ) {
14005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14006        let snapshot = self.snapshot(window, cx);
14007        let selection = self.selections.newest::<Point>(cx);
14008        self.go_to_hunk_before_or_after_position(
14009            &snapshot,
14010            selection.head(),
14011            Direction::Prev,
14012            window,
14013            cx,
14014        );
14015    }
14016
14017    fn hunk_before_position(
14018        &mut self,
14019        snapshot: &EditorSnapshot,
14020        position: Point,
14021    ) -> Option<MultiBufferRow> {
14022        snapshot
14023            .buffer_snapshot
14024            .diff_hunk_before(position)
14025            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14026    }
14027
14028    fn go_to_next_change(
14029        &mut self,
14030        _: &GoToNextChange,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        if let Some(selections) = self
14035            .change_list
14036            .next_change(1, Direction::Next)
14037            .map(|s| s.to_vec())
14038        {
14039            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14040                let map = s.display_map();
14041                s.select_display_ranges(selections.iter().map(|a| {
14042                    let point = a.to_display_point(&map);
14043                    point..point
14044                }))
14045            })
14046        }
14047    }
14048
14049    fn go_to_previous_change(
14050        &mut self,
14051        _: &GoToPreviousChange,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        if let Some(selections) = self
14056            .change_list
14057            .next_change(1, Direction::Prev)
14058            .map(|s| s.to_vec())
14059        {
14060            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14061                let map = s.display_map();
14062                s.select_display_ranges(selections.iter().map(|a| {
14063                    let point = a.to_display_point(&map);
14064                    point..point
14065                }))
14066            })
14067        }
14068    }
14069
14070    fn go_to_line<T: 'static>(
14071        &mut self,
14072        position: Anchor,
14073        highlight_color: Option<Hsla>,
14074        window: &mut Window,
14075        cx: &mut Context<Self>,
14076    ) {
14077        let snapshot = self.snapshot(window, cx).display_snapshot;
14078        let position = position.to_point(&snapshot.buffer_snapshot);
14079        let start = snapshot
14080            .buffer_snapshot
14081            .clip_point(Point::new(position.row, 0), Bias::Left);
14082        let end = start + Point::new(1, 0);
14083        let start = snapshot.buffer_snapshot.anchor_before(start);
14084        let end = snapshot.buffer_snapshot.anchor_before(end);
14085
14086        self.highlight_rows::<T>(
14087            start..end,
14088            highlight_color
14089                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14090            Default::default(),
14091            cx,
14092        );
14093
14094        if self.buffer.read(cx).is_singleton() {
14095            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14096        }
14097    }
14098
14099    pub fn go_to_definition(
14100        &mut self,
14101        _: &GoToDefinition,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) -> Task<Result<Navigated>> {
14105        let definition =
14106            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14107        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14108        cx.spawn_in(window, async move |editor, cx| {
14109            if definition.await? == Navigated::Yes {
14110                return Ok(Navigated::Yes);
14111            }
14112            match fallback_strategy {
14113                GoToDefinitionFallback::None => Ok(Navigated::No),
14114                GoToDefinitionFallback::FindAllReferences => {
14115                    match editor.update_in(cx, |editor, window, cx| {
14116                        editor.find_all_references(&FindAllReferences, window, cx)
14117                    })? {
14118                        Some(references) => references.await,
14119                        None => Ok(Navigated::No),
14120                    }
14121                }
14122            }
14123        })
14124    }
14125
14126    pub fn go_to_declaration(
14127        &mut self,
14128        _: &GoToDeclaration,
14129        window: &mut Window,
14130        cx: &mut Context<Self>,
14131    ) -> Task<Result<Navigated>> {
14132        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14133    }
14134
14135    pub fn go_to_declaration_split(
14136        &mut self,
14137        _: &GoToDeclaration,
14138        window: &mut Window,
14139        cx: &mut Context<Self>,
14140    ) -> Task<Result<Navigated>> {
14141        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14142    }
14143
14144    pub fn go_to_implementation(
14145        &mut self,
14146        _: &GoToImplementation,
14147        window: &mut Window,
14148        cx: &mut Context<Self>,
14149    ) -> Task<Result<Navigated>> {
14150        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14151    }
14152
14153    pub fn go_to_implementation_split(
14154        &mut self,
14155        _: &GoToImplementationSplit,
14156        window: &mut Window,
14157        cx: &mut Context<Self>,
14158    ) -> Task<Result<Navigated>> {
14159        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14160    }
14161
14162    pub fn go_to_type_definition(
14163        &mut self,
14164        _: &GoToTypeDefinition,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) -> Task<Result<Navigated>> {
14168        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14169    }
14170
14171    pub fn go_to_definition_split(
14172        &mut self,
14173        _: &GoToDefinitionSplit,
14174        window: &mut Window,
14175        cx: &mut Context<Self>,
14176    ) -> Task<Result<Navigated>> {
14177        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14178    }
14179
14180    pub fn go_to_type_definition_split(
14181        &mut self,
14182        _: &GoToTypeDefinitionSplit,
14183        window: &mut Window,
14184        cx: &mut Context<Self>,
14185    ) -> Task<Result<Navigated>> {
14186        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14187    }
14188
14189    fn go_to_definition_of_kind(
14190        &mut self,
14191        kind: GotoDefinitionKind,
14192        split: bool,
14193        window: &mut Window,
14194        cx: &mut Context<Self>,
14195    ) -> Task<Result<Navigated>> {
14196        let Some(provider) = self.semantics_provider.clone() else {
14197            return Task::ready(Ok(Navigated::No));
14198        };
14199        let head = self.selections.newest::<usize>(cx).head();
14200        let buffer = self.buffer.read(cx);
14201        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14202            text_anchor
14203        } else {
14204            return Task::ready(Ok(Navigated::No));
14205        };
14206
14207        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14208            return Task::ready(Ok(Navigated::No));
14209        };
14210
14211        cx.spawn_in(window, async move |editor, cx| {
14212            let definitions = definitions.await?;
14213            let navigated = editor
14214                .update_in(cx, |editor, window, cx| {
14215                    editor.navigate_to_hover_links(
14216                        Some(kind),
14217                        definitions
14218                            .into_iter()
14219                            .filter(|location| {
14220                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14221                            })
14222                            .map(HoverLink::Text)
14223                            .collect::<Vec<_>>(),
14224                        split,
14225                        window,
14226                        cx,
14227                    )
14228                })?
14229                .await?;
14230            anyhow::Ok(navigated)
14231        })
14232    }
14233
14234    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14235        let selection = self.selections.newest_anchor();
14236        let head = selection.head();
14237        let tail = selection.tail();
14238
14239        let Some((buffer, start_position)) =
14240            self.buffer.read(cx).text_anchor_for_position(head, cx)
14241        else {
14242            return;
14243        };
14244
14245        let end_position = if head != tail {
14246            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14247                return;
14248            };
14249            Some(pos)
14250        } else {
14251            None
14252        };
14253
14254        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14255            let url = if let Some(end_pos) = end_position {
14256                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14257            } else {
14258                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14259            };
14260
14261            if let Some(url) = url {
14262                editor.update(cx, |_, cx| {
14263                    cx.open_url(&url);
14264                })
14265            } else {
14266                Ok(())
14267            }
14268        });
14269
14270        url_finder.detach();
14271    }
14272
14273    pub fn open_selected_filename(
14274        &mut self,
14275        _: &OpenSelectedFilename,
14276        window: &mut Window,
14277        cx: &mut Context<Self>,
14278    ) {
14279        let Some(workspace) = self.workspace() else {
14280            return;
14281        };
14282
14283        let position = self.selections.newest_anchor().head();
14284
14285        let Some((buffer, buffer_position)) =
14286            self.buffer.read(cx).text_anchor_for_position(position, cx)
14287        else {
14288            return;
14289        };
14290
14291        let project = self.project.clone();
14292
14293        cx.spawn_in(window, async move |_, cx| {
14294            let result = find_file(&buffer, project, buffer_position, cx).await;
14295
14296            if let Some((_, path)) = result {
14297                workspace
14298                    .update_in(cx, |workspace, window, cx| {
14299                        workspace.open_resolved_path(path, window, cx)
14300                    })?
14301                    .await?;
14302            }
14303            anyhow::Ok(())
14304        })
14305        .detach();
14306    }
14307
14308    pub(crate) fn navigate_to_hover_links(
14309        &mut self,
14310        kind: Option<GotoDefinitionKind>,
14311        mut definitions: Vec<HoverLink>,
14312        split: bool,
14313        window: &mut Window,
14314        cx: &mut Context<Editor>,
14315    ) -> Task<Result<Navigated>> {
14316        // If there is one definition, just open it directly
14317        if definitions.len() == 1 {
14318            let definition = definitions.pop().unwrap();
14319
14320            enum TargetTaskResult {
14321                Location(Option<Location>),
14322                AlreadyNavigated,
14323            }
14324
14325            let target_task = match definition {
14326                HoverLink::Text(link) => {
14327                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14328                }
14329                HoverLink::InlayHint(lsp_location, server_id) => {
14330                    let computation =
14331                        self.compute_target_location(lsp_location, server_id, window, cx);
14332                    cx.background_spawn(async move {
14333                        let location = computation.await?;
14334                        Ok(TargetTaskResult::Location(location))
14335                    })
14336                }
14337                HoverLink::Url(url) => {
14338                    cx.open_url(&url);
14339                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14340                }
14341                HoverLink::File(path) => {
14342                    if let Some(workspace) = self.workspace() {
14343                        cx.spawn_in(window, async move |_, cx| {
14344                            workspace
14345                                .update_in(cx, |workspace, window, cx| {
14346                                    workspace.open_resolved_path(path, window, cx)
14347                                })?
14348                                .await
14349                                .map(|_| TargetTaskResult::AlreadyNavigated)
14350                        })
14351                    } else {
14352                        Task::ready(Ok(TargetTaskResult::Location(None)))
14353                    }
14354                }
14355            };
14356            cx.spawn_in(window, async move |editor, cx| {
14357                let target = match target_task.await.context("target resolution task")? {
14358                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14359                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14360                    TargetTaskResult::Location(Some(target)) => target,
14361                };
14362
14363                editor.update_in(cx, |editor, window, cx| {
14364                    let Some(workspace) = editor.workspace() else {
14365                        return Navigated::No;
14366                    };
14367                    let pane = workspace.read(cx).active_pane().clone();
14368
14369                    let range = target.range.to_point(target.buffer.read(cx));
14370                    let range = editor.range_for_match(&range);
14371                    let range = collapse_multiline_range(range);
14372
14373                    if !split
14374                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14375                    {
14376                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14377                    } else {
14378                        window.defer(cx, move |window, cx| {
14379                            let target_editor: Entity<Self> =
14380                                workspace.update(cx, |workspace, cx| {
14381                                    let pane = if split {
14382                                        workspace.adjacent_pane(window, cx)
14383                                    } else {
14384                                        workspace.active_pane().clone()
14385                                    };
14386
14387                                    workspace.open_project_item(
14388                                        pane,
14389                                        target.buffer.clone(),
14390                                        true,
14391                                        true,
14392                                        window,
14393                                        cx,
14394                                    )
14395                                });
14396                            target_editor.update(cx, |target_editor, cx| {
14397                                // When selecting a definition in a different buffer, disable the nav history
14398                                // to avoid creating a history entry at the previous cursor location.
14399                                pane.update(cx, |pane, _| pane.disable_history());
14400                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14401                                pane.update(cx, |pane, _| pane.enable_history());
14402                            });
14403                        });
14404                    }
14405                    Navigated::Yes
14406                })
14407            })
14408        } else if !definitions.is_empty() {
14409            cx.spawn_in(window, async move |editor, cx| {
14410                let (title, location_tasks, workspace) = editor
14411                    .update_in(cx, |editor, window, cx| {
14412                        let tab_kind = match kind {
14413                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14414                            _ => "Definitions",
14415                        };
14416                        let title = definitions
14417                            .iter()
14418                            .find_map(|definition| match definition {
14419                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14420                                    let buffer = origin.buffer.read(cx);
14421                                    format!(
14422                                        "{} for {}",
14423                                        tab_kind,
14424                                        buffer
14425                                            .text_for_range(origin.range.clone())
14426                                            .collect::<String>()
14427                                    )
14428                                }),
14429                                HoverLink::InlayHint(_, _) => None,
14430                                HoverLink::Url(_) => None,
14431                                HoverLink::File(_) => None,
14432                            })
14433                            .unwrap_or(tab_kind.to_string());
14434                        let location_tasks = definitions
14435                            .into_iter()
14436                            .map(|definition| match definition {
14437                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14438                                HoverLink::InlayHint(lsp_location, server_id) => editor
14439                                    .compute_target_location(lsp_location, server_id, window, cx),
14440                                HoverLink::Url(_) => Task::ready(Ok(None)),
14441                                HoverLink::File(_) => Task::ready(Ok(None)),
14442                            })
14443                            .collect::<Vec<_>>();
14444                        (title, location_tasks, editor.workspace().clone())
14445                    })
14446                    .context("location tasks preparation")?;
14447
14448                let locations = future::join_all(location_tasks)
14449                    .await
14450                    .into_iter()
14451                    .filter_map(|location| location.transpose())
14452                    .collect::<Result<_>>()
14453                    .context("location tasks")?;
14454
14455                let Some(workspace) = workspace else {
14456                    return Ok(Navigated::No);
14457                };
14458                let opened = workspace
14459                    .update_in(cx, |workspace, window, cx| {
14460                        Self::open_locations_in_multibuffer(
14461                            workspace,
14462                            locations,
14463                            title,
14464                            split,
14465                            MultibufferSelectionMode::First,
14466                            window,
14467                            cx,
14468                        )
14469                    })
14470                    .ok();
14471
14472                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14473            })
14474        } else {
14475            Task::ready(Ok(Navigated::No))
14476        }
14477    }
14478
14479    fn compute_target_location(
14480        &self,
14481        lsp_location: lsp::Location,
14482        server_id: LanguageServerId,
14483        window: &mut Window,
14484        cx: &mut Context<Self>,
14485    ) -> Task<anyhow::Result<Option<Location>>> {
14486        let Some(project) = self.project.clone() else {
14487            return Task::ready(Ok(None));
14488        };
14489
14490        cx.spawn_in(window, async move |editor, cx| {
14491            let location_task = editor.update(cx, |_, cx| {
14492                project.update(cx, |project, cx| {
14493                    let language_server_name = project
14494                        .language_server_statuses(cx)
14495                        .find(|(id, _)| server_id == *id)
14496                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14497                    language_server_name.map(|language_server_name| {
14498                        project.open_local_buffer_via_lsp(
14499                            lsp_location.uri.clone(),
14500                            server_id,
14501                            language_server_name,
14502                            cx,
14503                        )
14504                    })
14505                })
14506            })?;
14507            let location = match location_task {
14508                Some(task) => Some({
14509                    let target_buffer_handle = task.await.context("open local buffer")?;
14510                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14511                        let target_start = target_buffer
14512                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14513                        let target_end = target_buffer
14514                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14515                        target_buffer.anchor_after(target_start)
14516                            ..target_buffer.anchor_before(target_end)
14517                    })?;
14518                    Location {
14519                        buffer: target_buffer_handle,
14520                        range,
14521                    }
14522                }),
14523                None => None,
14524            };
14525            Ok(location)
14526        })
14527    }
14528
14529    pub fn find_all_references(
14530        &mut self,
14531        _: &FindAllReferences,
14532        window: &mut Window,
14533        cx: &mut Context<Self>,
14534    ) -> Option<Task<Result<Navigated>>> {
14535        let selection = self.selections.newest::<usize>(cx);
14536        let multi_buffer = self.buffer.read(cx);
14537        let head = selection.head();
14538
14539        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14540        let head_anchor = multi_buffer_snapshot.anchor_at(
14541            head,
14542            if head < selection.tail() {
14543                Bias::Right
14544            } else {
14545                Bias::Left
14546            },
14547        );
14548
14549        match self
14550            .find_all_references_task_sources
14551            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14552        {
14553            Ok(_) => {
14554                log::info!(
14555                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14556                );
14557                return None;
14558            }
14559            Err(i) => {
14560                self.find_all_references_task_sources.insert(i, head_anchor);
14561            }
14562        }
14563
14564        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14565        let workspace = self.workspace()?;
14566        let project = workspace.read(cx).project().clone();
14567        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14568        Some(cx.spawn_in(window, async move |editor, cx| {
14569            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14570                if let Ok(i) = editor
14571                    .find_all_references_task_sources
14572                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14573                {
14574                    editor.find_all_references_task_sources.remove(i);
14575                }
14576            });
14577
14578            let locations = references.await?;
14579            if locations.is_empty() {
14580                return anyhow::Ok(Navigated::No);
14581            }
14582
14583            workspace.update_in(cx, |workspace, window, cx| {
14584                let title = locations
14585                    .first()
14586                    .as_ref()
14587                    .map(|location| {
14588                        let buffer = location.buffer.read(cx);
14589                        format!(
14590                            "References to `{}`",
14591                            buffer
14592                                .text_for_range(location.range.clone())
14593                                .collect::<String>()
14594                        )
14595                    })
14596                    .unwrap();
14597                Self::open_locations_in_multibuffer(
14598                    workspace,
14599                    locations,
14600                    title,
14601                    false,
14602                    MultibufferSelectionMode::First,
14603                    window,
14604                    cx,
14605                );
14606                Navigated::Yes
14607            })
14608        }))
14609    }
14610
14611    /// Opens a multibuffer with the given project locations in it
14612    pub fn open_locations_in_multibuffer(
14613        workspace: &mut Workspace,
14614        mut locations: Vec<Location>,
14615        title: String,
14616        split: bool,
14617        multibuffer_selection_mode: MultibufferSelectionMode,
14618        window: &mut Window,
14619        cx: &mut Context<Workspace>,
14620    ) {
14621        // If there are multiple definitions, open them in a multibuffer
14622        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14623        let mut locations = locations.into_iter().peekable();
14624        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14625        let capability = workspace.project().read(cx).capability();
14626
14627        let excerpt_buffer = cx.new(|cx| {
14628            let mut multibuffer = MultiBuffer::new(capability);
14629            while let Some(location) = locations.next() {
14630                let buffer = location.buffer.read(cx);
14631                let mut ranges_for_buffer = Vec::new();
14632                let range = location.range.to_point(buffer);
14633                ranges_for_buffer.push(range.clone());
14634
14635                while let Some(next_location) = locations.peek() {
14636                    if next_location.buffer == location.buffer {
14637                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14638                        locations.next();
14639                    } else {
14640                        break;
14641                    }
14642                }
14643
14644                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14645                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14646                    PathKey::for_buffer(&location.buffer, cx),
14647                    location.buffer.clone(),
14648                    ranges_for_buffer,
14649                    DEFAULT_MULTIBUFFER_CONTEXT,
14650                    cx,
14651                );
14652                ranges.extend(new_ranges)
14653            }
14654
14655            multibuffer.with_title(title)
14656        });
14657
14658        let editor = cx.new(|cx| {
14659            Editor::for_multibuffer(
14660                excerpt_buffer,
14661                Some(workspace.project().clone()),
14662                window,
14663                cx,
14664            )
14665        });
14666        editor.update(cx, |editor, cx| {
14667            match multibuffer_selection_mode {
14668                MultibufferSelectionMode::First => {
14669                    if let Some(first_range) = ranges.first() {
14670                        editor.change_selections(None, window, cx, |selections| {
14671                            selections.clear_disjoint();
14672                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14673                        });
14674                    }
14675                    editor.highlight_background::<Self>(
14676                        &ranges,
14677                        |theme| theme.editor_highlighted_line_background,
14678                        cx,
14679                    );
14680                }
14681                MultibufferSelectionMode::All => {
14682                    editor.change_selections(None, window, cx, |selections| {
14683                        selections.clear_disjoint();
14684                        selections.select_anchor_ranges(ranges);
14685                    });
14686                }
14687            }
14688            editor.register_buffers_with_language_servers(cx);
14689        });
14690
14691        let item = Box::new(editor);
14692        let item_id = item.item_id();
14693
14694        if split {
14695            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14696        } else {
14697            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14698                let (preview_item_id, preview_item_idx) =
14699                    workspace.active_pane().update(cx, |pane, _| {
14700                        (pane.preview_item_id(), pane.preview_item_idx())
14701                    });
14702
14703                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14704
14705                if let Some(preview_item_id) = preview_item_id {
14706                    workspace.active_pane().update(cx, |pane, cx| {
14707                        pane.remove_item(preview_item_id, false, false, window, cx);
14708                    });
14709                }
14710            } else {
14711                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14712            }
14713        }
14714        workspace.active_pane().update(cx, |pane, cx| {
14715            pane.set_preview_item_id(Some(item_id), cx);
14716        });
14717    }
14718
14719    pub fn rename(
14720        &mut self,
14721        _: &Rename,
14722        window: &mut Window,
14723        cx: &mut Context<Self>,
14724    ) -> Option<Task<Result<()>>> {
14725        use language::ToOffset as _;
14726
14727        let provider = self.semantics_provider.clone()?;
14728        let selection = self.selections.newest_anchor().clone();
14729        let (cursor_buffer, cursor_buffer_position) = self
14730            .buffer
14731            .read(cx)
14732            .text_anchor_for_position(selection.head(), cx)?;
14733        let (tail_buffer, cursor_buffer_position_end) = self
14734            .buffer
14735            .read(cx)
14736            .text_anchor_for_position(selection.tail(), cx)?;
14737        if tail_buffer != cursor_buffer {
14738            return None;
14739        }
14740
14741        let snapshot = cursor_buffer.read(cx).snapshot();
14742        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14743        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14744        let prepare_rename = provider
14745            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14746            .unwrap_or_else(|| Task::ready(Ok(None)));
14747        drop(snapshot);
14748
14749        Some(cx.spawn_in(window, async move |this, cx| {
14750            let rename_range = if let Some(range) = prepare_rename.await? {
14751                Some(range)
14752            } else {
14753                this.update(cx, |this, cx| {
14754                    let buffer = this.buffer.read(cx).snapshot(cx);
14755                    let mut buffer_highlights = this
14756                        .document_highlights_for_position(selection.head(), &buffer)
14757                        .filter(|highlight| {
14758                            highlight.start.excerpt_id == selection.head().excerpt_id
14759                                && highlight.end.excerpt_id == selection.head().excerpt_id
14760                        });
14761                    buffer_highlights
14762                        .next()
14763                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14764                })?
14765            };
14766            if let Some(rename_range) = rename_range {
14767                this.update_in(cx, |this, window, cx| {
14768                    let snapshot = cursor_buffer.read(cx).snapshot();
14769                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14770                    let cursor_offset_in_rename_range =
14771                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14772                    let cursor_offset_in_rename_range_end =
14773                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14774
14775                    this.take_rename(false, window, cx);
14776                    let buffer = this.buffer.read(cx).read(cx);
14777                    let cursor_offset = selection.head().to_offset(&buffer);
14778                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14779                    let rename_end = rename_start + rename_buffer_range.len();
14780                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14781                    let mut old_highlight_id = None;
14782                    let old_name: Arc<str> = buffer
14783                        .chunks(rename_start..rename_end, true)
14784                        .map(|chunk| {
14785                            if old_highlight_id.is_none() {
14786                                old_highlight_id = chunk.syntax_highlight_id;
14787                            }
14788                            chunk.text
14789                        })
14790                        .collect::<String>()
14791                        .into();
14792
14793                    drop(buffer);
14794
14795                    // Position the selection in the rename editor so that it matches the current selection.
14796                    this.show_local_selections = false;
14797                    let rename_editor = cx.new(|cx| {
14798                        let mut editor = Editor::single_line(window, cx);
14799                        editor.buffer.update(cx, |buffer, cx| {
14800                            buffer.edit([(0..0, old_name.clone())], None, cx)
14801                        });
14802                        let rename_selection_range = match cursor_offset_in_rename_range
14803                            .cmp(&cursor_offset_in_rename_range_end)
14804                        {
14805                            Ordering::Equal => {
14806                                editor.select_all(&SelectAll, window, cx);
14807                                return editor;
14808                            }
14809                            Ordering::Less => {
14810                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14811                            }
14812                            Ordering::Greater => {
14813                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14814                            }
14815                        };
14816                        if rename_selection_range.end > old_name.len() {
14817                            editor.select_all(&SelectAll, window, cx);
14818                        } else {
14819                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14820                                s.select_ranges([rename_selection_range]);
14821                            });
14822                        }
14823                        editor
14824                    });
14825                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14826                        if e == &EditorEvent::Focused {
14827                            cx.emit(EditorEvent::FocusedIn)
14828                        }
14829                    })
14830                    .detach();
14831
14832                    let write_highlights =
14833                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14834                    let read_highlights =
14835                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14836                    let ranges = write_highlights
14837                        .iter()
14838                        .flat_map(|(_, ranges)| ranges.iter())
14839                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14840                        .cloned()
14841                        .collect();
14842
14843                    this.highlight_text::<Rename>(
14844                        ranges,
14845                        HighlightStyle {
14846                            fade_out: Some(0.6),
14847                            ..Default::default()
14848                        },
14849                        cx,
14850                    );
14851                    let rename_focus_handle = rename_editor.focus_handle(cx);
14852                    window.focus(&rename_focus_handle);
14853                    let block_id = this.insert_blocks(
14854                        [BlockProperties {
14855                            style: BlockStyle::Flex,
14856                            placement: BlockPlacement::Below(range.start),
14857                            height: Some(1),
14858                            render: Arc::new({
14859                                let rename_editor = rename_editor.clone();
14860                                move |cx: &mut BlockContext| {
14861                                    let mut text_style = cx.editor_style.text.clone();
14862                                    if let Some(highlight_style) = old_highlight_id
14863                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14864                                    {
14865                                        text_style = text_style.highlight(highlight_style);
14866                                    }
14867                                    div()
14868                                        .block_mouse_down()
14869                                        .pl(cx.anchor_x)
14870                                        .child(EditorElement::new(
14871                                            &rename_editor,
14872                                            EditorStyle {
14873                                                background: cx.theme().system().transparent,
14874                                                local_player: cx.editor_style.local_player,
14875                                                text: text_style,
14876                                                scrollbar_width: cx.editor_style.scrollbar_width,
14877                                                syntax: cx.editor_style.syntax.clone(),
14878                                                status: cx.editor_style.status.clone(),
14879                                                inlay_hints_style: HighlightStyle {
14880                                                    font_weight: Some(FontWeight::BOLD),
14881                                                    ..make_inlay_hints_style(cx.app)
14882                                                },
14883                                                inline_completion_styles: make_suggestion_styles(
14884                                                    cx.app,
14885                                                ),
14886                                                ..EditorStyle::default()
14887                                            },
14888                                        ))
14889                                        .into_any_element()
14890                                }
14891                            }),
14892                            priority: 0,
14893                            render_in_minimap: true,
14894                        }],
14895                        Some(Autoscroll::fit()),
14896                        cx,
14897                    )[0];
14898                    this.pending_rename = Some(RenameState {
14899                        range,
14900                        old_name,
14901                        editor: rename_editor,
14902                        block_id,
14903                    });
14904                })?;
14905            }
14906
14907            Ok(())
14908        }))
14909    }
14910
14911    pub fn confirm_rename(
14912        &mut self,
14913        _: &ConfirmRename,
14914        window: &mut Window,
14915        cx: &mut Context<Self>,
14916    ) -> Option<Task<Result<()>>> {
14917        let rename = self.take_rename(false, window, cx)?;
14918        let workspace = self.workspace()?.downgrade();
14919        let (buffer, start) = self
14920            .buffer
14921            .read(cx)
14922            .text_anchor_for_position(rename.range.start, cx)?;
14923        let (end_buffer, _) = self
14924            .buffer
14925            .read(cx)
14926            .text_anchor_for_position(rename.range.end, cx)?;
14927        if buffer != end_buffer {
14928            return None;
14929        }
14930
14931        let old_name = rename.old_name;
14932        let new_name = rename.editor.read(cx).text(cx);
14933
14934        let rename = self.semantics_provider.as_ref()?.perform_rename(
14935            &buffer,
14936            start,
14937            new_name.clone(),
14938            cx,
14939        )?;
14940
14941        Some(cx.spawn_in(window, async move |editor, cx| {
14942            let project_transaction = rename.await?;
14943            Self::open_project_transaction(
14944                &editor,
14945                workspace,
14946                project_transaction,
14947                format!("Rename: {}{}", old_name, new_name),
14948                cx,
14949            )
14950            .await?;
14951
14952            editor.update(cx, |editor, cx| {
14953                editor.refresh_document_highlights(cx);
14954            })?;
14955            Ok(())
14956        }))
14957    }
14958
14959    fn take_rename(
14960        &mut self,
14961        moving_cursor: bool,
14962        window: &mut Window,
14963        cx: &mut Context<Self>,
14964    ) -> Option<RenameState> {
14965        let rename = self.pending_rename.take()?;
14966        if rename.editor.focus_handle(cx).is_focused(window) {
14967            window.focus(&self.focus_handle);
14968        }
14969
14970        self.remove_blocks(
14971            [rename.block_id].into_iter().collect(),
14972            Some(Autoscroll::fit()),
14973            cx,
14974        );
14975        self.clear_highlights::<Rename>(cx);
14976        self.show_local_selections = true;
14977
14978        if moving_cursor {
14979            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14980                editor.selections.newest::<usize>(cx).head()
14981            });
14982
14983            // Update the selection to match the position of the selection inside
14984            // the rename editor.
14985            let snapshot = self.buffer.read(cx).read(cx);
14986            let rename_range = rename.range.to_offset(&snapshot);
14987            let cursor_in_editor = snapshot
14988                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14989                .min(rename_range.end);
14990            drop(snapshot);
14991
14992            self.change_selections(None, window, cx, |s| {
14993                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14994            });
14995        } else {
14996            self.refresh_document_highlights(cx);
14997        }
14998
14999        Some(rename)
15000    }
15001
15002    pub fn pending_rename(&self) -> Option<&RenameState> {
15003        self.pending_rename.as_ref()
15004    }
15005
15006    fn format(
15007        &mut self,
15008        _: &Format,
15009        window: &mut Window,
15010        cx: &mut Context<Self>,
15011    ) -> Option<Task<Result<()>>> {
15012        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15013
15014        let project = match &self.project {
15015            Some(project) => project.clone(),
15016            None => return None,
15017        };
15018
15019        Some(self.perform_format(
15020            project,
15021            FormatTrigger::Manual,
15022            FormatTarget::Buffers,
15023            window,
15024            cx,
15025        ))
15026    }
15027
15028    fn format_selections(
15029        &mut self,
15030        _: &FormatSelections,
15031        window: &mut Window,
15032        cx: &mut Context<Self>,
15033    ) -> Option<Task<Result<()>>> {
15034        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15035
15036        let project = match &self.project {
15037            Some(project) => project.clone(),
15038            None => return None,
15039        };
15040
15041        let ranges = self
15042            .selections
15043            .all_adjusted(cx)
15044            .into_iter()
15045            .map(|selection| selection.range())
15046            .collect_vec();
15047
15048        Some(self.perform_format(
15049            project,
15050            FormatTrigger::Manual,
15051            FormatTarget::Ranges(ranges),
15052            window,
15053            cx,
15054        ))
15055    }
15056
15057    fn perform_format(
15058        &mut self,
15059        project: Entity<Project>,
15060        trigger: FormatTrigger,
15061        target: FormatTarget,
15062        window: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) -> Task<Result<()>> {
15065        let buffer = self.buffer.clone();
15066        let (buffers, target) = match target {
15067            FormatTarget::Buffers => {
15068                let mut buffers = buffer.read(cx).all_buffers();
15069                if trigger == FormatTrigger::Save {
15070                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15071                }
15072                (buffers, LspFormatTarget::Buffers)
15073            }
15074            FormatTarget::Ranges(selection_ranges) => {
15075                let multi_buffer = buffer.read(cx);
15076                let snapshot = multi_buffer.read(cx);
15077                let mut buffers = HashSet::default();
15078                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15079                    BTreeMap::new();
15080                for selection_range in selection_ranges {
15081                    for (buffer, buffer_range, _) in
15082                        snapshot.range_to_buffer_ranges(selection_range)
15083                    {
15084                        let buffer_id = buffer.remote_id();
15085                        let start = buffer.anchor_before(buffer_range.start);
15086                        let end = buffer.anchor_after(buffer_range.end);
15087                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15088                        buffer_id_to_ranges
15089                            .entry(buffer_id)
15090                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15091                            .or_insert_with(|| vec![start..end]);
15092                    }
15093                }
15094                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15095            }
15096        };
15097
15098        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15099        let selections_prev = transaction_id_prev
15100            .and_then(|transaction_id_prev| {
15101                // default to selections as they were after the last edit, if we have them,
15102                // instead of how they are now.
15103                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15104                // will take you back to where you made the last edit, instead of staying where you scrolled
15105                self.selection_history
15106                    .transaction(transaction_id_prev)
15107                    .map(|t| t.0.clone())
15108            })
15109            .unwrap_or_else(|| {
15110                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15111                self.selections.disjoint_anchors()
15112            });
15113
15114        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15115        let format = project.update(cx, |project, cx| {
15116            project.format(buffers, target, true, trigger, cx)
15117        });
15118
15119        cx.spawn_in(window, async move |editor, cx| {
15120            let transaction = futures::select_biased! {
15121                transaction = format.log_err().fuse() => transaction,
15122                () = timeout => {
15123                    log::warn!("timed out waiting for formatting");
15124                    None
15125                }
15126            };
15127
15128            buffer
15129                .update(cx, |buffer, cx| {
15130                    if let Some(transaction) = transaction {
15131                        if !buffer.is_singleton() {
15132                            buffer.push_transaction(&transaction.0, cx);
15133                        }
15134                    }
15135                    cx.notify();
15136                })
15137                .ok();
15138
15139            if let Some(transaction_id_now) =
15140                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15141            {
15142                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15143                if has_new_transaction {
15144                    _ = editor.update(cx, |editor, _| {
15145                        editor
15146                            .selection_history
15147                            .insert_transaction(transaction_id_now, selections_prev);
15148                    });
15149                }
15150            }
15151
15152            Ok(())
15153        })
15154    }
15155
15156    fn organize_imports(
15157        &mut self,
15158        _: &OrganizeImports,
15159        window: &mut Window,
15160        cx: &mut Context<Self>,
15161    ) -> Option<Task<Result<()>>> {
15162        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15163        let project = match &self.project {
15164            Some(project) => project.clone(),
15165            None => return None,
15166        };
15167        Some(self.perform_code_action_kind(
15168            project,
15169            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15170            window,
15171            cx,
15172        ))
15173    }
15174
15175    fn perform_code_action_kind(
15176        &mut self,
15177        project: Entity<Project>,
15178        kind: CodeActionKind,
15179        window: &mut Window,
15180        cx: &mut Context<Self>,
15181    ) -> Task<Result<()>> {
15182        let buffer = self.buffer.clone();
15183        let buffers = buffer.read(cx).all_buffers();
15184        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15185        let apply_action = project.update(cx, |project, cx| {
15186            project.apply_code_action_kind(buffers, kind, true, cx)
15187        });
15188        cx.spawn_in(window, async move |_, cx| {
15189            let transaction = futures::select_biased! {
15190                () = timeout => {
15191                    log::warn!("timed out waiting for executing code action");
15192                    None
15193                }
15194                transaction = apply_action.log_err().fuse() => transaction,
15195            };
15196            buffer
15197                .update(cx, |buffer, cx| {
15198                    // check if we need this
15199                    if let Some(transaction) = transaction {
15200                        if !buffer.is_singleton() {
15201                            buffer.push_transaction(&transaction.0, cx);
15202                        }
15203                    }
15204                    cx.notify();
15205                })
15206                .ok();
15207            Ok(())
15208        })
15209    }
15210
15211    fn restart_language_server(
15212        &mut self,
15213        _: &RestartLanguageServer,
15214        _: &mut Window,
15215        cx: &mut Context<Self>,
15216    ) {
15217        if let Some(project) = self.project.clone() {
15218            self.buffer.update(cx, |multi_buffer, cx| {
15219                project.update(cx, |project, cx| {
15220                    project.restart_language_servers_for_buffers(
15221                        multi_buffer.all_buffers().into_iter().collect(),
15222                        cx,
15223                    );
15224                });
15225            })
15226        }
15227    }
15228
15229    fn stop_language_server(
15230        &mut self,
15231        _: &StopLanguageServer,
15232        _: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        if let Some(project) = self.project.clone() {
15236            self.buffer.update(cx, |multi_buffer, cx| {
15237                project.update(cx, |project, cx| {
15238                    project.stop_language_servers_for_buffers(
15239                        multi_buffer.all_buffers().into_iter().collect(),
15240                        cx,
15241                    );
15242                    cx.emit(project::Event::RefreshInlayHints);
15243                });
15244            });
15245        }
15246    }
15247
15248    fn cancel_language_server_work(
15249        workspace: &mut Workspace,
15250        _: &actions::CancelLanguageServerWork,
15251        _: &mut Window,
15252        cx: &mut Context<Workspace>,
15253    ) {
15254        let project = workspace.project();
15255        let buffers = workspace
15256            .active_item(cx)
15257            .and_then(|item| item.act_as::<Editor>(cx))
15258            .map_or(HashSet::default(), |editor| {
15259                editor.read(cx).buffer.read(cx).all_buffers()
15260            });
15261        project.update(cx, |project, cx| {
15262            project.cancel_language_server_work_for_buffers(buffers, cx);
15263        });
15264    }
15265
15266    fn show_character_palette(
15267        &mut self,
15268        _: &ShowCharacterPalette,
15269        window: &mut Window,
15270        _: &mut Context<Self>,
15271    ) {
15272        window.show_character_palette();
15273    }
15274
15275    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15276        if self.mode.is_minimap() {
15277            return;
15278        }
15279
15280        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15281            let buffer = self.buffer.read(cx).snapshot(cx);
15282            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15283            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15284            let is_valid = buffer
15285                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15286                .any(|entry| {
15287                    entry.diagnostic.is_primary
15288                        && !entry.range.is_empty()
15289                        && entry.range.start == primary_range_start
15290                        && entry.diagnostic.message == active_diagnostics.active_message
15291                });
15292
15293            if !is_valid {
15294                self.dismiss_diagnostics(cx);
15295            }
15296        }
15297    }
15298
15299    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15300        match &self.active_diagnostics {
15301            ActiveDiagnostic::Group(group) => Some(group),
15302            _ => None,
15303        }
15304    }
15305
15306    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15307        self.dismiss_diagnostics(cx);
15308        self.active_diagnostics = ActiveDiagnostic::All;
15309    }
15310
15311    fn activate_diagnostics(
15312        &mut self,
15313        buffer_id: BufferId,
15314        diagnostic: DiagnosticEntry<usize>,
15315        window: &mut Window,
15316        cx: &mut Context<Self>,
15317    ) {
15318        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15319            return;
15320        }
15321        self.dismiss_diagnostics(cx);
15322        let snapshot = self.snapshot(window, cx);
15323        let buffer = self.buffer.read(cx).snapshot(cx);
15324        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15325            return;
15326        };
15327
15328        let diagnostic_group = buffer
15329            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15330            .collect::<Vec<_>>();
15331
15332        let blocks =
15333            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15334
15335        let blocks = self.display_map.update(cx, |display_map, cx| {
15336            display_map.insert_blocks(blocks, cx).into_iter().collect()
15337        });
15338        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15339            active_range: buffer.anchor_before(diagnostic.range.start)
15340                ..buffer.anchor_after(diagnostic.range.end),
15341            active_message: diagnostic.diagnostic.message.clone(),
15342            group_id: diagnostic.diagnostic.group_id,
15343            blocks,
15344        });
15345        cx.notify();
15346    }
15347
15348    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15349        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15350            return;
15351        };
15352
15353        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15354        if let ActiveDiagnostic::Group(group) = prev {
15355            self.display_map.update(cx, |display_map, cx| {
15356                display_map.remove_blocks(group.blocks, cx);
15357            });
15358            cx.notify();
15359        }
15360    }
15361
15362    /// Disable inline diagnostics rendering for this editor.
15363    pub fn disable_inline_diagnostics(&mut self) {
15364        self.inline_diagnostics_enabled = false;
15365        self.inline_diagnostics_update = Task::ready(());
15366        self.inline_diagnostics.clear();
15367    }
15368
15369    pub fn diagnostics_enabled(&self) -> bool {
15370        self.mode.is_full()
15371    }
15372
15373    pub fn inline_diagnostics_enabled(&self) -> bool {
15374        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15375    }
15376
15377    pub fn show_inline_diagnostics(&self) -> bool {
15378        self.show_inline_diagnostics
15379    }
15380
15381    pub fn toggle_inline_diagnostics(
15382        &mut self,
15383        _: &ToggleInlineDiagnostics,
15384        window: &mut Window,
15385        cx: &mut Context<Editor>,
15386    ) {
15387        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15388        self.refresh_inline_diagnostics(false, window, cx);
15389    }
15390
15391    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15392        self.diagnostics_max_severity = severity;
15393        self.display_map.update(cx, |display_map, _| {
15394            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15395        });
15396    }
15397
15398    pub fn toggle_diagnostics(
15399        &mut self,
15400        _: &ToggleDiagnostics,
15401        window: &mut Window,
15402        cx: &mut Context<Editor>,
15403    ) {
15404        if !self.diagnostics_enabled() {
15405            return;
15406        }
15407
15408        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15409            EditorSettings::get_global(cx)
15410                .diagnostics_max_severity
15411                .filter(|severity| severity != &DiagnosticSeverity::Off)
15412                .unwrap_or(DiagnosticSeverity::Hint)
15413        } else {
15414            DiagnosticSeverity::Off
15415        };
15416        self.set_max_diagnostics_severity(new_severity, cx);
15417        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15418            self.active_diagnostics = ActiveDiagnostic::None;
15419            self.inline_diagnostics_update = Task::ready(());
15420            self.inline_diagnostics.clear();
15421        } else {
15422            self.refresh_inline_diagnostics(false, window, cx);
15423        }
15424
15425        cx.notify();
15426    }
15427
15428    pub fn toggle_minimap(
15429        &mut self,
15430        _: &ToggleMinimap,
15431        window: &mut Window,
15432        cx: &mut Context<Editor>,
15433    ) {
15434        if self.supports_minimap(cx) {
15435            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15436        }
15437    }
15438
15439    fn refresh_inline_diagnostics(
15440        &mut self,
15441        debounce: bool,
15442        window: &mut Window,
15443        cx: &mut Context<Self>,
15444    ) {
15445        let max_severity = ProjectSettings::get_global(cx)
15446            .diagnostics
15447            .inline
15448            .max_severity
15449            .unwrap_or(self.diagnostics_max_severity);
15450
15451        if !self.inline_diagnostics_enabled()
15452            || !self.show_inline_diagnostics
15453            || max_severity == DiagnosticSeverity::Off
15454        {
15455            self.inline_diagnostics_update = Task::ready(());
15456            self.inline_diagnostics.clear();
15457            return;
15458        }
15459
15460        let debounce_ms = ProjectSettings::get_global(cx)
15461            .diagnostics
15462            .inline
15463            .update_debounce_ms;
15464        let debounce = if debounce && debounce_ms > 0 {
15465            Some(Duration::from_millis(debounce_ms))
15466        } else {
15467            None
15468        };
15469        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15470            let editor = editor.upgrade().unwrap();
15471
15472            if let Some(debounce) = debounce {
15473                cx.background_executor().timer(debounce).await;
15474            }
15475            let Some(snapshot) = editor
15476                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15477                .ok()
15478            else {
15479                return;
15480            };
15481
15482            let new_inline_diagnostics = cx
15483                .background_spawn(async move {
15484                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15485                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15486                        let message = diagnostic_entry
15487                            .diagnostic
15488                            .message
15489                            .split_once('\n')
15490                            .map(|(line, _)| line)
15491                            .map(SharedString::new)
15492                            .unwrap_or_else(|| {
15493                                SharedString::from(diagnostic_entry.diagnostic.message)
15494                            });
15495                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15496                        let (Ok(i) | Err(i)) = inline_diagnostics
15497                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15498                        inline_diagnostics.insert(
15499                            i,
15500                            (
15501                                start_anchor,
15502                                InlineDiagnostic {
15503                                    message,
15504                                    group_id: diagnostic_entry.diagnostic.group_id,
15505                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15506                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15507                                    severity: diagnostic_entry.diagnostic.severity,
15508                                },
15509                            ),
15510                        );
15511                    }
15512                    inline_diagnostics
15513                })
15514                .await;
15515
15516            editor
15517                .update(cx, |editor, cx| {
15518                    editor.inline_diagnostics = new_inline_diagnostics;
15519                    cx.notify();
15520                })
15521                .ok();
15522        });
15523    }
15524
15525    pub fn set_selections_from_remote(
15526        &mut self,
15527        selections: Vec<Selection<Anchor>>,
15528        pending_selection: Option<Selection<Anchor>>,
15529        window: &mut Window,
15530        cx: &mut Context<Self>,
15531    ) {
15532        let old_cursor_position = self.selections.newest_anchor().head();
15533        self.selections.change_with(cx, |s| {
15534            s.select_anchors(selections);
15535            if let Some(pending_selection) = pending_selection {
15536                s.set_pending(pending_selection, SelectMode::Character);
15537            } else {
15538                s.clear_pending();
15539            }
15540        });
15541        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15542    }
15543
15544    fn push_to_selection_history(&mut self) {
15545        self.selection_history.push(SelectionHistoryEntry {
15546            selections: self.selections.disjoint_anchors(),
15547            select_next_state: self.select_next_state.clone(),
15548            select_prev_state: self.select_prev_state.clone(),
15549            add_selections_state: self.add_selections_state.clone(),
15550        });
15551    }
15552
15553    pub fn transact(
15554        &mut self,
15555        window: &mut Window,
15556        cx: &mut Context<Self>,
15557        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15558    ) -> Option<TransactionId> {
15559        self.start_transaction_at(Instant::now(), window, cx);
15560        update(self, window, cx);
15561        self.end_transaction_at(Instant::now(), cx)
15562    }
15563
15564    pub fn start_transaction_at(
15565        &mut self,
15566        now: Instant,
15567        window: &mut Window,
15568        cx: &mut Context<Self>,
15569    ) {
15570        self.end_selection(window, cx);
15571        if let Some(tx_id) = self
15572            .buffer
15573            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15574        {
15575            self.selection_history
15576                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15577            cx.emit(EditorEvent::TransactionBegun {
15578                transaction_id: tx_id,
15579            })
15580        }
15581    }
15582
15583    pub fn end_transaction_at(
15584        &mut self,
15585        now: Instant,
15586        cx: &mut Context<Self>,
15587    ) -> Option<TransactionId> {
15588        if let Some(transaction_id) = self
15589            .buffer
15590            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15591        {
15592            if let Some((_, end_selections)) =
15593                self.selection_history.transaction_mut(transaction_id)
15594            {
15595                *end_selections = Some(self.selections.disjoint_anchors());
15596            } else {
15597                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15598            }
15599
15600            cx.emit(EditorEvent::Edited { transaction_id });
15601            Some(transaction_id)
15602        } else {
15603            None
15604        }
15605    }
15606
15607    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15608        if self.selection_mark_mode {
15609            self.change_selections(None, window, cx, |s| {
15610                s.move_with(|_, sel| {
15611                    sel.collapse_to(sel.head(), SelectionGoal::None);
15612                });
15613            })
15614        }
15615        self.selection_mark_mode = true;
15616        cx.notify();
15617    }
15618
15619    pub fn swap_selection_ends(
15620        &mut self,
15621        _: &actions::SwapSelectionEnds,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) {
15625        self.change_selections(None, window, cx, |s| {
15626            s.move_with(|_, sel| {
15627                if sel.start != sel.end {
15628                    sel.reversed = !sel.reversed
15629                }
15630            });
15631        });
15632        self.request_autoscroll(Autoscroll::newest(), cx);
15633        cx.notify();
15634    }
15635
15636    pub fn toggle_fold(
15637        &mut self,
15638        _: &actions::ToggleFold,
15639        window: &mut Window,
15640        cx: &mut Context<Self>,
15641    ) {
15642        if self.is_singleton(cx) {
15643            let selection = self.selections.newest::<Point>(cx);
15644
15645            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15646            let range = if selection.is_empty() {
15647                let point = selection.head().to_display_point(&display_map);
15648                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15649                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15650                    .to_point(&display_map);
15651                start..end
15652            } else {
15653                selection.range()
15654            };
15655            if display_map.folds_in_range(range).next().is_some() {
15656                self.unfold_lines(&Default::default(), window, cx)
15657            } else {
15658                self.fold(&Default::default(), window, cx)
15659            }
15660        } else {
15661            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15662            let buffer_ids: HashSet<_> = self
15663                .selections
15664                .disjoint_anchor_ranges()
15665                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15666                .collect();
15667
15668            let should_unfold = buffer_ids
15669                .iter()
15670                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15671
15672            for buffer_id in buffer_ids {
15673                if should_unfold {
15674                    self.unfold_buffer(buffer_id, cx);
15675                } else {
15676                    self.fold_buffer(buffer_id, cx);
15677                }
15678            }
15679        }
15680    }
15681
15682    pub fn toggle_fold_recursive(
15683        &mut self,
15684        _: &actions::ToggleFoldRecursive,
15685        window: &mut Window,
15686        cx: &mut Context<Self>,
15687    ) {
15688        let selection = self.selections.newest::<Point>(cx);
15689
15690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15691        let range = if selection.is_empty() {
15692            let point = selection.head().to_display_point(&display_map);
15693            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15694            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15695                .to_point(&display_map);
15696            start..end
15697        } else {
15698            selection.range()
15699        };
15700        if display_map.folds_in_range(range).next().is_some() {
15701            self.unfold_recursive(&Default::default(), window, cx)
15702        } else {
15703            self.fold_recursive(&Default::default(), window, cx)
15704        }
15705    }
15706
15707    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15708        if self.is_singleton(cx) {
15709            let mut to_fold = Vec::new();
15710            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15711            let selections = self.selections.all_adjusted(cx);
15712
15713            for selection in selections {
15714                let range = selection.range().sorted();
15715                let buffer_start_row = range.start.row;
15716
15717                if range.start.row != range.end.row {
15718                    let mut found = false;
15719                    let mut row = range.start.row;
15720                    while row <= range.end.row {
15721                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15722                        {
15723                            found = true;
15724                            row = crease.range().end.row + 1;
15725                            to_fold.push(crease);
15726                        } else {
15727                            row += 1
15728                        }
15729                    }
15730                    if found {
15731                        continue;
15732                    }
15733                }
15734
15735                for row in (0..=range.start.row).rev() {
15736                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15737                        if crease.range().end.row >= buffer_start_row {
15738                            to_fold.push(crease);
15739                            if row <= range.start.row {
15740                                break;
15741                            }
15742                        }
15743                    }
15744                }
15745            }
15746
15747            self.fold_creases(to_fold, true, window, cx);
15748        } else {
15749            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15750            let buffer_ids = self
15751                .selections
15752                .disjoint_anchor_ranges()
15753                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15754                .collect::<HashSet<_>>();
15755            for buffer_id in buffer_ids {
15756                self.fold_buffer(buffer_id, cx);
15757            }
15758        }
15759    }
15760
15761    fn fold_at_level(
15762        &mut self,
15763        fold_at: &FoldAtLevel,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) {
15767        if !self.buffer.read(cx).is_singleton() {
15768            return;
15769        }
15770
15771        let fold_at_level = fold_at.0;
15772        let snapshot = self.buffer.read(cx).snapshot(cx);
15773        let mut to_fold = Vec::new();
15774        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15775
15776        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15777            while start_row < end_row {
15778                match self
15779                    .snapshot(window, cx)
15780                    .crease_for_buffer_row(MultiBufferRow(start_row))
15781                {
15782                    Some(crease) => {
15783                        let nested_start_row = crease.range().start.row + 1;
15784                        let nested_end_row = crease.range().end.row;
15785
15786                        if current_level < fold_at_level {
15787                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15788                        } else if current_level == fold_at_level {
15789                            to_fold.push(crease);
15790                        }
15791
15792                        start_row = nested_end_row + 1;
15793                    }
15794                    None => start_row += 1,
15795                }
15796            }
15797        }
15798
15799        self.fold_creases(to_fold, true, window, cx);
15800    }
15801
15802    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15803        if self.buffer.read(cx).is_singleton() {
15804            let mut fold_ranges = Vec::new();
15805            let snapshot = self.buffer.read(cx).snapshot(cx);
15806
15807            for row in 0..snapshot.max_row().0 {
15808                if let Some(foldable_range) = self
15809                    .snapshot(window, cx)
15810                    .crease_for_buffer_row(MultiBufferRow(row))
15811                {
15812                    fold_ranges.push(foldable_range);
15813                }
15814            }
15815
15816            self.fold_creases(fold_ranges, true, window, cx);
15817        } else {
15818            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15819                editor
15820                    .update_in(cx, |editor, _, cx| {
15821                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15822                            editor.fold_buffer(buffer_id, cx);
15823                        }
15824                    })
15825                    .ok();
15826            });
15827        }
15828    }
15829
15830    pub fn fold_function_bodies(
15831        &mut self,
15832        _: &actions::FoldFunctionBodies,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        let snapshot = self.buffer.read(cx).snapshot(cx);
15837
15838        let ranges = snapshot
15839            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15840            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15841            .collect::<Vec<_>>();
15842
15843        let creases = ranges
15844            .into_iter()
15845            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15846            .collect();
15847
15848        self.fold_creases(creases, true, window, cx);
15849    }
15850
15851    pub fn fold_recursive(
15852        &mut self,
15853        _: &actions::FoldRecursive,
15854        window: &mut Window,
15855        cx: &mut Context<Self>,
15856    ) {
15857        let mut to_fold = Vec::new();
15858        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15859        let selections = self.selections.all_adjusted(cx);
15860
15861        for selection in selections {
15862            let range = selection.range().sorted();
15863            let buffer_start_row = range.start.row;
15864
15865            if range.start.row != range.end.row {
15866                let mut found = false;
15867                for row in range.start.row..=range.end.row {
15868                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15869                        found = true;
15870                        to_fold.push(crease);
15871                    }
15872                }
15873                if found {
15874                    continue;
15875                }
15876            }
15877
15878            for row in (0..=range.start.row).rev() {
15879                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15880                    if crease.range().end.row >= buffer_start_row {
15881                        to_fold.push(crease);
15882                    } else {
15883                        break;
15884                    }
15885                }
15886            }
15887        }
15888
15889        self.fold_creases(to_fold, true, window, cx);
15890    }
15891
15892    pub fn fold_at(
15893        &mut self,
15894        buffer_row: MultiBufferRow,
15895        window: &mut Window,
15896        cx: &mut Context<Self>,
15897    ) {
15898        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15899
15900        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15901            let autoscroll = self
15902                .selections
15903                .all::<Point>(cx)
15904                .iter()
15905                .any(|selection| crease.range().overlaps(&selection.range()));
15906
15907            self.fold_creases(vec![crease], autoscroll, window, cx);
15908        }
15909    }
15910
15911    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15912        if self.is_singleton(cx) {
15913            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15914            let buffer = &display_map.buffer_snapshot;
15915            let selections = self.selections.all::<Point>(cx);
15916            let ranges = selections
15917                .iter()
15918                .map(|s| {
15919                    let range = s.display_range(&display_map).sorted();
15920                    let mut start = range.start.to_point(&display_map);
15921                    let mut end = range.end.to_point(&display_map);
15922                    start.column = 0;
15923                    end.column = buffer.line_len(MultiBufferRow(end.row));
15924                    start..end
15925                })
15926                .collect::<Vec<_>>();
15927
15928            self.unfold_ranges(&ranges, true, true, cx);
15929        } else {
15930            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15931            let buffer_ids = self
15932                .selections
15933                .disjoint_anchor_ranges()
15934                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15935                .collect::<HashSet<_>>();
15936            for buffer_id in buffer_ids {
15937                self.unfold_buffer(buffer_id, cx);
15938            }
15939        }
15940    }
15941
15942    pub fn unfold_recursive(
15943        &mut self,
15944        _: &UnfoldRecursive,
15945        _window: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15949        let selections = self.selections.all::<Point>(cx);
15950        let ranges = selections
15951            .iter()
15952            .map(|s| {
15953                let mut range = s.display_range(&display_map).sorted();
15954                *range.start.column_mut() = 0;
15955                *range.end.column_mut() = display_map.line_len(range.end.row());
15956                let start = range.start.to_point(&display_map);
15957                let end = range.end.to_point(&display_map);
15958                start..end
15959            })
15960            .collect::<Vec<_>>();
15961
15962        self.unfold_ranges(&ranges, true, true, cx);
15963    }
15964
15965    pub fn unfold_at(
15966        &mut self,
15967        buffer_row: MultiBufferRow,
15968        _window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15972
15973        let intersection_range = Point::new(buffer_row.0, 0)
15974            ..Point::new(
15975                buffer_row.0,
15976                display_map.buffer_snapshot.line_len(buffer_row),
15977            );
15978
15979        let autoscroll = self
15980            .selections
15981            .all::<Point>(cx)
15982            .iter()
15983            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15984
15985        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15986    }
15987
15988    pub fn unfold_all(
15989        &mut self,
15990        _: &actions::UnfoldAll,
15991        _window: &mut Window,
15992        cx: &mut Context<Self>,
15993    ) {
15994        if self.buffer.read(cx).is_singleton() {
15995            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15996            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15997        } else {
15998            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15999                editor
16000                    .update(cx, |editor, cx| {
16001                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16002                            editor.unfold_buffer(buffer_id, cx);
16003                        }
16004                    })
16005                    .ok();
16006            });
16007        }
16008    }
16009
16010    pub fn fold_selected_ranges(
16011        &mut self,
16012        _: &FoldSelectedRanges,
16013        window: &mut Window,
16014        cx: &mut Context<Self>,
16015    ) {
16016        let selections = self.selections.all_adjusted(cx);
16017        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16018        let ranges = selections
16019            .into_iter()
16020            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16021            .collect::<Vec<_>>();
16022        self.fold_creases(ranges, true, window, cx);
16023    }
16024
16025    pub fn fold_ranges<T: ToOffset + Clone>(
16026        &mut self,
16027        ranges: Vec<Range<T>>,
16028        auto_scroll: bool,
16029        window: &mut Window,
16030        cx: &mut Context<Self>,
16031    ) {
16032        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16033        let ranges = ranges
16034            .into_iter()
16035            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16036            .collect::<Vec<_>>();
16037        self.fold_creases(ranges, auto_scroll, window, cx);
16038    }
16039
16040    pub fn fold_creases<T: ToOffset + Clone>(
16041        &mut self,
16042        creases: Vec<Crease<T>>,
16043        auto_scroll: bool,
16044        _window: &mut Window,
16045        cx: &mut Context<Self>,
16046    ) {
16047        if creases.is_empty() {
16048            return;
16049        }
16050
16051        let mut buffers_affected = HashSet::default();
16052        let multi_buffer = self.buffer().read(cx);
16053        for crease in &creases {
16054            if let Some((_, buffer, _)) =
16055                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16056            {
16057                buffers_affected.insert(buffer.read(cx).remote_id());
16058            };
16059        }
16060
16061        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16062
16063        if auto_scroll {
16064            self.request_autoscroll(Autoscroll::fit(), cx);
16065        }
16066
16067        cx.notify();
16068
16069        self.scrollbar_marker_state.dirty = true;
16070        self.folds_did_change(cx);
16071    }
16072
16073    /// Removes any folds whose ranges intersect any of the given ranges.
16074    pub fn unfold_ranges<T: ToOffset + Clone>(
16075        &mut self,
16076        ranges: &[Range<T>],
16077        inclusive: bool,
16078        auto_scroll: bool,
16079        cx: &mut Context<Self>,
16080    ) {
16081        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16082            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16083        });
16084        self.folds_did_change(cx);
16085    }
16086
16087    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16088        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16089            return;
16090        }
16091        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16092        self.display_map.update(cx, |display_map, cx| {
16093            display_map.fold_buffers([buffer_id], cx)
16094        });
16095        cx.emit(EditorEvent::BufferFoldToggled {
16096            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16097            folded: true,
16098        });
16099        cx.notify();
16100    }
16101
16102    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16103        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16104            return;
16105        }
16106        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16107        self.display_map.update(cx, |display_map, cx| {
16108            display_map.unfold_buffers([buffer_id], cx);
16109        });
16110        cx.emit(EditorEvent::BufferFoldToggled {
16111            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16112            folded: false,
16113        });
16114        cx.notify();
16115    }
16116
16117    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16118        self.display_map.read(cx).is_buffer_folded(buffer)
16119    }
16120
16121    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16122        self.display_map.read(cx).folded_buffers()
16123    }
16124
16125    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16126        self.display_map.update(cx, |display_map, cx| {
16127            display_map.disable_header_for_buffer(buffer_id, cx);
16128        });
16129        cx.notify();
16130    }
16131
16132    /// Removes any folds with the given ranges.
16133    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16134        &mut self,
16135        ranges: &[Range<T>],
16136        type_id: TypeId,
16137        auto_scroll: bool,
16138        cx: &mut Context<Self>,
16139    ) {
16140        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16141            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16142        });
16143        self.folds_did_change(cx);
16144    }
16145
16146    fn remove_folds_with<T: ToOffset + Clone>(
16147        &mut self,
16148        ranges: &[Range<T>],
16149        auto_scroll: bool,
16150        cx: &mut Context<Self>,
16151        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16152    ) {
16153        if ranges.is_empty() {
16154            return;
16155        }
16156
16157        let mut buffers_affected = HashSet::default();
16158        let multi_buffer = self.buffer().read(cx);
16159        for range in ranges {
16160            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16161                buffers_affected.insert(buffer.read(cx).remote_id());
16162            };
16163        }
16164
16165        self.display_map.update(cx, update);
16166
16167        if auto_scroll {
16168            self.request_autoscroll(Autoscroll::fit(), cx);
16169        }
16170
16171        cx.notify();
16172        self.scrollbar_marker_state.dirty = true;
16173        self.active_indent_guides_state.dirty = true;
16174    }
16175
16176    pub fn update_fold_widths(
16177        &mut self,
16178        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16179        cx: &mut Context<Self>,
16180    ) -> bool {
16181        self.display_map
16182            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16183    }
16184
16185    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16186        self.display_map.read(cx).fold_placeholder.clone()
16187    }
16188
16189    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16190        self.buffer.update(cx, |buffer, cx| {
16191            buffer.set_all_diff_hunks_expanded(cx);
16192        });
16193    }
16194
16195    pub fn expand_all_diff_hunks(
16196        &mut self,
16197        _: &ExpandAllDiffHunks,
16198        _window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) {
16201        self.buffer.update(cx, |buffer, cx| {
16202            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16203        });
16204    }
16205
16206    pub fn toggle_selected_diff_hunks(
16207        &mut self,
16208        _: &ToggleSelectedDiffHunks,
16209        _window: &mut Window,
16210        cx: &mut Context<Self>,
16211    ) {
16212        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16213        self.toggle_diff_hunks_in_ranges(ranges, cx);
16214    }
16215
16216    pub fn diff_hunks_in_ranges<'a>(
16217        &'a self,
16218        ranges: &'a [Range<Anchor>],
16219        buffer: &'a MultiBufferSnapshot,
16220    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16221        ranges.iter().flat_map(move |range| {
16222            let end_excerpt_id = range.end.excerpt_id;
16223            let range = range.to_point(buffer);
16224            let mut peek_end = range.end;
16225            if range.end.row < buffer.max_row().0 {
16226                peek_end = Point::new(range.end.row + 1, 0);
16227            }
16228            buffer
16229                .diff_hunks_in_range(range.start..peek_end)
16230                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16231        })
16232    }
16233
16234    pub fn has_stageable_diff_hunks_in_ranges(
16235        &self,
16236        ranges: &[Range<Anchor>],
16237        snapshot: &MultiBufferSnapshot,
16238    ) -> bool {
16239        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16240        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16241    }
16242
16243    pub fn toggle_staged_selected_diff_hunks(
16244        &mut self,
16245        _: &::git::ToggleStaged,
16246        _: &mut Window,
16247        cx: &mut Context<Self>,
16248    ) {
16249        let snapshot = self.buffer.read(cx).snapshot(cx);
16250        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16251        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16252        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16253    }
16254
16255    pub fn set_render_diff_hunk_controls(
16256        &mut self,
16257        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16258        cx: &mut Context<Self>,
16259    ) {
16260        self.render_diff_hunk_controls = render_diff_hunk_controls;
16261        cx.notify();
16262    }
16263
16264    pub fn stage_and_next(
16265        &mut self,
16266        _: &::git::StageAndNext,
16267        window: &mut Window,
16268        cx: &mut Context<Self>,
16269    ) {
16270        self.do_stage_or_unstage_and_next(true, window, cx);
16271    }
16272
16273    pub fn unstage_and_next(
16274        &mut self,
16275        _: &::git::UnstageAndNext,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        self.do_stage_or_unstage_and_next(false, window, cx);
16280    }
16281
16282    pub fn stage_or_unstage_diff_hunks(
16283        &mut self,
16284        stage: bool,
16285        ranges: Vec<Range<Anchor>>,
16286        cx: &mut Context<Self>,
16287    ) {
16288        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16289        cx.spawn(async move |this, cx| {
16290            task.await?;
16291            this.update(cx, |this, cx| {
16292                let snapshot = this.buffer.read(cx).snapshot(cx);
16293                let chunk_by = this
16294                    .diff_hunks_in_ranges(&ranges, &snapshot)
16295                    .chunk_by(|hunk| hunk.buffer_id);
16296                for (buffer_id, hunks) in &chunk_by {
16297                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16298                }
16299            })
16300        })
16301        .detach_and_log_err(cx);
16302    }
16303
16304    fn save_buffers_for_ranges_if_needed(
16305        &mut self,
16306        ranges: &[Range<Anchor>],
16307        cx: &mut Context<Editor>,
16308    ) -> Task<Result<()>> {
16309        let multibuffer = self.buffer.read(cx);
16310        let snapshot = multibuffer.read(cx);
16311        let buffer_ids: HashSet<_> = ranges
16312            .iter()
16313            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16314            .collect();
16315        drop(snapshot);
16316
16317        let mut buffers = HashSet::default();
16318        for buffer_id in buffer_ids {
16319            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16320                let buffer = buffer_entity.read(cx);
16321                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16322                {
16323                    buffers.insert(buffer_entity);
16324                }
16325            }
16326        }
16327
16328        if let Some(project) = &self.project {
16329            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16330        } else {
16331            Task::ready(Ok(()))
16332        }
16333    }
16334
16335    fn do_stage_or_unstage_and_next(
16336        &mut self,
16337        stage: bool,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) {
16341        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16342
16343        if ranges.iter().any(|range| range.start != range.end) {
16344            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16345            return;
16346        }
16347
16348        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16349        let snapshot = self.snapshot(window, cx);
16350        let position = self.selections.newest::<Point>(cx).head();
16351        let mut row = snapshot
16352            .buffer_snapshot
16353            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16354            .find(|hunk| hunk.row_range.start.0 > position.row)
16355            .map(|hunk| hunk.row_range.start);
16356
16357        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16358        // Outside of the project diff editor, wrap around to the beginning.
16359        if !all_diff_hunks_expanded {
16360            row = row.or_else(|| {
16361                snapshot
16362                    .buffer_snapshot
16363                    .diff_hunks_in_range(Point::zero()..position)
16364                    .find(|hunk| hunk.row_range.end.0 < position.row)
16365                    .map(|hunk| hunk.row_range.start)
16366            });
16367        }
16368
16369        if let Some(row) = row {
16370            let destination = Point::new(row.0, 0);
16371            let autoscroll = Autoscroll::center();
16372
16373            self.unfold_ranges(&[destination..destination], false, false, cx);
16374            self.change_selections(Some(autoscroll), window, cx, |s| {
16375                s.select_ranges([destination..destination]);
16376            });
16377        }
16378    }
16379
16380    fn do_stage_or_unstage(
16381        &self,
16382        stage: bool,
16383        buffer_id: BufferId,
16384        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16385        cx: &mut App,
16386    ) -> Option<()> {
16387        let project = self.project.as_ref()?;
16388        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16389        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16390        let buffer_snapshot = buffer.read(cx).snapshot();
16391        let file_exists = buffer_snapshot
16392            .file()
16393            .is_some_and(|file| file.disk_state().exists());
16394        diff.update(cx, |diff, cx| {
16395            diff.stage_or_unstage_hunks(
16396                stage,
16397                &hunks
16398                    .map(|hunk| buffer_diff::DiffHunk {
16399                        buffer_range: hunk.buffer_range,
16400                        diff_base_byte_range: hunk.diff_base_byte_range,
16401                        secondary_status: hunk.secondary_status,
16402                        range: Point::zero()..Point::zero(), // unused
16403                    })
16404                    .collect::<Vec<_>>(),
16405                &buffer_snapshot,
16406                file_exists,
16407                cx,
16408            )
16409        });
16410        None
16411    }
16412
16413    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16414        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16415        self.buffer
16416            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16417    }
16418
16419    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16420        self.buffer.update(cx, |buffer, cx| {
16421            let ranges = vec![Anchor::min()..Anchor::max()];
16422            if !buffer.all_diff_hunks_expanded()
16423                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16424            {
16425                buffer.collapse_diff_hunks(ranges, cx);
16426                true
16427            } else {
16428                false
16429            }
16430        })
16431    }
16432
16433    fn toggle_diff_hunks_in_ranges(
16434        &mut self,
16435        ranges: Vec<Range<Anchor>>,
16436        cx: &mut Context<Editor>,
16437    ) {
16438        self.buffer.update(cx, |buffer, cx| {
16439            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16440            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16441        })
16442    }
16443
16444    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16445        self.buffer.update(cx, |buffer, cx| {
16446            let snapshot = buffer.snapshot(cx);
16447            let excerpt_id = range.end.excerpt_id;
16448            let point_range = range.to_point(&snapshot);
16449            let expand = !buffer.single_hunk_is_expanded(range, cx);
16450            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16451        })
16452    }
16453
16454    pub(crate) fn apply_all_diff_hunks(
16455        &mut self,
16456        _: &ApplyAllDiffHunks,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) {
16460        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16461
16462        let buffers = self.buffer.read(cx).all_buffers();
16463        for branch_buffer in buffers {
16464            branch_buffer.update(cx, |branch_buffer, cx| {
16465                branch_buffer.merge_into_base(Vec::new(), cx);
16466            });
16467        }
16468
16469        if let Some(project) = self.project.clone() {
16470            self.save(true, project, window, cx).detach_and_log_err(cx);
16471        }
16472    }
16473
16474    pub(crate) fn apply_selected_diff_hunks(
16475        &mut self,
16476        _: &ApplyDiffHunk,
16477        window: &mut Window,
16478        cx: &mut Context<Self>,
16479    ) {
16480        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16481        let snapshot = self.snapshot(window, cx);
16482        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16483        let mut ranges_by_buffer = HashMap::default();
16484        self.transact(window, cx, |editor, _window, cx| {
16485            for hunk in hunks {
16486                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16487                    ranges_by_buffer
16488                        .entry(buffer.clone())
16489                        .or_insert_with(Vec::new)
16490                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16491                }
16492            }
16493
16494            for (buffer, ranges) in ranges_by_buffer {
16495                buffer.update(cx, |buffer, cx| {
16496                    buffer.merge_into_base(ranges, cx);
16497                });
16498            }
16499        });
16500
16501        if let Some(project) = self.project.clone() {
16502            self.save(true, project, window, cx).detach_and_log_err(cx);
16503        }
16504    }
16505
16506    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16507        if hovered != self.gutter_hovered {
16508            self.gutter_hovered = hovered;
16509            cx.notify();
16510        }
16511    }
16512
16513    pub fn insert_blocks(
16514        &mut self,
16515        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16516        autoscroll: Option<Autoscroll>,
16517        cx: &mut Context<Self>,
16518    ) -> Vec<CustomBlockId> {
16519        let blocks = self
16520            .display_map
16521            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16522        if let Some(autoscroll) = autoscroll {
16523            self.request_autoscroll(autoscroll, cx);
16524        }
16525        cx.notify();
16526        blocks
16527    }
16528
16529    pub fn resize_blocks(
16530        &mut self,
16531        heights: HashMap<CustomBlockId, u32>,
16532        autoscroll: Option<Autoscroll>,
16533        cx: &mut Context<Self>,
16534    ) {
16535        self.display_map
16536            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16537        if let Some(autoscroll) = autoscroll {
16538            self.request_autoscroll(autoscroll, cx);
16539        }
16540        cx.notify();
16541    }
16542
16543    pub fn replace_blocks(
16544        &mut self,
16545        renderers: HashMap<CustomBlockId, RenderBlock>,
16546        autoscroll: Option<Autoscroll>,
16547        cx: &mut Context<Self>,
16548    ) {
16549        self.display_map
16550            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16551        if let Some(autoscroll) = autoscroll {
16552            self.request_autoscroll(autoscroll, cx);
16553        }
16554        cx.notify();
16555    }
16556
16557    pub fn remove_blocks(
16558        &mut self,
16559        block_ids: HashSet<CustomBlockId>,
16560        autoscroll: Option<Autoscroll>,
16561        cx: &mut Context<Self>,
16562    ) {
16563        self.display_map.update(cx, |display_map, cx| {
16564            display_map.remove_blocks(block_ids, cx)
16565        });
16566        if let Some(autoscroll) = autoscroll {
16567            self.request_autoscroll(autoscroll, cx);
16568        }
16569        cx.notify();
16570    }
16571
16572    pub fn row_for_block(
16573        &self,
16574        block_id: CustomBlockId,
16575        cx: &mut Context<Self>,
16576    ) -> Option<DisplayRow> {
16577        self.display_map
16578            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16579    }
16580
16581    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16582        self.focused_block = Some(focused_block);
16583    }
16584
16585    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16586        self.focused_block.take()
16587    }
16588
16589    pub fn insert_creases(
16590        &mut self,
16591        creases: impl IntoIterator<Item = Crease<Anchor>>,
16592        cx: &mut Context<Self>,
16593    ) -> Vec<CreaseId> {
16594        self.display_map
16595            .update(cx, |map, cx| map.insert_creases(creases, cx))
16596    }
16597
16598    pub fn remove_creases(
16599        &mut self,
16600        ids: impl IntoIterator<Item = CreaseId>,
16601        cx: &mut Context<Self>,
16602    ) -> Vec<(CreaseId, Range<Anchor>)> {
16603        self.display_map
16604            .update(cx, |map, cx| map.remove_creases(ids, cx))
16605    }
16606
16607    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16608        self.display_map
16609            .update(cx, |map, cx| map.snapshot(cx))
16610            .longest_row()
16611    }
16612
16613    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16614        self.display_map
16615            .update(cx, |map, cx| map.snapshot(cx))
16616            .max_point()
16617    }
16618
16619    pub fn text(&self, cx: &App) -> String {
16620        self.buffer.read(cx).read(cx).text()
16621    }
16622
16623    pub fn is_empty(&self, cx: &App) -> bool {
16624        self.buffer.read(cx).read(cx).is_empty()
16625    }
16626
16627    pub fn text_option(&self, cx: &App) -> Option<String> {
16628        let text = self.text(cx);
16629        let text = text.trim();
16630
16631        if text.is_empty() {
16632            return None;
16633        }
16634
16635        Some(text.to_string())
16636    }
16637
16638    pub fn set_text(
16639        &mut self,
16640        text: impl Into<Arc<str>>,
16641        window: &mut Window,
16642        cx: &mut Context<Self>,
16643    ) {
16644        self.transact(window, cx, |this, _, cx| {
16645            this.buffer
16646                .read(cx)
16647                .as_singleton()
16648                .expect("you can only call set_text on editors for singleton buffers")
16649                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16650        });
16651    }
16652
16653    pub fn display_text(&self, cx: &mut App) -> String {
16654        self.display_map
16655            .update(cx, |map, cx| map.snapshot(cx))
16656            .text()
16657    }
16658
16659    fn create_minimap(
16660        &self,
16661        minimap_settings: MinimapSettings,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) -> Option<Entity<Self>> {
16665        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16666            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16667    }
16668
16669    fn initialize_new_minimap(
16670        &self,
16671        minimap_settings: MinimapSettings,
16672        window: &mut Window,
16673        cx: &mut Context<Self>,
16674    ) -> Entity<Self> {
16675        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16676
16677        let mut minimap = Editor::new_internal(
16678            EditorMode::Minimap {
16679                parent: cx.weak_entity(),
16680            },
16681            self.buffer.clone(),
16682            self.project.clone(),
16683            Some(self.display_map.clone()),
16684            window,
16685            cx,
16686        );
16687        minimap.scroll_manager.clone_state(&self.scroll_manager);
16688        minimap.set_text_style_refinement(TextStyleRefinement {
16689            font_size: Some(MINIMAP_FONT_SIZE),
16690            font_weight: Some(MINIMAP_FONT_WEIGHT),
16691            ..Default::default()
16692        });
16693        minimap.update_minimap_configuration(minimap_settings, cx);
16694        cx.new(|_| minimap)
16695    }
16696
16697    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16698        let current_line_highlight = minimap_settings
16699            .current_line_highlight
16700            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16701        self.set_current_line_highlight(Some(current_line_highlight));
16702    }
16703
16704    pub fn minimap(&self) -> Option<&Entity<Self>> {
16705        self.minimap
16706            .as_ref()
16707            .filter(|_| self.minimap_visibility.visible())
16708    }
16709
16710    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16711        let mut wrap_guides = smallvec![];
16712
16713        if self.show_wrap_guides == Some(false) {
16714            return wrap_guides;
16715        }
16716
16717        let settings = self.buffer.read(cx).language_settings(cx);
16718        if settings.show_wrap_guides {
16719            match self.soft_wrap_mode(cx) {
16720                SoftWrap::Column(soft_wrap) => {
16721                    wrap_guides.push((soft_wrap as usize, true));
16722                }
16723                SoftWrap::Bounded(soft_wrap) => {
16724                    wrap_guides.push((soft_wrap as usize, true));
16725                }
16726                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16727            }
16728            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16729        }
16730
16731        wrap_guides
16732    }
16733
16734    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16735        let settings = self.buffer.read(cx).language_settings(cx);
16736        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16737        match mode {
16738            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16739                SoftWrap::None
16740            }
16741            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16742            language_settings::SoftWrap::PreferredLineLength => {
16743                SoftWrap::Column(settings.preferred_line_length)
16744            }
16745            language_settings::SoftWrap::Bounded => {
16746                SoftWrap::Bounded(settings.preferred_line_length)
16747            }
16748        }
16749    }
16750
16751    pub fn set_soft_wrap_mode(
16752        &mut self,
16753        mode: language_settings::SoftWrap,
16754
16755        cx: &mut Context<Self>,
16756    ) {
16757        self.soft_wrap_mode_override = Some(mode);
16758        cx.notify();
16759    }
16760
16761    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16762        self.hard_wrap = hard_wrap;
16763        cx.notify();
16764    }
16765
16766    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16767        self.text_style_refinement = Some(style);
16768    }
16769
16770    /// called by the Element so we know what style we were most recently rendered with.
16771    pub(crate) fn set_style(
16772        &mut self,
16773        style: EditorStyle,
16774        window: &mut Window,
16775        cx: &mut Context<Self>,
16776    ) {
16777        // We intentionally do not inform the display map about the minimap style
16778        // so that wrapping is not recalculated and stays consistent for the editor
16779        // and its linked minimap.
16780        if !self.mode.is_minimap() {
16781            let rem_size = window.rem_size();
16782            self.display_map.update(cx, |map, cx| {
16783                map.set_font(
16784                    style.text.font(),
16785                    style.text.font_size.to_pixels(rem_size),
16786                    cx,
16787                )
16788            });
16789        }
16790        self.style = Some(style);
16791    }
16792
16793    pub fn style(&self) -> Option<&EditorStyle> {
16794        self.style.as_ref()
16795    }
16796
16797    // Called by the element. This method is not designed to be called outside of the editor
16798    // element's layout code because it does not notify when rewrapping is computed synchronously.
16799    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16800        self.display_map
16801            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16802    }
16803
16804    pub fn set_soft_wrap(&mut self) {
16805        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16806    }
16807
16808    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16809        if self.soft_wrap_mode_override.is_some() {
16810            self.soft_wrap_mode_override.take();
16811        } else {
16812            let soft_wrap = match self.soft_wrap_mode(cx) {
16813                SoftWrap::GitDiff => return,
16814                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16815                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16816                    language_settings::SoftWrap::None
16817                }
16818            };
16819            self.soft_wrap_mode_override = Some(soft_wrap);
16820        }
16821        cx.notify();
16822    }
16823
16824    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16825        let Some(workspace) = self.workspace() else {
16826            return;
16827        };
16828        let fs = workspace.read(cx).app_state().fs.clone();
16829        let current_show = TabBarSettings::get_global(cx).show;
16830        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16831            setting.show = Some(!current_show);
16832        });
16833    }
16834
16835    pub fn toggle_indent_guides(
16836        &mut self,
16837        _: &ToggleIndentGuides,
16838        _: &mut Window,
16839        cx: &mut Context<Self>,
16840    ) {
16841        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16842            self.buffer
16843                .read(cx)
16844                .language_settings(cx)
16845                .indent_guides
16846                .enabled
16847        });
16848        self.show_indent_guides = Some(!currently_enabled);
16849        cx.notify();
16850    }
16851
16852    fn should_show_indent_guides(&self) -> Option<bool> {
16853        self.show_indent_guides
16854    }
16855
16856    pub fn toggle_line_numbers(
16857        &mut self,
16858        _: &ToggleLineNumbers,
16859        _: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let mut editor_settings = EditorSettings::get_global(cx).clone();
16863        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16864        EditorSettings::override_global(editor_settings, cx);
16865    }
16866
16867    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16868        if let Some(show_line_numbers) = self.show_line_numbers {
16869            return show_line_numbers;
16870        }
16871        EditorSettings::get_global(cx).gutter.line_numbers
16872    }
16873
16874    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16875        self.use_relative_line_numbers
16876            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16877    }
16878
16879    pub fn toggle_relative_line_numbers(
16880        &mut self,
16881        _: &ToggleRelativeLineNumbers,
16882        _: &mut Window,
16883        cx: &mut Context<Self>,
16884    ) {
16885        let is_relative = self.should_use_relative_line_numbers(cx);
16886        self.set_relative_line_number(Some(!is_relative), cx)
16887    }
16888
16889    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16890        self.use_relative_line_numbers = is_relative;
16891        cx.notify();
16892    }
16893
16894    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16895        self.show_gutter = show_gutter;
16896        cx.notify();
16897    }
16898
16899    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16900        self.show_scrollbars = show_scrollbars;
16901        cx.notify();
16902    }
16903
16904    pub fn set_minimap_visibility(
16905        &mut self,
16906        minimap_visibility: MinimapVisibility,
16907        window: &mut Window,
16908        cx: &mut Context<Self>,
16909    ) {
16910        if self.minimap_visibility != minimap_visibility {
16911            if minimap_visibility.visible() && self.minimap.is_none() {
16912                let minimap_settings = EditorSettings::get_global(cx).minimap;
16913                self.minimap =
16914                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16915            }
16916            self.minimap_visibility = minimap_visibility;
16917            cx.notify();
16918        }
16919    }
16920
16921    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16922        self.set_show_scrollbars(false, cx);
16923        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16924    }
16925
16926    /// Normally the text in full mode and auto height editors is padded on the
16927    /// left side by roughly half a character width for improved hit testing.
16928    ///
16929    /// Use this method to disable this for cases where this is not wanted (e.g.
16930    /// if you want to align the editor text with some other text above or below)
16931    /// or if you want to add this padding to single-line editors.
16932    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
16933        self.offset_content = offset_content;
16934        cx.notify();
16935    }
16936
16937    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16938        self.show_line_numbers = Some(show_line_numbers);
16939        cx.notify();
16940    }
16941
16942    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16943        self.disable_expand_excerpt_buttons = true;
16944        cx.notify();
16945    }
16946
16947    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16948        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16949        cx.notify();
16950    }
16951
16952    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16953        self.show_code_actions = Some(show_code_actions);
16954        cx.notify();
16955    }
16956
16957    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16958        self.show_runnables = Some(show_runnables);
16959        cx.notify();
16960    }
16961
16962    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16963        self.show_breakpoints = Some(show_breakpoints);
16964        cx.notify();
16965    }
16966
16967    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16968        if self.display_map.read(cx).masked != masked {
16969            self.display_map.update(cx, |map, _| map.masked = masked);
16970        }
16971        cx.notify()
16972    }
16973
16974    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16975        self.show_wrap_guides = Some(show_wrap_guides);
16976        cx.notify();
16977    }
16978
16979    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16980        self.show_indent_guides = Some(show_indent_guides);
16981        cx.notify();
16982    }
16983
16984    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16985        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16986            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16987                if let Some(dir) = file.abs_path(cx).parent() {
16988                    return Some(dir.to_owned());
16989                }
16990            }
16991
16992            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16993                return Some(project_path.path.to_path_buf());
16994            }
16995        }
16996
16997        None
16998    }
16999
17000    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17001        self.active_excerpt(cx)?
17002            .1
17003            .read(cx)
17004            .file()
17005            .and_then(|f| f.as_local())
17006    }
17007
17008    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17009        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17010            let buffer = buffer.read(cx);
17011            if let Some(project_path) = buffer.project_path(cx) {
17012                let project = self.project.as_ref()?.read(cx);
17013                project.absolute_path(&project_path, cx)
17014            } else {
17015                buffer
17016                    .file()
17017                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17018            }
17019        })
17020    }
17021
17022    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17023        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17024            let project_path = buffer.read(cx).project_path(cx)?;
17025            let project = self.project.as_ref()?.read(cx);
17026            let entry = project.entry_for_path(&project_path, cx)?;
17027            let path = entry.path.to_path_buf();
17028            Some(path)
17029        })
17030    }
17031
17032    pub fn reveal_in_finder(
17033        &mut self,
17034        _: &RevealInFileManager,
17035        _window: &mut Window,
17036        cx: &mut Context<Self>,
17037    ) {
17038        if let Some(target) = self.target_file(cx) {
17039            cx.reveal_path(&target.abs_path(cx));
17040        }
17041    }
17042
17043    pub fn copy_path(
17044        &mut self,
17045        _: &zed_actions::workspace::CopyPath,
17046        _window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        if let Some(path) = self.target_file_abs_path(cx) {
17050            if let Some(path) = path.to_str() {
17051                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17052            }
17053        }
17054    }
17055
17056    pub fn copy_relative_path(
17057        &mut self,
17058        _: &zed_actions::workspace::CopyRelativePath,
17059        _window: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) {
17062        if let Some(path) = self.target_file_path(cx) {
17063            if let Some(path) = path.to_str() {
17064                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17065            }
17066        }
17067    }
17068
17069    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17070        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17071            buffer.read(cx).project_path(cx)
17072        } else {
17073            None
17074        }
17075    }
17076
17077    // Returns true if the editor handled a go-to-line request
17078    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17079        maybe!({
17080            let breakpoint_store = self.breakpoint_store.as_ref()?;
17081
17082            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17083            else {
17084                self.clear_row_highlights::<ActiveDebugLine>();
17085                return None;
17086            };
17087
17088            let position = active_stack_frame.position;
17089            let buffer_id = position.buffer_id?;
17090            let snapshot = self
17091                .project
17092                .as_ref()?
17093                .read(cx)
17094                .buffer_for_id(buffer_id, cx)?
17095                .read(cx)
17096                .snapshot();
17097
17098            let mut handled = false;
17099            for (id, ExcerptRange { context, .. }) in
17100                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17101            {
17102                if context.start.cmp(&position, &snapshot).is_ge()
17103                    || context.end.cmp(&position, &snapshot).is_lt()
17104                {
17105                    continue;
17106                }
17107                let snapshot = self.buffer.read(cx).snapshot(cx);
17108                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17109
17110                handled = true;
17111                self.clear_row_highlights::<ActiveDebugLine>();
17112
17113                self.go_to_line::<ActiveDebugLine>(
17114                    multibuffer_anchor,
17115                    Some(cx.theme().colors().editor_debugger_active_line_background),
17116                    window,
17117                    cx,
17118                );
17119
17120                cx.notify();
17121            }
17122
17123            handled.then_some(())
17124        })
17125        .is_some()
17126    }
17127
17128    pub fn copy_file_name_without_extension(
17129        &mut self,
17130        _: &CopyFileNameWithoutExtension,
17131        _: &mut Window,
17132        cx: &mut Context<Self>,
17133    ) {
17134        if let Some(file) = self.target_file(cx) {
17135            if let Some(file_stem) = file.path().file_stem() {
17136                if let Some(name) = file_stem.to_str() {
17137                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17138                }
17139            }
17140        }
17141    }
17142
17143    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17144        if let Some(file) = self.target_file(cx) {
17145            if let Some(file_name) = file.path().file_name() {
17146                if let Some(name) = file_name.to_str() {
17147                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17148                }
17149            }
17150        }
17151    }
17152
17153    pub fn toggle_git_blame(
17154        &mut self,
17155        _: &::git::Blame,
17156        window: &mut Window,
17157        cx: &mut Context<Self>,
17158    ) {
17159        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17160
17161        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17162            self.start_git_blame(true, window, cx);
17163        }
17164
17165        cx.notify();
17166    }
17167
17168    pub fn toggle_git_blame_inline(
17169        &mut self,
17170        _: &ToggleGitBlameInline,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) {
17174        self.toggle_git_blame_inline_internal(true, window, cx);
17175        cx.notify();
17176    }
17177
17178    pub fn open_git_blame_commit(
17179        &mut self,
17180        _: &OpenGitBlameCommit,
17181        window: &mut Window,
17182        cx: &mut Context<Self>,
17183    ) {
17184        self.open_git_blame_commit_internal(window, cx);
17185    }
17186
17187    fn open_git_blame_commit_internal(
17188        &mut self,
17189        window: &mut Window,
17190        cx: &mut Context<Self>,
17191    ) -> Option<()> {
17192        let blame = self.blame.as_ref()?;
17193        let snapshot = self.snapshot(window, cx);
17194        let cursor = self.selections.newest::<Point>(cx).head();
17195        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17196        let blame_entry = blame
17197            .update(cx, |blame, cx| {
17198                blame
17199                    .blame_for_rows(
17200                        &[RowInfo {
17201                            buffer_id: Some(buffer.remote_id()),
17202                            buffer_row: Some(point.row),
17203                            ..Default::default()
17204                        }],
17205                        cx,
17206                    )
17207                    .next()
17208            })
17209            .flatten()?;
17210        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17211        let repo = blame.read(cx).repository(cx)?;
17212        let workspace = self.workspace()?.downgrade();
17213        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17214        None
17215    }
17216
17217    pub fn git_blame_inline_enabled(&self) -> bool {
17218        self.git_blame_inline_enabled
17219    }
17220
17221    pub fn toggle_selection_menu(
17222        &mut self,
17223        _: &ToggleSelectionMenu,
17224        _: &mut Window,
17225        cx: &mut Context<Self>,
17226    ) {
17227        self.show_selection_menu = self
17228            .show_selection_menu
17229            .map(|show_selections_menu| !show_selections_menu)
17230            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17231
17232        cx.notify();
17233    }
17234
17235    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17236        self.show_selection_menu
17237            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17238    }
17239
17240    fn start_git_blame(
17241        &mut self,
17242        user_triggered: bool,
17243        window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) {
17246        if let Some(project) = self.project.as_ref() {
17247            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17248                return;
17249            };
17250
17251            if buffer.read(cx).file().is_none() {
17252                return;
17253            }
17254
17255            let focused = self.focus_handle(cx).contains_focused(window, cx);
17256
17257            let project = project.clone();
17258            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17259            self.blame_subscription =
17260                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17261            self.blame = Some(blame);
17262        }
17263    }
17264
17265    fn toggle_git_blame_inline_internal(
17266        &mut self,
17267        user_triggered: bool,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270    ) {
17271        if self.git_blame_inline_enabled {
17272            self.git_blame_inline_enabled = false;
17273            self.show_git_blame_inline = false;
17274            self.show_git_blame_inline_delay_task.take();
17275        } else {
17276            self.git_blame_inline_enabled = true;
17277            self.start_git_blame_inline(user_triggered, window, cx);
17278        }
17279
17280        cx.notify();
17281    }
17282
17283    fn start_git_blame_inline(
17284        &mut self,
17285        user_triggered: bool,
17286        window: &mut Window,
17287        cx: &mut Context<Self>,
17288    ) {
17289        self.start_git_blame(user_triggered, window, cx);
17290
17291        if ProjectSettings::get_global(cx)
17292            .git
17293            .inline_blame_delay()
17294            .is_some()
17295        {
17296            self.start_inline_blame_timer(window, cx);
17297        } else {
17298            self.show_git_blame_inline = true
17299        }
17300    }
17301
17302    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17303        self.blame.as_ref()
17304    }
17305
17306    pub fn show_git_blame_gutter(&self) -> bool {
17307        self.show_git_blame_gutter
17308    }
17309
17310    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17311        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17312    }
17313
17314    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17315        self.show_git_blame_inline
17316            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17317            && !self.newest_selection_head_on_empty_line(cx)
17318            && self.has_blame_entries(cx)
17319    }
17320
17321    fn has_blame_entries(&self, cx: &App) -> bool {
17322        self.blame()
17323            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17324    }
17325
17326    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17327        let cursor_anchor = self.selections.newest_anchor().head();
17328
17329        let snapshot = self.buffer.read(cx).snapshot(cx);
17330        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17331
17332        snapshot.line_len(buffer_row) == 0
17333    }
17334
17335    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17336        let buffer_and_selection = maybe!({
17337            let selection = self.selections.newest::<Point>(cx);
17338            let selection_range = selection.range();
17339
17340            let multi_buffer = self.buffer().read(cx);
17341            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17342            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17343
17344            let (buffer, range, _) = if selection.reversed {
17345                buffer_ranges.first()
17346            } else {
17347                buffer_ranges.last()
17348            }?;
17349
17350            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17351                ..text::ToPoint::to_point(&range.end, &buffer).row;
17352            Some((
17353                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17354                selection,
17355            ))
17356        });
17357
17358        let Some((buffer, selection)) = buffer_and_selection else {
17359            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17360        };
17361
17362        let Some(project) = self.project.as_ref() else {
17363            return Task::ready(Err(anyhow!("editor does not have project")));
17364        };
17365
17366        project.update(cx, |project, cx| {
17367            project.get_permalink_to_line(&buffer, selection, cx)
17368        })
17369    }
17370
17371    pub fn copy_permalink_to_line(
17372        &mut self,
17373        _: &CopyPermalinkToLine,
17374        window: &mut Window,
17375        cx: &mut Context<Self>,
17376    ) {
17377        let permalink_task = self.get_permalink_to_line(cx);
17378        let workspace = self.workspace();
17379
17380        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17381            Ok(permalink) => {
17382                cx.update(|_, cx| {
17383                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17384                })
17385                .ok();
17386            }
17387            Err(err) => {
17388                let message = format!("Failed to copy permalink: {err}");
17389
17390                anyhow::Result::<()>::Err(err).log_err();
17391
17392                if let Some(workspace) = workspace {
17393                    workspace
17394                        .update_in(cx, |workspace, _, cx| {
17395                            struct CopyPermalinkToLine;
17396
17397                            workspace.show_toast(
17398                                Toast::new(
17399                                    NotificationId::unique::<CopyPermalinkToLine>(),
17400                                    message,
17401                                ),
17402                                cx,
17403                            )
17404                        })
17405                        .ok();
17406                }
17407            }
17408        })
17409        .detach();
17410    }
17411
17412    pub fn copy_file_location(
17413        &mut self,
17414        _: &CopyFileLocation,
17415        _: &mut Window,
17416        cx: &mut Context<Self>,
17417    ) {
17418        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17419        if let Some(file) = self.target_file(cx) {
17420            if let Some(path) = file.path().to_str() {
17421                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17422            }
17423        }
17424    }
17425
17426    pub fn open_permalink_to_line(
17427        &mut self,
17428        _: &OpenPermalinkToLine,
17429        window: &mut Window,
17430        cx: &mut Context<Self>,
17431    ) {
17432        let permalink_task = self.get_permalink_to_line(cx);
17433        let workspace = self.workspace();
17434
17435        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17436            Ok(permalink) => {
17437                cx.update(|_, cx| {
17438                    cx.open_url(permalink.as_ref());
17439                })
17440                .ok();
17441            }
17442            Err(err) => {
17443                let message = format!("Failed to open permalink: {err}");
17444
17445                anyhow::Result::<()>::Err(err).log_err();
17446
17447                if let Some(workspace) = workspace {
17448                    workspace
17449                        .update(cx, |workspace, cx| {
17450                            struct OpenPermalinkToLine;
17451
17452                            workspace.show_toast(
17453                                Toast::new(
17454                                    NotificationId::unique::<OpenPermalinkToLine>(),
17455                                    message,
17456                                ),
17457                                cx,
17458                            )
17459                        })
17460                        .ok();
17461                }
17462            }
17463        })
17464        .detach();
17465    }
17466
17467    pub fn insert_uuid_v4(
17468        &mut self,
17469        _: &InsertUuidV4,
17470        window: &mut Window,
17471        cx: &mut Context<Self>,
17472    ) {
17473        self.insert_uuid(UuidVersion::V4, window, cx);
17474    }
17475
17476    pub fn insert_uuid_v7(
17477        &mut self,
17478        _: &InsertUuidV7,
17479        window: &mut Window,
17480        cx: &mut Context<Self>,
17481    ) {
17482        self.insert_uuid(UuidVersion::V7, window, cx);
17483    }
17484
17485    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17486        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17487        self.transact(window, cx, |this, window, cx| {
17488            let edits = this
17489                .selections
17490                .all::<Point>(cx)
17491                .into_iter()
17492                .map(|selection| {
17493                    let uuid = match version {
17494                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17495                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17496                    };
17497
17498                    (selection.range(), uuid.to_string())
17499                });
17500            this.edit(edits, cx);
17501            this.refresh_inline_completion(true, false, window, cx);
17502        });
17503    }
17504
17505    pub fn open_selections_in_multibuffer(
17506        &mut self,
17507        _: &OpenSelectionsInMultibuffer,
17508        window: &mut Window,
17509        cx: &mut Context<Self>,
17510    ) {
17511        let multibuffer = self.buffer.read(cx);
17512
17513        let Some(buffer) = multibuffer.as_singleton() else {
17514            return;
17515        };
17516
17517        let Some(workspace) = self.workspace() else {
17518            return;
17519        };
17520
17521        let locations = self
17522            .selections
17523            .disjoint_anchors()
17524            .iter()
17525            .map(|selection| {
17526                let range = if selection.reversed {
17527                    selection.end.text_anchor..selection.start.text_anchor
17528                } else {
17529                    selection.start.text_anchor..selection.end.text_anchor
17530                };
17531                Location {
17532                    buffer: buffer.clone(),
17533                    range,
17534                }
17535            })
17536            .collect::<Vec<_>>();
17537
17538        let title = multibuffer.title(cx).to_string();
17539
17540        cx.spawn_in(window, async move |_, cx| {
17541            workspace.update_in(cx, |workspace, window, cx| {
17542                Self::open_locations_in_multibuffer(
17543                    workspace,
17544                    locations,
17545                    format!("Selections for '{title}'"),
17546                    false,
17547                    MultibufferSelectionMode::All,
17548                    window,
17549                    cx,
17550                );
17551            })
17552        })
17553        .detach();
17554    }
17555
17556    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17557    /// last highlight added will be used.
17558    ///
17559    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17560    pub fn highlight_rows<T: 'static>(
17561        &mut self,
17562        range: Range<Anchor>,
17563        color: Hsla,
17564        options: RowHighlightOptions,
17565        cx: &mut Context<Self>,
17566    ) {
17567        let snapshot = self.buffer().read(cx).snapshot(cx);
17568        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17569        let ix = row_highlights.binary_search_by(|highlight| {
17570            Ordering::Equal
17571                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17572                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17573        });
17574
17575        if let Err(mut ix) = ix {
17576            let index = post_inc(&mut self.highlight_order);
17577
17578            // If this range intersects with the preceding highlight, then merge it with
17579            // the preceding highlight. Otherwise insert a new highlight.
17580            let mut merged = false;
17581            if ix > 0 {
17582                let prev_highlight = &mut row_highlights[ix - 1];
17583                if prev_highlight
17584                    .range
17585                    .end
17586                    .cmp(&range.start, &snapshot)
17587                    .is_ge()
17588                {
17589                    ix -= 1;
17590                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17591                        prev_highlight.range.end = range.end;
17592                    }
17593                    merged = true;
17594                    prev_highlight.index = index;
17595                    prev_highlight.color = color;
17596                    prev_highlight.options = options;
17597                }
17598            }
17599
17600            if !merged {
17601                row_highlights.insert(
17602                    ix,
17603                    RowHighlight {
17604                        range: range.clone(),
17605                        index,
17606                        color,
17607                        options,
17608                        type_id: TypeId::of::<T>(),
17609                    },
17610                );
17611            }
17612
17613            // If any of the following highlights intersect with this one, merge them.
17614            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17615                let highlight = &row_highlights[ix];
17616                if next_highlight
17617                    .range
17618                    .start
17619                    .cmp(&highlight.range.end, &snapshot)
17620                    .is_le()
17621                {
17622                    if next_highlight
17623                        .range
17624                        .end
17625                        .cmp(&highlight.range.end, &snapshot)
17626                        .is_gt()
17627                    {
17628                        row_highlights[ix].range.end = next_highlight.range.end;
17629                    }
17630                    row_highlights.remove(ix + 1);
17631                } else {
17632                    break;
17633                }
17634            }
17635        }
17636    }
17637
17638    /// Remove any highlighted row ranges of the given type that intersect the
17639    /// given ranges.
17640    pub fn remove_highlighted_rows<T: 'static>(
17641        &mut self,
17642        ranges_to_remove: Vec<Range<Anchor>>,
17643        cx: &mut Context<Self>,
17644    ) {
17645        let snapshot = self.buffer().read(cx).snapshot(cx);
17646        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17647        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17648        row_highlights.retain(|highlight| {
17649            while let Some(range_to_remove) = ranges_to_remove.peek() {
17650                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17651                    Ordering::Less | Ordering::Equal => {
17652                        ranges_to_remove.next();
17653                    }
17654                    Ordering::Greater => {
17655                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17656                            Ordering::Less | Ordering::Equal => {
17657                                return false;
17658                            }
17659                            Ordering::Greater => break,
17660                        }
17661                    }
17662                }
17663            }
17664
17665            true
17666        })
17667    }
17668
17669    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17670    pub fn clear_row_highlights<T: 'static>(&mut self) {
17671        self.highlighted_rows.remove(&TypeId::of::<T>());
17672    }
17673
17674    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17675    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17676        self.highlighted_rows
17677            .get(&TypeId::of::<T>())
17678            .map_or(&[] as &[_], |vec| vec.as_slice())
17679            .iter()
17680            .map(|highlight| (highlight.range.clone(), highlight.color))
17681    }
17682
17683    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17684    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17685    /// Allows to ignore certain kinds of highlights.
17686    pub fn highlighted_display_rows(
17687        &self,
17688        window: &mut Window,
17689        cx: &mut App,
17690    ) -> BTreeMap<DisplayRow, LineHighlight> {
17691        let snapshot = self.snapshot(window, cx);
17692        let mut used_highlight_orders = HashMap::default();
17693        self.highlighted_rows
17694            .iter()
17695            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17696            .fold(
17697                BTreeMap::<DisplayRow, LineHighlight>::new(),
17698                |mut unique_rows, highlight| {
17699                    let start = highlight.range.start.to_display_point(&snapshot);
17700                    let end = highlight.range.end.to_display_point(&snapshot);
17701                    let start_row = start.row().0;
17702                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17703                        && end.column() == 0
17704                    {
17705                        end.row().0.saturating_sub(1)
17706                    } else {
17707                        end.row().0
17708                    };
17709                    for row in start_row..=end_row {
17710                        let used_index =
17711                            used_highlight_orders.entry(row).or_insert(highlight.index);
17712                        if highlight.index >= *used_index {
17713                            *used_index = highlight.index;
17714                            unique_rows.insert(
17715                                DisplayRow(row),
17716                                LineHighlight {
17717                                    include_gutter: highlight.options.include_gutter,
17718                                    border: None,
17719                                    background: highlight.color.into(),
17720                                    type_id: Some(highlight.type_id),
17721                                },
17722                            );
17723                        }
17724                    }
17725                    unique_rows
17726                },
17727            )
17728    }
17729
17730    pub fn highlighted_display_row_for_autoscroll(
17731        &self,
17732        snapshot: &DisplaySnapshot,
17733    ) -> Option<DisplayRow> {
17734        self.highlighted_rows
17735            .values()
17736            .flat_map(|highlighted_rows| highlighted_rows.iter())
17737            .filter_map(|highlight| {
17738                if highlight.options.autoscroll {
17739                    Some(highlight.range.start.to_display_point(snapshot).row())
17740                } else {
17741                    None
17742                }
17743            })
17744            .min()
17745    }
17746
17747    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17748        self.highlight_background::<SearchWithinRange>(
17749            ranges,
17750            |colors| colors.editor_document_highlight_read_background,
17751            cx,
17752        )
17753    }
17754
17755    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17756        self.breadcrumb_header = Some(new_header);
17757    }
17758
17759    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17760        self.clear_background_highlights::<SearchWithinRange>(cx);
17761    }
17762
17763    pub fn highlight_background<T: 'static>(
17764        &mut self,
17765        ranges: &[Range<Anchor>],
17766        color_fetcher: fn(&ThemeColors) -> Hsla,
17767        cx: &mut Context<Self>,
17768    ) {
17769        self.background_highlights
17770            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17771        self.scrollbar_marker_state.dirty = true;
17772        cx.notify();
17773    }
17774
17775    pub fn clear_background_highlights<T: 'static>(
17776        &mut self,
17777        cx: &mut Context<Self>,
17778    ) -> Option<BackgroundHighlight> {
17779        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17780        if !text_highlights.1.is_empty() {
17781            self.scrollbar_marker_state.dirty = true;
17782            cx.notify();
17783        }
17784        Some(text_highlights)
17785    }
17786
17787    pub fn highlight_gutter<T: 'static>(
17788        &mut self,
17789        ranges: &[Range<Anchor>],
17790        color_fetcher: fn(&App) -> Hsla,
17791        cx: &mut Context<Self>,
17792    ) {
17793        self.gutter_highlights
17794            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17795        cx.notify();
17796    }
17797
17798    pub fn clear_gutter_highlights<T: 'static>(
17799        &mut self,
17800        cx: &mut Context<Self>,
17801    ) -> Option<GutterHighlight> {
17802        cx.notify();
17803        self.gutter_highlights.remove(&TypeId::of::<T>())
17804    }
17805
17806    #[cfg(feature = "test-support")]
17807    pub fn all_text_background_highlights(
17808        &self,
17809        window: &mut Window,
17810        cx: &mut Context<Self>,
17811    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17812        let snapshot = self.snapshot(window, cx);
17813        let buffer = &snapshot.buffer_snapshot;
17814        let start = buffer.anchor_before(0);
17815        let end = buffer.anchor_after(buffer.len());
17816        let theme = cx.theme().colors();
17817        self.background_highlights_in_range(start..end, &snapshot, theme)
17818    }
17819
17820    #[cfg(feature = "test-support")]
17821    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17822        let snapshot = self.buffer().read(cx).snapshot(cx);
17823
17824        let highlights = self
17825            .background_highlights
17826            .get(&TypeId::of::<items::BufferSearchHighlights>());
17827
17828        if let Some((_color, ranges)) = highlights {
17829            ranges
17830                .iter()
17831                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17832                .collect_vec()
17833        } else {
17834            vec![]
17835        }
17836    }
17837
17838    fn document_highlights_for_position<'a>(
17839        &'a self,
17840        position: Anchor,
17841        buffer: &'a MultiBufferSnapshot,
17842    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17843        let read_highlights = self
17844            .background_highlights
17845            .get(&TypeId::of::<DocumentHighlightRead>())
17846            .map(|h| &h.1);
17847        let write_highlights = self
17848            .background_highlights
17849            .get(&TypeId::of::<DocumentHighlightWrite>())
17850            .map(|h| &h.1);
17851        let left_position = position.bias_left(buffer);
17852        let right_position = position.bias_right(buffer);
17853        read_highlights
17854            .into_iter()
17855            .chain(write_highlights)
17856            .flat_map(move |ranges| {
17857                let start_ix = match ranges.binary_search_by(|probe| {
17858                    let cmp = probe.end.cmp(&left_position, buffer);
17859                    if cmp.is_ge() {
17860                        Ordering::Greater
17861                    } else {
17862                        Ordering::Less
17863                    }
17864                }) {
17865                    Ok(i) | Err(i) => i,
17866                };
17867
17868                ranges[start_ix..]
17869                    .iter()
17870                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17871            })
17872    }
17873
17874    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17875        self.background_highlights
17876            .get(&TypeId::of::<T>())
17877            .map_or(false, |(_, highlights)| !highlights.is_empty())
17878    }
17879
17880    pub fn background_highlights_in_range(
17881        &self,
17882        search_range: Range<Anchor>,
17883        display_snapshot: &DisplaySnapshot,
17884        theme: &ThemeColors,
17885    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17886        let mut results = Vec::new();
17887        for (color_fetcher, ranges) in self.background_highlights.values() {
17888            let color = color_fetcher(theme);
17889            let start_ix = match ranges.binary_search_by(|probe| {
17890                let cmp = probe
17891                    .end
17892                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17893                if cmp.is_gt() {
17894                    Ordering::Greater
17895                } else {
17896                    Ordering::Less
17897                }
17898            }) {
17899                Ok(i) | Err(i) => i,
17900            };
17901            for range in &ranges[start_ix..] {
17902                if range
17903                    .start
17904                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17905                    .is_ge()
17906                {
17907                    break;
17908                }
17909
17910                let start = range.start.to_display_point(display_snapshot);
17911                let end = range.end.to_display_point(display_snapshot);
17912                results.push((start..end, color))
17913            }
17914        }
17915        results
17916    }
17917
17918    pub fn background_highlight_row_ranges<T: 'static>(
17919        &self,
17920        search_range: Range<Anchor>,
17921        display_snapshot: &DisplaySnapshot,
17922        count: usize,
17923    ) -> Vec<RangeInclusive<DisplayPoint>> {
17924        let mut results = Vec::new();
17925        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17926            return vec![];
17927        };
17928
17929        let start_ix = match ranges.binary_search_by(|probe| {
17930            let cmp = probe
17931                .end
17932                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17933            if cmp.is_gt() {
17934                Ordering::Greater
17935            } else {
17936                Ordering::Less
17937            }
17938        }) {
17939            Ok(i) | Err(i) => i,
17940        };
17941        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17942            if let (Some(start_display), Some(end_display)) = (start, end) {
17943                results.push(
17944                    start_display.to_display_point(display_snapshot)
17945                        ..=end_display.to_display_point(display_snapshot),
17946                );
17947            }
17948        };
17949        let mut start_row: Option<Point> = None;
17950        let mut end_row: Option<Point> = None;
17951        if ranges.len() > count {
17952            return Vec::new();
17953        }
17954        for range in &ranges[start_ix..] {
17955            if range
17956                .start
17957                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17958                .is_ge()
17959            {
17960                break;
17961            }
17962            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17963            if let Some(current_row) = &end_row {
17964                if end.row == current_row.row {
17965                    continue;
17966                }
17967            }
17968            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17969            if start_row.is_none() {
17970                assert_eq!(end_row, None);
17971                start_row = Some(start);
17972                end_row = Some(end);
17973                continue;
17974            }
17975            if let Some(current_end) = end_row.as_mut() {
17976                if start.row > current_end.row + 1 {
17977                    push_region(start_row, end_row);
17978                    start_row = Some(start);
17979                    end_row = Some(end);
17980                } else {
17981                    // Merge two hunks.
17982                    *current_end = end;
17983                }
17984            } else {
17985                unreachable!();
17986            }
17987        }
17988        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17989        push_region(start_row, end_row);
17990        results
17991    }
17992
17993    pub fn gutter_highlights_in_range(
17994        &self,
17995        search_range: Range<Anchor>,
17996        display_snapshot: &DisplaySnapshot,
17997        cx: &App,
17998    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17999        let mut results = Vec::new();
18000        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18001            let color = color_fetcher(cx);
18002            let start_ix = match ranges.binary_search_by(|probe| {
18003                let cmp = probe
18004                    .end
18005                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18006                if cmp.is_gt() {
18007                    Ordering::Greater
18008                } else {
18009                    Ordering::Less
18010                }
18011            }) {
18012                Ok(i) | Err(i) => i,
18013            };
18014            for range in &ranges[start_ix..] {
18015                if range
18016                    .start
18017                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18018                    .is_ge()
18019                {
18020                    break;
18021                }
18022
18023                let start = range.start.to_display_point(display_snapshot);
18024                let end = range.end.to_display_point(display_snapshot);
18025                results.push((start..end, color))
18026            }
18027        }
18028        results
18029    }
18030
18031    /// Get the text ranges corresponding to the redaction query
18032    pub fn redacted_ranges(
18033        &self,
18034        search_range: Range<Anchor>,
18035        display_snapshot: &DisplaySnapshot,
18036        cx: &App,
18037    ) -> Vec<Range<DisplayPoint>> {
18038        display_snapshot
18039            .buffer_snapshot
18040            .redacted_ranges(search_range, |file| {
18041                if let Some(file) = file {
18042                    file.is_private()
18043                        && EditorSettings::get(
18044                            Some(SettingsLocation {
18045                                worktree_id: file.worktree_id(cx),
18046                                path: file.path().as_ref(),
18047                            }),
18048                            cx,
18049                        )
18050                        .redact_private_values
18051                } else {
18052                    false
18053                }
18054            })
18055            .map(|range| {
18056                range.start.to_display_point(display_snapshot)
18057                    ..range.end.to_display_point(display_snapshot)
18058            })
18059            .collect()
18060    }
18061
18062    pub fn highlight_text<T: 'static>(
18063        &mut self,
18064        ranges: Vec<Range<Anchor>>,
18065        style: HighlightStyle,
18066        cx: &mut Context<Self>,
18067    ) {
18068        self.display_map.update(cx, |map, _| {
18069            map.highlight_text(TypeId::of::<T>(), ranges, style)
18070        });
18071        cx.notify();
18072    }
18073
18074    pub(crate) fn highlight_inlays<T: 'static>(
18075        &mut self,
18076        highlights: Vec<InlayHighlight>,
18077        style: HighlightStyle,
18078        cx: &mut Context<Self>,
18079    ) {
18080        self.display_map.update(cx, |map, _| {
18081            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18082        });
18083        cx.notify();
18084    }
18085
18086    pub fn text_highlights<'a, T: 'static>(
18087        &'a self,
18088        cx: &'a App,
18089    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18090        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18091    }
18092
18093    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18094        let cleared = self
18095            .display_map
18096            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18097        if cleared {
18098            cx.notify();
18099        }
18100    }
18101
18102    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18103        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18104            && self.focus_handle.is_focused(window)
18105    }
18106
18107    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18108        self.show_cursor_when_unfocused = is_enabled;
18109        cx.notify();
18110    }
18111
18112    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18113        cx.notify();
18114    }
18115
18116    fn on_debug_session_event(
18117        &mut self,
18118        _session: Entity<Session>,
18119        event: &SessionEvent,
18120        cx: &mut Context<Self>,
18121    ) {
18122        match event {
18123            SessionEvent::InvalidateInlineValue => {
18124                self.refresh_inline_values(cx);
18125            }
18126            _ => {}
18127        }
18128    }
18129
18130    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18131        let Some(project) = self.project.clone() else {
18132            return;
18133        };
18134
18135        if !self.inline_value_cache.enabled {
18136            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18137            self.splice_inlays(&inlays, Vec::new(), cx);
18138            return;
18139        }
18140
18141        let current_execution_position = self
18142            .highlighted_rows
18143            .get(&TypeId::of::<ActiveDebugLine>())
18144            .and_then(|lines| lines.last().map(|line| line.range.start));
18145
18146        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18147            let inline_values = editor
18148                .update(cx, |editor, cx| {
18149                    let Some(current_execution_position) = current_execution_position else {
18150                        return Some(Task::ready(Ok(Vec::new())));
18151                    };
18152
18153                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18154                        let snapshot = buffer.snapshot(cx);
18155
18156                        let excerpt = snapshot.excerpt_containing(
18157                            current_execution_position..current_execution_position,
18158                        )?;
18159
18160                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18161                    })?;
18162
18163                    let range =
18164                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18165
18166                    project.inline_values(buffer, range, cx)
18167                })
18168                .ok()
18169                .flatten()?
18170                .await
18171                .context("refreshing debugger inlays")
18172                .log_err()?;
18173
18174            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18175
18176            for (buffer_id, inline_value) in inline_values
18177                .into_iter()
18178                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18179            {
18180                buffer_inline_values
18181                    .entry(buffer_id)
18182                    .or_default()
18183                    .push(inline_value);
18184            }
18185
18186            editor
18187                .update(cx, |editor, cx| {
18188                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18189                    let mut new_inlays = Vec::default();
18190
18191                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18192                        let buffer_id = buffer_snapshot.remote_id();
18193                        buffer_inline_values
18194                            .get(&buffer_id)
18195                            .into_iter()
18196                            .flatten()
18197                            .for_each(|hint| {
18198                                let inlay = Inlay::debugger_hint(
18199                                    post_inc(&mut editor.next_inlay_id),
18200                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18201                                    hint.text(),
18202                                );
18203
18204                                new_inlays.push(inlay);
18205                            });
18206                    }
18207
18208                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18209                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18210
18211                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18212                })
18213                .ok()?;
18214            Some(())
18215        });
18216    }
18217
18218    fn on_buffer_event(
18219        &mut self,
18220        multibuffer: &Entity<MultiBuffer>,
18221        event: &multi_buffer::Event,
18222        window: &mut Window,
18223        cx: &mut Context<Self>,
18224    ) {
18225        match event {
18226            multi_buffer::Event::Edited {
18227                singleton_buffer_edited,
18228                edited_buffer: buffer_edited,
18229            } => {
18230                self.scrollbar_marker_state.dirty = true;
18231                self.active_indent_guides_state.dirty = true;
18232                self.refresh_active_diagnostics(cx);
18233                self.refresh_code_actions(window, cx);
18234                self.refresh_selected_text_highlights(true, window, cx);
18235                refresh_matching_bracket_highlights(self, window, cx);
18236                if self.has_active_inline_completion() {
18237                    self.update_visible_inline_completion(window, cx);
18238                }
18239                if let Some(buffer) = buffer_edited {
18240                    let buffer_id = buffer.read(cx).remote_id();
18241                    if !self.registered_buffers.contains_key(&buffer_id) {
18242                        if let Some(project) = self.project.as_ref() {
18243                            project.update(cx, |project, cx| {
18244                                self.registered_buffers.insert(
18245                                    buffer_id,
18246                                    project.register_buffer_with_language_servers(&buffer, cx),
18247                                );
18248                            })
18249                        }
18250                    }
18251                }
18252                cx.emit(EditorEvent::BufferEdited);
18253                cx.emit(SearchEvent::MatchesInvalidated);
18254                if *singleton_buffer_edited {
18255                    if let Some(project) = &self.project {
18256                        #[allow(clippy::mutable_key_type)]
18257                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18258                            multibuffer
18259                                .all_buffers()
18260                                .into_iter()
18261                                .filter_map(|buffer| {
18262                                    buffer.update(cx, |buffer, cx| {
18263                                        let language = buffer.language()?;
18264                                        let should_discard = project.update(cx, |project, cx| {
18265                                            project.is_local()
18266                                                && !project.has_language_servers_for(buffer, cx)
18267                                        });
18268                                        should_discard.not().then_some(language.clone())
18269                                    })
18270                                })
18271                                .collect::<HashSet<_>>()
18272                        });
18273                        if !languages_affected.is_empty() {
18274                            self.refresh_inlay_hints(
18275                                InlayHintRefreshReason::BufferEdited(languages_affected),
18276                                cx,
18277                            );
18278                        }
18279                    }
18280                }
18281
18282                let Some(project) = &self.project else { return };
18283                let (telemetry, is_via_ssh) = {
18284                    let project = project.read(cx);
18285                    let telemetry = project.client().telemetry().clone();
18286                    let is_via_ssh = project.is_via_ssh();
18287                    (telemetry, is_via_ssh)
18288                };
18289                refresh_linked_ranges(self, window, cx);
18290                telemetry.log_edit_event("editor", is_via_ssh);
18291            }
18292            multi_buffer::Event::ExcerptsAdded {
18293                buffer,
18294                predecessor,
18295                excerpts,
18296            } => {
18297                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18298                let buffer_id = buffer.read(cx).remote_id();
18299                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18300                    if let Some(project) = &self.project {
18301                        update_uncommitted_diff_for_buffer(
18302                            cx.entity(),
18303                            project,
18304                            [buffer.clone()],
18305                            self.buffer.clone(),
18306                            cx,
18307                        )
18308                        .detach();
18309                    }
18310                }
18311                cx.emit(EditorEvent::ExcerptsAdded {
18312                    buffer: buffer.clone(),
18313                    predecessor: *predecessor,
18314                    excerpts: excerpts.clone(),
18315                });
18316                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18317            }
18318            multi_buffer::Event::ExcerptsRemoved {
18319                ids,
18320                removed_buffer_ids,
18321            } => {
18322                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18323                let buffer = self.buffer.read(cx);
18324                self.registered_buffers
18325                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18326                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18327                cx.emit(EditorEvent::ExcerptsRemoved {
18328                    ids: ids.clone(),
18329                    removed_buffer_ids: removed_buffer_ids.clone(),
18330                })
18331            }
18332            multi_buffer::Event::ExcerptsEdited {
18333                excerpt_ids,
18334                buffer_ids,
18335            } => {
18336                self.display_map.update(cx, |map, cx| {
18337                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18338                });
18339                cx.emit(EditorEvent::ExcerptsEdited {
18340                    ids: excerpt_ids.clone(),
18341                })
18342            }
18343            multi_buffer::Event::ExcerptsExpanded { ids } => {
18344                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18345                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18346            }
18347            multi_buffer::Event::Reparsed(buffer_id) => {
18348                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18349                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18350
18351                cx.emit(EditorEvent::Reparsed(*buffer_id));
18352            }
18353            multi_buffer::Event::DiffHunksToggled => {
18354                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18355            }
18356            multi_buffer::Event::LanguageChanged(buffer_id) => {
18357                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18358                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18359                cx.emit(EditorEvent::Reparsed(*buffer_id));
18360                cx.notify();
18361            }
18362            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18363            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18364            multi_buffer::Event::FileHandleChanged
18365            | multi_buffer::Event::Reloaded
18366            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18367            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18368            multi_buffer::Event::DiagnosticsUpdated => {
18369                self.refresh_active_diagnostics(cx);
18370                self.refresh_inline_diagnostics(true, window, cx);
18371                self.scrollbar_marker_state.dirty = true;
18372                cx.notify();
18373            }
18374            _ => {}
18375        };
18376    }
18377
18378    pub fn start_temporary_diff_override(&mut self) {
18379        self.load_diff_task.take();
18380        self.temporary_diff_override = true;
18381    }
18382
18383    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18384        self.temporary_diff_override = false;
18385        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18386        self.buffer.update(cx, |buffer, cx| {
18387            buffer.set_all_diff_hunks_collapsed(cx);
18388        });
18389
18390        if let Some(project) = self.project.clone() {
18391            self.load_diff_task = Some(
18392                update_uncommitted_diff_for_buffer(
18393                    cx.entity(),
18394                    &project,
18395                    self.buffer.read(cx).all_buffers(),
18396                    self.buffer.clone(),
18397                    cx,
18398                )
18399                .shared(),
18400            );
18401        }
18402    }
18403
18404    fn on_display_map_changed(
18405        &mut self,
18406        _: Entity<DisplayMap>,
18407        _: &mut Window,
18408        cx: &mut Context<Self>,
18409    ) {
18410        cx.notify();
18411    }
18412
18413    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18414        let new_severity = if self.diagnostics_enabled() {
18415            EditorSettings::get_global(cx)
18416                .diagnostics_max_severity
18417                .unwrap_or(DiagnosticSeverity::Hint)
18418        } else {
18419            DiagnosticSeverity::Off
18420        };
18421        self.set_max_diagnostics_severity(new_severity, cx);
18422        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18423        self.update_edit_prediction_settings(cx);
18424        self.refresh_inline_completion(true, false, window, cx);
18425        self.refresh_inlay_hints(
18426            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18427                self.selections.newest_anchor().head(),
18428                &self.buffer.read(cx).snapshot(cx),
18429                cx,
18430            )),
18431            cx,
18432        );
18433
18434        let old_cursor_shape = self.cursor_shape;
18435
18436        {
18437            let editor_settings = EditorSettings::get_global(cx);
18438            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18439            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18440            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18441            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18442        }
18443
18444        if old_cursor_shape != self.cursor_shape {
18445            cx.emit(EditorEvent::CursorShapeChanged);
18446        }
18447
18448        let project_settings = ProjectSettings::get_global(cx);
18449        self.serialize_dirty_buffers =
18450            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18451
18452        if self.mode.is_full() {
18453            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18454            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18455            if self.show_inline_diagnostics != show_inline_diagnostics {
18456                self.show_inline_diagnostics = show_inline_diagnostics;
18457                self.refresh_inline_diagnostics(false, window, cx);
18458            }
18459
18460            if self.git_blame_inline_enabled != inline_blame_enabled {
18461                self.toggle_git_blame_inline_internal(false, window, cx);
18462            }
18463
18464            let minimap_settings = EditorSettings::get_global(cx).minimap;
18465            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18466                self.set_minimap_visibility(
18467                    self.minimap_visibility.toggle_visibility(),
18468                    window,
18469                    cx,
18470                );
18471            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18472                minimap_entity.update(cx, |minimap_editor, cx| {
18473                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18474                })
18475            }
18476        }
18477
18478        cx.notify();
18479    }
18480
18481    pub fn set_searchable(&mut self, searchable: bool) {
18482        self.searchable = searchable;
18483    }
18484
18485    pub fn searchable(&self) -> bool {
18486        self.searchable
18487    }
18488
18489    fn open_proposed_changes_editor(
18490        &mut self,
18491        _: &OpenProposedChangesEditor,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) {
18495        let Some(workspace) = self.workspace() else {
18496            cx.propagate();
18497            return;
18498        };
18499
18500        let selections = self.selections.all::<usize>(cx);
18501        let multi_buffer = self.buffer.read(cx);
18502        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18503        let mut new_selections_by_buffer = HashMap::default();
18504        for selection in selections {
18505            for (buffer, range, _) in
18506                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18507            {
18508                let mut range = range.to_point(buffer);
18509                range.start.column = 0;
18510                range.end.column = buffer.line_len(range.end.row);
18511                new_selections_by_buffer
18512                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18513                    .or_insert(Vec::new())
18514                    .push(range)
18515            }
18516        }
18517
18518        let proposed_changes_buffers = new_selections_by_buffer
18519            .into_iter()
18520            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18521            .collect::<Vec<_>>();
18522        let proposed_changes_editor = cx.new(|cx| {
18523            ProposedChangesEditor::new(
18524                "Proposed changes",
18525                proposed_changes_buffers,
18526                self.project.clone(),
18527                window,
18528                cx,
18529            )
18530        });
18531
18532        window.defer(cx, move |window, cx| {
18533            workspace.update(cx, |workspace, cx| {
18534                workspace.active_pane().update(cx, |pane, cx| {
18535                    pane.add_item(
18536                        Box::new(proposed_changes_editor),
18537                        true,
18538                        true,
18539                        None,
18540                        window,
18541                        cx,
18542                    );
18543                });
18544            });
18545        });
18546    }
18547
18548    pub fn open_excerpts_in_split(
18549        &mut self,
18550        _: &OpenExcerptsSplit,
18551        window: &mut Window,
18552        cx: &mut Context<Self>,
18553    ) {
18554        self.open_excerpts_common(None, true, window, cx)
18555    }
18556
18557    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18558        self.open_excerpts_common(None, false, window, cx)
18559    }
18560
18561    fn open_excerpts_common(
18562        &mut self,
18563        jump_data: Option<JumpData>,
18564        split: bool,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        let Some(workspace) = self.workspace() else {
18569            cx.propagate();
18570            return;
18571        };
18572
18573        if self.buffer.read(cx).is_singleton() {
18574            cx.propagate();
18575            return;
18576        }
18577
18578        let mut new_selections_by_buffer = HashMap::default();
18579        match &jump_data {
18580            Some(JumpData::MultiBufferPoint {
18581                excerpt_id,
18582                position,
18583                anchor,
18584                line_offset_from_top,
18585            }) => {
18586                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18587                if let Some(buffer) = multi_buffer_snapshot
18588                    .buffer_id_for_excerpt(*excerpt_id)
18589                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18590                {
18591                    let buffer_snapshot = buffer.read(cx).snapshot();
18592                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18593                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18594                    } else {
18595                        buffer_snapshot.clip_point(*position, Bias::Left)
18596                    };
18597                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18598                    new_selections_by_buffer.insert(
18599                        buffer,
18600                        (
18601                            vec![jump_to_offset..jump_to_offset],
18602                            Some(*line_offset_from_top),
18603                        ),
18604                    );
18605                }
18606            }
18607            Some(JumpData::MultiBufferRow {
18608                row,
18609                line_offset_from_top,
18610            }) => {
18611                let point = MultiBufferPoint::new(row.0, 0);
18612                if let Some((buffer, buffer_point, _)) =
18613                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18614                {
18615                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18616                    new_selections_by_buffer
18617                        .entry(buffer)
18618                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18619                        .0
18620                        .push(buffer_offset..buffer_offset)
18621                }
18622            }
18623            None => {
18624                let selections = self.selections.all::<usize>(cx);
18625                let multi_buffer = self.buffer.read(cx);
18626                for selection in selections {
18627                    for (snapshot, range, _, anchor) in multi_buffer
18628                        .snapshot(cx)
18629                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18630                    {
18631                        if let Some(anchor) = anchor {
18632                            // selection is in a deleted hunk
18633                            let Some(buffer_id) = anchor.buffer_id else {
18634                                continue;
18635                            };
18636                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18637                                continue;
18638                            };
18639                            let offset = text::ToOffset::to_offset(
18640                                &anchor.text_anchor,
18641                                &buffer_handle.read(cx).snapshot(),
18642                            );
18643                            let range = offset..offset;
18644                            new_selections_by_buffer
18645                                .entry(buffer_handle)
18646                                .or_insert((Vec::new(), None))
18647                                .0
18648                                .push(range)
18649                        } else {
18650                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18651                            else {
18652                                continue;
18653                            };
18654                            new_selections_by_buffer
18655                                .entry(buffer_handle)
18656                                .or_insert((Vec::new(), None))
18657                                .0
18658                                .push(range)
18659                        }
18660                    }
18661                }
18662            }
18663        }
18664
18665        new_selections_by_buffer
18666            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18667
18668        if new_selections_by_buffer.is_empty() {
18669            return;
18670        }
18671
18672        // We defer the pane interaction because we ourselves are a workspace item
18673        // and activating a new item causes the pane to call a method on us reentrantly,
18674        // which panics if we're on the stack.
18675        window.defer(cx, move |window, cx| {
18676            workspace.update(cx, |workspace, cx| {
18677                let pane = if split {
18678                    workspace.adjacent_pane(window, cx)
18679                } else {
18680                    workspace.active_pane().clone()
18681                };
18682
18683                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18684                    let editor = buffer
18685                        .read(cx)
18686                        .file()
18687                        .is_none()
18688                        .then(|| {
18689                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18690                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18691                            // Instead, we try to activate the existing editor in the pane first.
18692                            let (editor, pane_item_index) =
18693                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18694                                    let editor = item.downcast::<Editor>()?;
18695                                    let singleton_buffer =
18696                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18697                                    if singleton_buffer == buffer {
18698                                        Some((editor, i))
18699                                    } else {
18700                                        None
18701                                    }
18702                                })?;
18703                            pane.update(cx, |pane, cx| {
18704                                pane.activate_item(pane_item_index, true, true, window, cx)
18705                            });
18706                            Some(editor)
18707                        })
18708                        .flatten()
18709                        .unwrap_or_else(|| {
18710                            workspace.open_project_item::<Self>(
18711                                pane.clone(),
18712                                buffer,
18713                                true,
18714                                true,
18715                                window,
18716                                cx,
18717                            )
18718                        });
18719
18720                    editor.update(cx, |editor, cx| {
18721                        let autoscroll = match scroll_offset {
18722                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18723                            None => Autoscroll::newest(),
18724                        };
18725                        let nav_history = editor.nav_history.take();
18726                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18727                            s.select_ranges(ranges);
18728                        });
18729                        editor.nav_history = nav_history;
18730                    });
18731                }
18732            })
18733        });
18734    }
18735
18736    // For now, don't allow opening excerpts in buffers that aren't backed by
18737    // regular project files.
18738    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18739        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18740    }
18741
18742    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18743        let snapshot = self.buffer.read(cx).read(cx);
18744        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18745        Some(
18746            ranges
18747                .iter()
18748                .map(move |range| {
18749                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18750                })
18751                .collect(),
18752        )
18753    }
18754
18755    fn selection_replacement_ranges(
18756        &self,
18757        range: Range<OffsetUtf16>,
18758        cx: &mut App,
18759    ) -> Vec<Range<OffsetUtf16>> {
18760        let selections = self.selections.all::<OffsetUtf16>(cx);
18761        let newest_selection = selections
18762            .iter()
18763            .max_by_key(|selection| selection.id)
18764            .unwrap();
18765        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18766        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18767        let snapshot = self.buffer.read(cx).read(cx);
18768        selections
18769            .into_iter()
18770            .map(|mut selection| {
18771                selection.start.0 =
18772                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18773                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18774                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18775                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18776            })
18777            .collect()
18778    }
18779
18780    fn report_editor_event(
18781        &self,
18782        event_type: &'static str,
18783        file_extension: Option<String>,
18784        cx: &App,
18785    ) {
18786        if cfg!(any(test, feature = "test-support")) {
18787            return;
18788        }
18789
18790        let Some(project) = &self.project else { return };
18791
18792        // If None, we are in a file without an extension
18793        let file = self
18794            .buffer
18795            .read(cx)
18796            .as_singleton()
18797            .and_then(|b| b.read(cx).file());
18798        let file_extension = file_extension.or(file
18799            .as_ref()
18800            .and_then(|file| Path::new(file.file_name(cx)).extension())
18801            .and_then(|e| e.to_str())
18802            .map(|a| a.to_string()));
18803
18804        let vim_mode = vim_enabled(cx);
18805
18806        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18807        let copilot_enabled = edit_predictions_provider
18808            == language::language_settings::EditPredictionProvider::Copilot;
18809        let copilot_enabled_for_language = self
18810            .buffer
18811            .read(cx)
18812            .language_settings(cx)
18813            .show_edit_predictions;
18814
18815        let project = project.read(cx);
18816        telemetry::event!(
18817            event_type,
18818            file_extension,
18819            vim_mode,
18820            copilot_enabled,
18821            copilot_enabled_for_language,
18822            edit_predictions_provider,
18823            is_via_ssh = project.is_via_ssh(),
18824        );
18825    }
18826
18827    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18828    /// with each line being an array of {text, highlight} objects.
18829    fn copy_highlight_json(
18830        &mut self,
18831        _: &CopyHighlightJson,
18832        window: &mut Window,
18833        cx: &mut Context<Self>,
18834    ) {
18835        #[derive(Serialize)]
18836        struct Chunk<'a> {
18837            text: String,
18838            highlight: Option<&'a str>,
18839        }
18840
18841        let snapshot = self.buffer.read(cx).snapshot(cx);
18842        let range = self
18843            .selected_text_range(false, window, cx)
18844            .and_then(|selection| {
18845                if selection.range.is_empty() {
18846                    None
18847                } else {
18848                    Some(selection.range)
18849                }
18850            })
18851            .unwrap_or_else(|| 0..snapshot.len());
18852
18853        let chunks = snapshot.chunks(range, true);
18854        let mut lines = Vec::new();
18855        let mut line: VecDeque<Chunk> = VecDeque::new();
18856
18857        let Some(style) = self.style.as_ref() else {
18858            return;
18859        };
18860
18861        for chunk in chunks {
18862            let highlight = chunk
18863                .syntax_highlight_id
18864                .and_then(|id| id.name(&style.syntax));
18865            let mut chunk_lines = chunk.text.split('\n').peekable();
18866            while let Some(text) = chunk_lines.next() {
18867                let mut merged_with_last_token = false;
18868                if let Some(last_token) = line.back_mut() {
18869                    if last_token.highlight == highlight {
18870                        last_token.text.push_str(text);
18871                        merged_with_last_token = true;
18872                    }
18873                }
18874
18875                if !merged_with_last_token {
18876                    line.push_back(Chunk {
18877                        text: text.into(),
18878                        highlight,
18879                    });
18880                }
18881
18882                if chunk_lines.peek().is_some() {
18883                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18884                        line.pop_front();
18885                    }
18886                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18887                        line.pop_back();
18888                    }
18889
18890                    lines.push(mem::take(&mut line));
18891                }
18892            }
18893        }
18894
18895        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18896            return;
18897        };
18898        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18899    }
18900
18901    pub fn open_context_menu(
18902        &mut self,
18903        _: &OpenContextMenu,
18904        window: &mut Window,
18905        cx: &mut Context<Self>,
18906    ) {
18907        self.request_autoscroll(Autoscroll::newest(), cx);
18908        let position = self.selections.newest_display(cx).start;
18909        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18910    }
18911
18912    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18913        &self.inlay_hint_cache
18914    }
18915
18916    pub fn replay_insert_event(
18917        &mut self,
18918        text: &str,
18919        relative_utf16_range: Option<Range<isize>>,
18920        window: &mut Window,
18921        cx: &mut Context<Self>,
18922    ) {
18923        if !self.input_enabled {
18924            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18925            return;
18926        }
18927        if let Some(relative_utf16_range) = relative_utf16_range {
18928            let selections = self.selections.all::<OffsetUtf16>(cx);
18929            self.change_selections(None, window, cx, |s| {
18930                let new_ranges = selections.into_iter().map(|range| {
18931                    let start = OffsetUtf16(
18932                        range
18933                            .head()
18934                            .0
18935                            .saturating_add_signed(relative_utf16_range.start),
18936                    );
18937                    let end = OffsetUtf16(
18938                        range
18939                            .head()
18940                            .0
18941                            .saturating_add_signed(relative_utf16_range.end),
18942                    );
18943                    start..end
18944                });
18945                s.select_ranges(new_ranges);
18946            });
18947        }
18948
18949        self.handle_input(text, window, cx);
18950    }
18951
18952    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18953        let Some(provider) = self.semantics_provider.as_ref() else {
18954            return false;
18955        };
18956
18957        let mut supports = false;
18958        self.buffer().update(cx, |this, cx| {
18959            this.for_each_buffer(|buffer| {
18960                supports |= provider.supports_inlay_hints(buffer, cx);
18961            });
18962        });
18963
18964        supports
18965    }
18966
18967    pub fn is_focused(&self, window: &Window) -> bool {
18968        self.focus_handle.is_focused(window)
18969    }
18970
18971    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18972        cx.emit(EditorEvent::Focused);
18973
18974        if let Some(descendant) = self
18975            .last_focused_descendant
18976            .take()
18977            .and_then(|descendant| descendant.upgrade())
18978        {
18979            window.focus(&descendant);
18980        } else {
18981            if let Some(blame) = self.blame.as_ref() {
18982                blame.update(cx, GitBlame::focus)
18983            }
18984
18985            self.blink_manager.update(cx, BlinkManager::enable);
18986            self.show_cursor_names(window, cx);
18987            self.buffer.update(cx, |buffer, cx| {
18988                buffer.finalize_last_transaction(cx);
18989                if self.leader_id.is_none() {
18990                    buffer.set_active_selections(
18991                        &self.selections.disjoint_anchors(),
18992                        self.selections.line_mode,
18993                        self.cursor_shape,
18994                        cx,
18995                    );
18996                }
18997            });
18998        }
18999    }
19000
19001    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19002        cx.emit(EditorEvent::FocusedIn)
19003    }
19004
19005    fn handle_focus_out(
19006        &mut self,
19007        event: FocusOutEvent,
19008        _window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) {
19011        if event.blurred != self.focus_handle {
19012            self.last_focused_descendant = Some(event.blurred);
19013        }
19014        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19015    }
19016
19017    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19018        self.blink_manager.update(cx, BlinkManager::disable);
19019        self.buffer
19020            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19021
19022        if let Some(blame) = self.blame.as_ref() {
19023            blame.update(cx, GitBlame::blur)
19024        }
19025        if !self.hover_state.focused(window, cx) {
19026            hide_hover(self, cx);
19027        }
19028        if !self
19029            .context_menu
19030            .borrow()
19031            .as_ref()
19032            .is_some_and(|context_menu| context_menu.focused(window, cx))
19033        {
19034            self.hide_context_menu(window, cx);
19035        }
19036        self.discard_inline_completion(false, cx);
19037        cx.emit(EditorEvent::Blurred);
19038        cx.notify();
19039    }
19040
19041    pub fn register_action<A: Action>(
19042        &mut self,
19043        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19044    ) -> Subscription {
19045        let id = self.next_editor_action_id.post_inc();
19046        let listener = Arc::new(listener);
19047        self.editor_actions.borrow_mut().insert(
19048            id,
19049            Box::new(move |window, _| {
19050                let listener = listener.clone();
19051                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19052                    let action = action.downcast_ref().unwrap();
19053                    if phase == DispatchPhase::Bubble {
19054                        listener(action, window, cx)
19055                    }
19056                })
19057            }),
19058        );
19059
19060        let editor_actions = self.editor_actions.clone();
19061        Subscription::new(move || {
19062            editor_actions.borrow_mut().remove(&id);
19063        })
19064    }
19065
19066    pub fn file_header_size(&self) -> u32 {
19067        FILE_HEADER_HEIGHT
19068    }
19069
19070    pub fn restore(
19071        &mut self,
19072        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19073        window: &mut Window,
19074        cx: &mut Context<Self>,
19075    ) {
19076        let workspace = self.workspace();
19077        let project = self.project.as_ref();
19078        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19079            let mut tasks = Vec::new();
19080            for (buffer_id, changes) in revert_changes {
19081                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19082                    buffer.update(cx, |buffer, cx| {
19083                        buffer.edit(
19084                            changes
19085                                .into_iter()
19086                                .map(|(range, text)| (range, text.to_string())),
19087                            None,
19088                            cx,
19089                        );
19090                    });
19091
19092                    if let Some(project) =
19093                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19094                    {
19095                        project.update(cx, |project, cx| {
19096                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19097                        })
19098                    }
19099                }
19100            }
19101            tasks
19102        });
19103        cx.spawn_in(window, async move |_, cx| {
19104            for (buffer, task) in save_tasks {
19105                let result = task.await;
19106                if result.is_err() {
19107                    let Some(path) = buffer
19108                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19109                        .ok()
19110                    else {
19111                        continue;
19112                    };
19113                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19114                        let Some(task) = cx
19115                            .update_window_entity(&workspace, |workspace, window, cx| {
19116                                workspace
19117                                    .open_path_preview(path, None, false, false, false, window, cx)
19118                            })
19119                            .ok()
19120                        else {
19121                            continue;
19122                        };
19123                        task.await.log_err();
19124                    }
19125                }
19126            }
19127        })
19128        .detach();
19129        self.change_selections(None, window, cx, |selections| selections.refresh());
19130    }
19131
19132    pub fn to_pixel_point(
19133        &self,
19134        source: multi_buffer::Anchor,
19135        editor_snapshot: &EditorSnapshot,
19136        window: &mut Window,
19137    ) -> Option<gpui::Point<Pixels>> {
19138        let source_point = source.to_display_point(editor_snapshot);
19139        self.display_to_pixel_point(source_point, editor_snapshot, window)
19140    }
19141
19142    pub fn display_to_pixel_point(
19143        &self,
19144        source: DisplayPoint,
19145        editor_snapshot: &EditorSnapshot,
19146        window: &mut Window,
19147    ) -> Option<gpui::Point<Pixels>> {
19148        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19149        let text_layout_details = self.text_layout_details(window);
19150        let scroll_top = text_layout_details
19151            .scroll_anchor
19152            .scroll_position(editor_snapshot)
19153            .y;
19154
19155        if source.row().as_f32() < scroll_top.floor() {
19156            return None;
19157        }
19158        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19159        let source_y = line_height * (source.row().as_f32() - scroll_top);
19160        Some(gpui::Point::new(source_x, source_y))
19161    }
19162
19163    pub fn has_visible_completions_menu(&self) -> bool {
19164        !self.edit_prediction_preview_is_active()
19165            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19166                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19167            })
19168    }
19169
19170    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19171        if self.mode.is_minimap() {
19172            return;
19173        }
19174        self.addons
19175            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19176    }
19177
19178    pub fn unregister_addon<T: Addon>(&mut self) {
19179        self.addons.remove(&std::any::TypeId::of::<T>());
19180    }
19181
19182    pub fn addon<T: Addon>(&self) -> Option<&T> {
19183        let type_id = std::any::TypeId::of::<T>();
19184        self.addons
19185            .get(&type_id)
19186            .and_then(|item| item.to_any().downcast_ref::<T>())
19187    }
19188
19189    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19190        let type_id = std::any::TypeId::of::<T>();
19191        self.addons
19192            .get_mut(&type_id)
19193            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19194    }
19195
19196    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19197        let text_layout_details = self.text_layout_details(window);
19198        let style = &text_layout_details.editor_style;
19199        let font_id = window.text_system().resolve_font(&style.text.font());
19200        let font_size = style.text.font_size.to_pixels(window.rem_size());
19201        let line_height = style.text.line_height_in_pixels(window.rem_size());
19202        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19203
19204        gpui::Size::new(em_width, line_height)
19205    }
19206
19207    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19208        self.load_diff_task.clone()
19209    }
19210
19211    fn read_metadata_from_db(
19212        &mut self,
19213        item_id: u64,
19214        workspace_id: WorkspaceId,
19215        window: &mut Window,
19216        cx: &mut Context<Editor>,
19217    ) {
19218        if self.is_singleton(cx)
19219            && !self.mode.is_minimap()
19220            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19221        {
19222            let buffer_snapshot = OnceCell::new();
19223
19224            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19225                if !folds.is_empty() {
19226                    let snapshot =
19227                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19228                    self.fold_ranges(
19229                        folds
19230                            .into_iter()
19231                            .map(|(start, end)| {
19232                                snapshot.clip_offset(start, Bias::Left)
19233                                    ..snapshot.clip_offset(end, Bias::Right)
19234                            })
19235                            .collect(),
19236                        false,
19237                        window,
19238                        cx,
19239                    );
19240                }
19241            }
19242
19243            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19244                if !selections.is_empty() {
19245                    let snapshot =
19246                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19247                    self.change_selections(None, window, cx, |s| {
19248                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19249                            snapshot.clip_offset(start, Bias::Left)
19250                                ..snapshot.clip_offset(end, Bias::Right)
19251                        }));
19252                    });
19253                }
19254            };
19255        }
19256
19257        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19258    }
19259}
19260
19261fn vim_enabled(cx: &App) -> bool {
19262    cx.global::<SettingsStore>()
19263        .raw_user_settings()
19264        .get("vim_mode")
19265        == Some(&serde_json::Value::Bool(true))
19266}
19267
19268// Consider user intent and default settings
19269fn choose_completion_range(
19270    completion: &Completion,
19271    intent: CompletionIntent,
19272    buffer: &Entity<Buffer>,
19273    cx: &mut Context<Editor>,
19274) -> Range<usize> {
19275    fn should_replace(
19276        completion: &Completion,
19277        insert_range: &Range<text::Anchor>,
19278        intent: CompletionIntent,
19279        completion_mode_setting: LspInsertMode,
19280        buffer: &Buffer,
19281    ) -> bool {
19282        // specific actions take precedence over settings
19283        match intent {
19284            CompletionIntent::CompleteWithInsert => return false,
19285            CompletionIntent::CompleteWithReplace => return true,
19286            CompletionIntent::Complete | CompletionIntent::Compose => {}
19287        }
19288
19289        match completion_mode_setting {
19290            LspInsertMode::Insert => false,
19291            LspInsertMode::Replace => true,
19292            LspInsertMode::ReplaceSubsequence => {
19293                let mut text_to_replace = buffer.chars_for_range(
19294                    buffer.anchor_before(completion.replace_range.start)
19295                        ..buffer.anchor_after(completion.replace_range.end),
19296                );
19297                let mut completion_text = completion.new_text.chars();
19298
19299                // is `text_to_replace` a subsequence of `completion_text`
19300                text_to_replace
19301                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19302            }
19303            LspInsertMode::ReplaceSuffix => {
19304                let range_after_cursor = insert_range.end..completion.replace_range.end;
19305
19306                let text_after_cursor = buffer
19307                    .text_for_range(
19308                        buffer.anchor_before(range_after_cursor.start)
19309                            ..buffer.anchor_after(range_after_cursor.end),
19310                    )
19311                    .collect::<String>();
19312                completion.new_text.ends_with(&text_after_cursor)
19313            }
19314        }
19315    }
19316
19317    let buffer = buffer.read(cx);
19318
19319    if let CompletionSource::Lsp {
19320        insert_range: Some(insert_range),
19321        ..
19322    } = &completion.source
19323    {
19324        let completion_mode_setting =
19325            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19326                .completions
19327                .lsp_insert_mode;
19328
19329        if !should_replace(
19330            completion,
19331            &insert_range,
19332            intent,
19333            completion_mode_setting,
19334            buffer,
19335        ) {
19336            return insert_range.to_offset(buffer);
19337        }
19338    }
19339
19340    completion.replace_range.to_offset(buffer)
19341}
19342
19343fn insert_extra_newline_brackets(
19344    buffer: &MultiBufferSnapshot,
19345    range: Range<usize>,
19346    language: &language::LanguageScope,
19347) -> bool {
19348    let leading_whitespace_len = buffer
19349        .reversed_chars_at(range.start)
19350        .take_while(|c| c.is_whitespace() && *c != '\n')
19351        .map(|c| c.len_utf8())
19352        .sum::<usize>();
19353    let trailing_whitespace_len = buffer
19354        .chars_at(range.end)
19355        .take_while(|c| c.is_whitespace() && *c != '\n')
19356        .map(|c| c.len_utf8())
19357        .sum::<usize>();
19358    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19359
19360    language.brackets().any(|(pair, enabled)| {
19361        let pair_start = pair.start.trim_end();
19362        let pair_end = pair.end.trim_start();
19363
19364        enabled
19365            && pair.newline
19366            && buffer.contains_str_at(range.end, pair_end)
19367            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19368    })
19369}
19370
19371fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19372    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19373        [(buffer, range, _)] => (*buffer, range.clone()),
19374        _ => return false,
19375    };
19376    let pair = {
19377        let mut result: Option<BracketMatch> = None;
19378
19379        for pair in buffer
19380            .all_bracket_ranges(range.clone())
19381            .filter(move |pair| {
19382                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19383            })
19384        {
19385            let len = pair.close_range.end - pair.open_range.start;
19386
19387            if let Some(existing) = &result {
19388                let existing_len = existing.close_range.end - existing.open_range.start;
19389                if len > existing_len {
19390                    continue;
19391                }
19392            }
19393
19394            result = Some(pair);
19395        }
19396
19397        result
19398    };
19399    let Some(pair) = pair else {
19400        return false;
19401    };
19402    pair.newline_only
19403        && buffer
19404            .chars_for_range(pair.open_range.end..range.start)
19405            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19406            .all(|c| c.is_whitespace() && c != '\n')
19407}
19408
19409fn update_uncommitted_diff_for_buffer(
19410    editor: Entity<Editor>,
19411    project: &Entity<Project>,
19412    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19413    buffer: Entity<MultiBuffer>,
19414    cx: &mut App,
19415) -> Task<()> {
19416    let mut tasks = Vec::new();
19417    project.update(cx, |project, cx| {
19418        for buffer in buffers {
19419            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19420                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19421            }
19422        }
19423    });
19424    cx.spawn(async move |cx| {
19425        let diffs = future::join_all(tasks).await;
19426        if editor
19427            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19428            .unwrap_or(false)
19429        {
19430            return;
19431        }
19432
19433        buffer
19434            .update(cx, |buffer, cx| {
19435                for diff in diffs.into_iter().flatten() {
19436                    buffer.add_diff(diff, cx);
19437                }
19438            })
19439            .ok();
19440    })
19441}
19442
19443pub trait CollaborationHub {
19444    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19445    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19446    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19447}
19448
19449impl CollaborationHub for Entity<Project> {
19450    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19451        self.read(cx).collaborators()
19452    }
19453
19454    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19455        self.read(cx).user_store().read(cx).participant_indices()
19456    }
19457
19458    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19459        let this = self.read(cx);
19460        let user_ids = this.collaborators().values().map(|c| c.user_id);
19461        this.user_store().read_with(cx, |user_store, cx| {
19462            user_store.participant_names(user_ids, cx)
19463        })
19464    }
19465}
19466
19467pub trait SemanticsProvider {
19468    fn hover(
19469        &self,
19470        buffer: &Entity<Buffer>,
19471        position: text::Anchor,
19472        cx: &mut App,
19473    ) -> Option<Task<Vec<project::Hover>>>;
19474
19475    fn inline_values(
19476        &self,
19477        buffer_handle: Entity<Buffer>,
19478        range: Range<text::Anchor>,
19479        cx: &mut App,
19480    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19481
19482    fn inlay_hints(
19483        &self,
19484        buffer_handle: Entity<Buffer>,
19485        range: Range<text::Anchor>,
19486        cx: &mut App,
19487    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19488
19489    fn resolve_inlay_hint(
19490        &self,
19491        hint: InlayHint,
19492        buffer_handle: Entity<Buffer>,
19493        server_id: LanguageServerId,
19494        cx: &mut App,
19495    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19496
19497    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19498
19499    fn document_highlights(
19500        &self,
19501        buffer: &Entity<Buffer>,
19502        position: text::Anchor,
19503        cx: &mut App,
19504    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19505
19506    fn definitions(
19507        &self,
19508        buffer: &Entity<Buffer>,
19509        position: text::Anchor,
19510        kind: GotoDefinitionKind,
19511        cx: &mut App,
19512    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19513
19514    fn range_for_rename(
19515        &self,
19516        buffer: &Entity<Buffer>,
19517        position: text::Anchor,
19518        cx: &mut App,
19519    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19520
19521    fn perform_rename(
19522        &self,
19523        buffer: &Entity<Buffer>,
19524        position: text::Anchor,
19525        new_name: String,
19526        cx: &mut App,
19527    ) -> Option<Task<Result<ProjectTransaction>>>;
19528}
19529
19530pub trait CompletionProvider {
19531    fn completions(
19532        &self,
19533        excerpt_id: ExcerptId,
19534        buffer: &Entity<Buffer>,
19535        buffer_position: text::Anchor,
19536        trigger: CompletionContext,
19537        window: &mut Window,
19538        cx: &mut Context<Editor>,
19539    ) -> Task<Result<Option<Vec<Completion>>>>;
19540
19541    fn resolve_completions(
19542        &self,
19543        buffer: Entity<Buffer>,
19544        completion_indices: Vec<usize>,
19545        completions: Rc<RefCell<Box<[Completion]>>>,
19546        cx: &mut Context<Editor>,
19547    ) -> Task<Result<bool>>;
19548
19549    fn apply_additional_edits_for_completion(
19550        &self,
19551        _buffer: Entity<Buffer>,
19552        _completions: Rc<RefCell<Box<[Completion]>>>,
19553        _completion_index: usize,
19554        _push_to_history: bool,
19555        _cx: &mut Context<Editor>,
19556    ) -> Task<Result<Option<language::Transaction>>> {
19557        Task::ready(Ok(None))
19558    }
19559
19560    fn is_completion_trigger(
19561        &self,
19562        buffer: &Entity<Buffer>,
19563        position: language::Anchor,
19564        text: &str,
19565        trigger_in_words: bool,
19566        cx: &mut Context<Editor>,
19567    ) -> bool;
19568
19569    fn sort_completions(&self) -> bool {
19570        true
19571    }
19572
19573    fn filter_completions(&self) -> bool {
19574        true
19575    }
19576}
19577
19578pub trait CodeActionProvider {
19579    fn id(&self) -> Arc<str>;
19580
19581    fn code_actions(
19582        &self,
19583        buffer: &Entity<Buffer>,
19584        range: Range<text::Anchor>,
19585        window: &mut Window,
19586        cx: &mut App,
19587    ) -> Task<Result<Vec<CodeAction>>>;
19588
19589    fn apply_code_action(
19590        &self,
19591        buffer_handle: Entity<Buffer>,
19592        action: CodeAction,
19593        excerpt_id: ExcerptId,
19594        push_to_history: bool,
19595        window: &mut Window,
19596        cx: &mut App,
19597    ) -> Task<Result<ProjectTransaction>>;
19598}
19599
19600impl CodeActionProvider for Entity<Project> {
19601    fn id(&self) -> Arc<str> {
19602        "project".into()
19603    }
19604
19605    fn code_actions(
19606        &self,
19607        buffer: &Entity<Buffer>,
19608        range: Range<text::Anchor>,
19609        _window: &mut Window,
19610        cx: &mut App,
19611    ) -> Task<Result<Vec<CodeAction>>> {
19612        self.update(cx, |project, cx| {
19613            let code_lens = project.code_lens(buffer, range.clone(), cx);
19614            let code_actions = project.code_actions(buffer, range, None, cx);
19615            cx.background_spawn(async move {
19616                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19617                Ok(code_lens
19618                    .context("code lens fetch")?
19619                    .into_iter()
19620                    .chain(code_actions.context("code action fetch")?)
19621                    .collect())
19622            })
19623        })
19624    }
19625
19626    fn apply_code_action(
19627        &self,
19628        buffer_handle: Entity<Buffer>,
19629        action: CodeAction,
19630        _excerpt_id: ExcerptId,
19631        push_to_history: bool,
19632        _window: &mut Window,
19633        cx: &mut App,
19634    ) -> Task<Result<ProjectTransaction>> {
19635        self.update(cx, |project, cx| {
19636            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19637        })
19638    }
19639}
19640
19641fn snippet_completions(
19642    project: &Project,
19643    buffer: &Entity<Buffer>,
19644    buffer_position: text::Anchor,
19645    cx: &mut App,
19646) -> Task<Result<Vec<Completion>>> {
19647    let languages = buffer.read(cx).languages_at(buffer_position);
19648    let snippet_store = project.snippets().read(cx);
19649
19650    let scopes: Vec<_> = languages
19651        .iter()
19652        .filter_map(|language| {
19653            let language_name = language.lsp_id();
19654            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19655
19656            if snippets.is_empty() {
19657                None
19658            } else {
19659                Some((language.default_scope(), snippets))
19660            }
19661        })
19662        .collect();
19663
19664    if scopes.is_empty() {
19665        return Task::ready(Ok(vec![]));
19666    }
19667
19668    let snapshot = buffer.read(cx).text_snapshot();
19669    let chars: String = snapshot
19670        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19671        .collect();
19672    let executor = cx.background_executor().clone();
19673
19674    cx.background_spawn(async move {
19675        let mut all_results: Vec<Completion> = Vec::new();
19676        for (scope, snippets) in scopes.into_iter() {
19677            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19678            let mut last_word = chars
19679                .chars()
19680                .take_while(|c| classifier.is_word(*c))
19681                .collect::<String>();
19682            last_word = last_word.chars().rev().collect();
19683
19684            if last_word.is_empty() {
19685                return Ok(vec![]);
19686            }
19687
19688            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19689            let to_lsp = |point: &text::Anchor| {
19690                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19691                point_to_lsp(end)
19692            };
19693            let lsp_end = to_lsp(&buffer_position);
19694
19695            let candidates = snippets
19696                .iter()
19697                .enumerate()
19698                .flat_map(|(ix, snippet)| {
19699                    snippet
19700                        .prefix
19701                        .iter()
19702                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19703                })
19704                .collect::<Vec<StringMatchCandidate>>();
19705
19706            let mut matches = fuzzy::match_strings(
19707                &candidates,
19708                &last_word,
19709                last_word.chars().any(|c| c.is_uppercase()),
19710                100,
19711                &Default::default(),
19712                executor.clone(),
19713            )
19714            .await;
19715
19716            // Remove all candidates where the query's start does not match the start of any word in the candidate
19717            if let Some(query_start) = last_word.chars().next() {
19718                matches.retain(|string_match| {
19719                    split_words(&string_match.string).any(|word| {
19720                        // Check that the first codepoint of the word as lowercase matches the first
19721                        // codepoint of the query as lowercase
19722                        word.chars()
19723                            .flat_map(|codepoint| codepoint.to_lowercase())
19724                            .zip(query_start.to_lowercase())
19725                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19726                    })
19727                });
19728            }
19729
19730            let matched_strings = matches
19731                .into_iter()
19732                .map(|m| m.string)
19733                .collect::<HashSet<_>>();
19734
19735            let mut result: Vec<Completion> = snippets
19736                .iter()
19737                .filter_map(|snippet| {
19738                    let matching_prefix = snippet
19739                        .prefix
19740                        .iter()
19741                        .find(|prefix| matched_strings.contains(*prefix))?;
19742                    let start = as_offset - last_word.len();
19743                    let start = snapshot.anchor_before(start);
19744                    let range = start..buffer_position;
19745                    let lsp_start = to_lsp(&start);
19746                    let lsp_range = lsp::Range {
19747                        start: lsp_start,
19748                        end: lsp_end,
19749                    };
19750                    Some(Completion {
19751                        replace_range: range,
19752                        new_text: snippet.body.clone(),
19753                        source: CompletionSource::Lsp {
19754                            insert_range: None,
19755                            server_id: LanguageServerId(usize::MAX),
19756                            resolved: true,
19757                            lsp_completion: Box::new(lsp::CompletionItem {
19758                                label: snippet.prefix.first().unwrap().clone(),
19759                                kind: Some(CompletionItemKind::SNIPPET),
19760                                label_details: snippet.description.as_ref().map(|description| {
19761                                    lsp::CompletionItemLabelDetails {
19762                                        detail: Some(description.clone()),
19763                                        description: None,
19764                                    }
19765                                }),
19766                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19767                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19768                                    lsp::InsertReplaceEdit {
19769                                        new_text: snippet.body.clone(),
19770                                        insert: lsp_range,
19771                                        replace: lsp_range,
19772                                    },
19773                                )),
19774                                filter_text: Some(snippet.body.clone()),
19775                                sort_text: Some(char::MAX.to_string()),
19776                                ..lsp::CompletionItem::default()
19777                            }),
19778                            lsp_defaults: None,
19779                        },
19780                        label: CodeLabel {
19781                            text: matching_prefix.clone(),
19782                            runs: Vec::new(),
19783                            filter_range: 0..matching_prefix.len(),
19784                        },
19785                        icon_path: None,
19786                        documentation: Some(
19787                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
19788                                single_line: snippet.name.clone().into(),
19789                                plain_text: snippet
19790                                    .description
19791                                    .clone()
19792                                    .map(|description| description.into()),
19793                            },
19794                        ),
19795                        insert_text_mode: None,
19796                        confirm: None,
19797                    })
19798                })
19799                .collect();
19800
19801            all_results.append(&mut result);
19802        }
19803
19804        Ok(all_results)
19805    })
19806}
19807
19808impl CompletionProvider for Entity<Project> {
19809    fn completions(
19810        &self,
19811        _excerpt_id: ExcerptId,
19812        buffer: &Entity<Buffer>,
19813        buffer_position: text::Anchor,
19814        options: CompletionContext,
19815        _window: &mut Window,
19816        cx: &mut Context<Editor>,
19817    ) -> Task<Result<Option<Vec<Completion>>>> {
19818        self.update(cx, |project, cx| {
19819            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19820            let project_completions = project.completions(buffer, buffer_position, options, cx);
19821            cx.background_spawn(async move {
19822                let snippets_completions = snippets.await?;
19823                match project_completions.await? {
19824                    Some(mut completions) => {
19825                        completions.extend(snippets_completions);
19826                        Ok(Some(completions))
19827                    }
19828                    None => {
19829                        if snippets_completions.is_empty() {
19830                            Ok(None)
19831                        } else {
19832                            Ok(Some(snippets_completions))
19833                        }
19834                    }
19835                }
19836            })
19837        })
19838    }
19839
19840    fn resolve_completions(
19841        &self,
19842        buffer: Entity<Buffer>,
19843        completion_indices: Vec<usize>,
19844        completions: Rc<RefCell<Box<[Completion]>>>,
19845        cx: &mut Context<Editor>,
19846    ) -> Task<Result<bool>> {
19847        self.update(cx, |project, cx| {
19848            project.lsp_store().update(cx, |lsp_store, cx| {
19849                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19850            })
19851        })
19852    }
19853
19854    fn apply_additional_edits_for_completion(
19855        &self,
19856        buffer: Entity<Buffer>,
19857        completions: Rc<RefCell<Box<[Completion]>>>,
19858        completion_index: usize,
19859        push_to_history: bool,
19860        cx: &mut Context<Editor>,
19861    ) -> Task<Result<Option<language::Transaction>>> {
19862        self.update(cx, |project, cx| {
19863            project.lsp_store().update(cx, |lsp_store, cx| {
19864                lsp_store.apply_additional_edits_for_completion(
19865                    buffer,
19866                    completions,
19867                    completion_index,
19868                    push_to_history,
19869                    cx,
19870                )
19871            })
19872        })
19873    }
19874
19875    fn is_completion_trigger(
19876        &self,
19877        buffer: &Entity<Buffer>,
19878        position: language::Anchor,
19879        text: &str,
19880        trigger_in_words: bool,
19881        cx: &mut Context<Editor>,
19882    ) -> bool {
19883        let mut chars = text.chars();
19884        let char = if let Some(char) = chars.next() {
19885            char
19886        } else {
19887            return false;
19888        };
19889        if chars.next().is_some() {
19890            return false;
19891        }
19892
19893        let buffer = buffer.read(cx);
19894        let snapshot = buffer.snapshot();
19895        if !snapshot.settings_at(position, cx).show_completions_on_input {
19896            return false;
19897        }
19898        let classifier = snapshot.char_classifier_at(position).for_completion(true);
19899        if trigger_in_words && classifier.is_word(char) {
19900            return true;
19901        }
19902
19903        buffer.completion_triggers().contains(text)
19904    }
19905}
19906
19907impl SemanticsProvider for Entity<Project> {
19908    fn hover(
19909        &self,
19910        buffer: &Entity<Buffer>,
19911        position: text::Anchor,
19912        cx: &mut App,
19913    ) -> Option<Task<Vec<project::Hover>>> {
19914        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
19915    }
19916
19917    fn document_highlights(
19918        &self,
19919        buffer: &Entity<Buffer>,
19920        position: text::Anchor,
19921        cx: &mut App,
19922    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
19923        Some(self.update(cx, |project, cx| {
19924            project.document_highlights(buffer, position, cx)
19925        }))
19926    }
19927
19928    fn definitions(
19929        &self,
19930        buffer: &Entity<Buffer>,
19931        position: text::Anchor,
19932        kind: GotoDefinitionKind,
19933        cx: &mut App,
19934    ) -> Option<Task<Result<Vec<LocationLink>>>> {
19935        Some(self.update(cx, |project, cx| match kind {
19936            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
19937            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
19938            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
19939            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
19940        }))
19941    }
19942
19943    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
19944        // TODO: make this work for remote projects
19945        self.update(cx, |project, cx| {
19946            if project
19947                .active_debug_session(cx)
19948                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
19949            {
19950                return true;
19951            }
19952
19953            buffer.update(cx, |buffer, cx| {
19954                project.any_language_server_supports_inlay_hints(buffer, cx)
19955            })
19956        })
19957    }
19958
19959    fn inline_values(
19960        &self,
19961        buffer_handle: Entity<Buffer>,
19962
19963        range: Range<text::Anchor>,
19964        cx: &mut App,
19965    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19966        self.update(cx, |project, cx| {
19967            let (session, active_stack_frame) = project.active_debug_session(cx)?;
19968
19969            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
19970        })
19971    }
19972
19973    fn inlay_hints(
19974        &self,
19975        buffer_handle: Entity<Buffer>,
19976        range: Range<text::Anchor>,
19977        cx: &mut App,
19978    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19979        Some(self.update(cx, |project, cx| {
19980            project.inlay_hints(buffer_handle, range, cx)
19981        }))
19982    }
19983
19984    fn resolve_inlay_hint(
19985        &self,
19986        hint: InlayHint,
19987        buffer_handle: Entity<Buffer>,
19988        server_id: LanguageServerId,
19989        cx: &mut App,
19990    ) -> Option<Task<anyhow::Result<InlayHint>>> {
19991        Some(self.update(cx, |project, cx| {
19992            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
19993        }))
19994    }
19995
19996    fn range_for_rename(
19997        &self,
19998        buffer: &Entity<Buffer>,
19999        position: text::Anchor,
20000        cx: &mut App,
20001    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20002        Some(self.update(cx, |project, cx| {
20003            let buffer = buffer.clone();
20004            let task = project.prepare_rename(buffer.clone(), position, cx);
20005            cx.spawn(async move |_, cx| {
20006                Ok(match task.await? {
20007                    PrepareRenameResponse::Success(range) => Some(range),
20008                    PrepareRenameResponse::InvalidPosition => None,
20009                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20010                        // Fallback on using TreeSitter info to determine identifier range
20011                        buffer.update(cx, |buffer, _| {
20012                            let snapshot = buffer.snapshot();
20013                            let (range, kind) = snapshot.surrounding_word(position);
20014                            if kind != Some(CharKind::Word) {
20015                                return None;
20016                            }
20017                            Some(
20018                                snapshot.anchor_before(range.start)
20019                                    ..snapshot.anchor_after(range.end),
20020                            )
20021                        })?
20022                    }
20023                })
20024            })
20025        }))
20026    }
20027
20028    fn perform_rename(
20029        &self,
20030        buffer: &Entity<Buffer>,
20031        position: text::Anchor,
20032        new_name: String,
20033        cx: &mut App,
20034    ) -> Option<Task<Result<ProjectTransaction>>> {
20035        Some(self.update(cx, |project, cx| {
20036            project.perform_rename(buffer.clone(), position, new_name, cx)
20037        }))
20038    }
20039}
20040
20041fn inlay_hint_settings(
20042    location: Anchor,
20043    snapshot: &MultiBufferSnapshot,
20044    cx: &mut Context<Editor>,
20045) -> InlayHintSettings {
20046    let file = snapshot.file_at(location);
20047    let language = snapshot.language_at(location).map(|l| l.name());
20048    language_settings(language, file, cx).inlay_hints
20049}
20050
20051fn consume_contiguous_rows(
20052    contiguous_row_selections: &mut Vec<Selection<Point>>,
20053    selection: &Selection<Point>,
20054    display_map: &DisplaySnapshot,
20055    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20056) -> (MultiBufferRow, MultiBufferRow) {
20057    contiguous_row_selections.push(selection.clone());
20058    let start_row = MultiBufferRow(selection.start.row);
20059    let mut end_row = ending_row(selection, display_map);
20060
20061    while let Some(next_selection) = selections.peek() {
20062        if next_selection.start.row <= end_row.0 {
20063            end_row = ending_row(next_selection, display_map);
20064            contiguous_row_selections.push(selections.next().unwrap().clone());
20065        } else {
20066            break;
20067        }
20068    }
20069    (start_row, end_row)
20070}
20071
20072fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20073    if next_selection.end.column > 0 || next_selection.is_empty() {
20074        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20075    } else {
20076        MultiBufferRow(next_selection.end.row)
20077    }
20078}
20079
20080impl EditorSnapshot {
20081    pub fn remote_selections_in_range<'a>(
20082        &'a self,
20083        range: &'a Range<Anchor>,
20084        collaboration_hub: &dyn CollaborationHub,
20085        cx: &'a App,
20086    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20087        let participant_names = collaboration_hub.user_names(cx);
20088        let participant_indices = collaboration_hub.user_participant_indices(cx);
20089        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20090        let collaborators_by_replica_id = collaborators_by_peer_id
20091            .values()
20092            .map(|collaborator| (collaborator.replica_id, collaborator))
20093            .collect::<HashMap<_, _>>();
20094        self.buffer_snapshot
20095            .selections_in_range(range, false)
20096            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20097                if replica_id == AGENT_REPLICA_ID {
20098                    Some(RemoteSelection {
20099                        replica_id,
20100                        selection,
20101                        cursor_shape,
20102                        line_mode,
20103                        collaborator_id: CollaboratorId::Agent,
20104                        user_name: Some("Agent".into()),
20105                        color: cx.theme().players().agent(),
20106                    })
20107                } else {
20108                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20109                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20110                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20111                    Some(RemoteSelection {
20112                        replica_id,
20113                        selection,
20114                        cursor_shape,
20115                        line_mode,
20116                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20117                        user_name,
20118                        color: if let Some(index) = participant_index {
20119                            cx.theme().players().color_for_participant(index.0)
20120                        } else {
20121                            cx.theme().players().absent()
20122                        },
20123                    })
20124                }
20125            })
20126    }
20127
20128    pub fn hunks_for_ranges(
20129        &self,
20130        ranges: impl IntoIterator<Item = Range<Point>>,
20131    ) -> Vec<MultiBufferDiffHunk> {
20132        let mut hunks = Vec::new();
20133        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20134            HashMap::default();
20135        for query_range in ranges {
20136            let query_rows =
20137                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20138            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20139                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20140            ) {
20141                // Include deleted hunks that are adjacent to the query range, because
20142                // otherwise they would be missed.
20143                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20144                if hunk.status().is_deleted() {
20145                    intersects_range |= hunk.row_range.start == query_rows.end;
20146                    intersects_range |= hunk.row_range.end == query_rows.start;
20147                }
20148                if intersects_range {
20149                    if !processed_buffer_rows
20150                        .entry(hunk.buffer_id)
20151                        .or_default()
20152                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20153                    {
20154                        continue;
20155                    }
20156                    hunks.push(hunk);
20157                }
20158            }
20159        }
20160
20161        hunks
20162    }
20163
20164    fn display_diff_hunks_for_rows<'a>(
20165        &'a self,
20166        display_rows: Range<DisplayRow>,
20167        folded_buffers: &'a HashSet<BufferId>,
20168    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20169        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20170        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20171
20172        self.buffer_snapshot
20173            .diff_hunks_in_range(buffer_start..buffer_end)
20174            .filter_map(|hunk| {
20175                if folded_buffers.contains(&hunk.buffer_id) {
20176                    return None;
20177                }
20178
20179                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20180                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20181
20182                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20183                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20184
20185                let display_hunk = if hunk_display_start.column() != 0 {
20186                    DisplayDiffHunk::Folded {
20187                        display_row: hunk_display_start.row(),
20188                    }
20189                } else {
20190                    let mut end_row = hunk_display_end.row();
20191                    if hunk_display_end.column() > 0 {
20192                        end_row.0 += 1;
20193                    }
20194                    let is_created_file = hunk.is_created_file();
20195                    DisplayDiffHunk::Unfolded {
20196                        status: hunk.status(),
20197                        diff_base_byte_range: hunk.diff_base_byte_range,
20198                        display_row_range: hunk_display_start.row()..end_row,
20199                        multi_buffer_range: Anchor::range_in_buffer(
20200                            hunk.excerpt_id,
20201                            hunk.buffer_id,
20202                            hunk.buffer_range,
20203                        ),
20204                        is_created_file,
20205                    }
20206                };
20207
20208                Some(display_hunk)
20209            })
20210    }
20211
20212    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20213        self.display_snapshot.buffer_snapshot.language_at(position)
20214    }
20215
20216    pub fn is_focused(&self) -> bool {
20217        self.is_focused
20218    }
20219
20220    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20221        self.placeholder_text.as_ref()
20222    }
20223
20224    pub fn scroll_position(&self) -> gpui::Point<f32> {
20225        self.scroll_anchor.scroll_position(&self.display_snapshot)
20226    }
20227
20228    fn gutter_dimensions(
20229        &self,
20230        font_id: FontId,
20231        font_size: Pixels,
20232        max_line_number_width: Pixels,
20233        cx: &App,
20234    ) -> Option<GutterDimensions> {
20235        if !self.show_gutter {
20236            return None;
20237        }
20238
20239        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20240        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20241
20242        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20243            matches!(
20244                ProjectSettings::get_global(cx).git.git_gutter,
20245                Some(GitGutterSetting::TrackedFiles)
20246            )
20247        });
20248        let gutter_settings = EditorSettings::get_global(cx).gutter;
20249        let show_line_numbers = self
20250            .show_line_numbers
20251            .unwrap_or(gutter_settings.line_numbers);
20252        let line_gutter_width = if show_line_numbers {
20253            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20254            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20255            max_line_number_width.max(min_width_for_number_on_gutter)
20256        } else {
20257            0.0.into()
20258        };
20259
20260        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20261        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20262
20263        let git_blame_entries_width =
20264            self.git_blame_gutter_max_author_length
20265                .map(|max_author_length| {
20266                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20267                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20268
20269                    /// The number of characters to dedicate to gaps and margins.
20270                    const SPACING_WIDTH: usize = 4;
20271
20272                    let max_char_count = max_author_length.min(renderer.max_author_length())
20273                        + ::git::SHORT_SHA_LENGTH
20274                        + MAX_RELATIVE_TIMESTAMP.len()
20275                        + SPACING_WIDTH;
20276
20277                    em_advance * max_char_count
20278                });
20279
20280        let is_singleton = self.buffer_snapshot.is_singleton();
20281
20282        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20283        left_padding += if !is_singleton {
20284            em_width * 4.0
20285        } else if show_runnables || show_breakpoints {
20286            em_width * 3.0
20287        } else if show_git_gutter && show_line_numbers {
20288            em_width * 2.0
20289        } else if show_git_gutter || show_line_numbers {
20290            em_width
20291        } else {
20292            px(0.)
20293        };
20294
20295        let shows_folds = is_singleton && gutter_settings.folds;
20296
20297        let right_padding = if shows_folds && show_line_numbers {
20298            em_width * 4.0
20299        } else if shows_folds || (!is_singleton && show_line_numbers) {
20300            em_width * 3.0
20301        } else if show_line_numbers {
20302            em_width
20303        } else {
20304            px(0.)
20305        };
20306
20307        Some(GutterDimensions {
20308            left_padding,
20309            right_padding,
20310            width: line_gutter_width + left_padding + right_padding,
20311            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20312            git_blame_entries_width,
20313        })
20314    }
20315
20316    pub fn render_crease_toggle(
20317        &self,
20318        buffer_row: MultiBufferRow,
20319        row_contains_cursor: bool,
20320        editor: Entity<Editor>,
20321        window: &mut Window,
20322        cx: &mut App,
20323    ) -> Option<AnyElement> {
20324        let folded = self.is_line_folded(buffer_row);
20325        let mut is_foldable = false;
20326
20327        if let Some(crease) = self
20328            .crease_snapshot
20329            .query_row(buffer_row, &self.buffer_snapshot)
20330        {
20331            is_foldable = true;
20332            match crease {
20333                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20334                    if let Some(render_toggle) = render_toggle {
20335                        let toggle_callback =
20336                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20337                                if folded {
20338                                    editor.update(cx, |editor, cx| {
20339                                        editor.fold_at(buffer_row, window, cx)
20340                                    });
20341                                } else {
20342                                    editor.update(cx, |editor, cx| {
20343                                        editor.unfold_at(buffer_row, window, cx)
20344                                    });
20345                                }
20346                            });
20347                        return Some((render_toggle)(
20348                            buffer_row,
20349                            folded,
20350                            toggle_callback,
20351                            window,
20352                            cx,
20353                        ));
20354                    }
20355                }
20356            }
20357        }
20358
20359        is_foldable |= self.starts_indent(buffer_row);
20360
20361        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20362            Some(
20363                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20364                    .toggle_state(folded)
20365                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20366                        if folded {
20367                            this.unfold_at(buffer_row, window, cx);
20368                        } else {
20369                            this.fold_at(buffer_row, window, cx);
20370                        }
20371                    }))
20372                    .into_any_element(),
20373            )
20374        } else {
20375            None
20376        }
20377    }
20378
20379    pub fn render_crease_trailer(
20380        &self,
20381        buffer_row: MultiBufferRow,
20382        window: &mut Window,
20383        cx: &mut App,
20384    ) -> Option<AnyElement> {
20385        let folded = self.is_line_folded(buffer_row);
20386        if let Crease::Inline { render_trailer, .. } = self
20387            .crease_snapshot
20388            .query_row(buffer_row, &self.buffer_snapshot)?
20389        {
20390            let render_trailer = render_trailer.as_ref()?;
20391            Some(render_trailer(buffer_row, folded, window, cx))
20392        } else {
20393            None
20394        }
20395    }
20396}
20397
20398impl Deref for EditorSnapshot {
20399    type Target = DisplaySnapshot;
20400
20401    fn deref(&self) -> &Self::Target {
20402        &self.display_snapshot
20403    }
20404}
20405
20406#[derive(Clone, Debug, PartialEq, Eq)]
20407pub enum EditorEvent {
20408    InputIgnored {
20409        text: Arc<str>,
20410    },
20411    InputHandled {
20412        utf16_range_to_replace: Option<Range<isize>>,
20413        text: Arc<str>,
20414    },
20415    ExcerptsAdded {
20416        buffer: Entity<Buffer>,
20417        predecessor: ExcerptId,
20418        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20419    },
20420    ExcerptsRemoved {
20421        ids: Vec<ExcerptId>,
20422        removed_buffer_ids: Vec<BufferId>,
20423    },
20424    BufferFoldToggled {
20425        ids: Vec<ExcerptId>,
20426        folded: bool,
20427    },
20428    ExcerptsEdited {
20429        ids: Vec<ExcerptId>,
20430    },
20431    ExcerptsExpanded {
20432        ids: Vec<ExcerptId>,
20433    },
20434    BufferEdited,
20435    Edited {
20436        transaction_id: clock::Lamport,
20437    },
20438    Reparsed(BufferId),
20439    Focused,
20440    FocusedIn,
20441    Blurred,
20442    DirtyChanged,
20443    Saved,
20444    TitleChanged,
20445    DiffBaseChanged,
20446    SelectionsChanged {
20447        local: bool,
20448    },
20449    ScrollPositionChanged {
20450        local: bool,
20451        autoscroll: bool,
20452    },
20453    Closed,
20454    TransactionUndone {
20455        transaction_id: clock::Lamport,
20456    },
20457    TransactionBegun {
20458        transaction_id: clock::Lamport,
20459    },
20460    Reloaded,
20461    CursorShapeChanged,
20462    PushedToNavHistory {
20463        anchor: Anchor,
20464        is_deactivate: bool,
20465    },
20466}
20467
20468impl EventEmitter<EditorEvent> for Editor {}
20469
20470impl Focusable for Editor {
20471    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20472        self.focus_handle.clone()
20473    }
20474}
20475
20476impl Render for Editor {
20477    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20478        let settings = ThemeSettings::get_global(cx);
20479
20480        let mut text_style = match self.mode {
20481            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20482                color: cx.theme().colors().editor_foreground,
20483                font_family: settings.ui_font.family.clone(),
20484                font_features: settings.ui_font.features.clone(),
20485                font_fallbacks: settings.ui_font.fallbacks.clone(),
20486                font_size: rems(0.875).into(),
20487                font_weight: settings.ui_font.weight,
20488                line_height: relative(settings.buffer_line_height.value()),
20489                ..Default::default()
20490            },
20491            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20492                color: cx.theme().colors().editor_foreground,
20493                font_family: settings.buffer_font.family.clone(),
20494                font_features: settings.buffer_font.features.clone(),
20495                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20496                font_size: settings.buffer_font_size(cx).into(),
20497                font_weight: settings.buffer_font.weight,
20498                line_height: relative(settings.buffer_line_height.value()),
20499                ..Default::default()
20500            },
20501        };
20502        if let Some(text_style_refinement) = &self.text_style_refinement {
20503            text_style.refine(text_style_refinement)
20504        }
20505
20506        let background = match self.mode {
20507            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20508            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20509            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20510            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20511        };
20512
20513        EditorElement::new(
20514            &cx.entity(),
20515            EditorStyle {
20516                background,
20517                local_player: cx.theme().players().local(),
20518                text: text_style,
20519                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20520                syntax: cx.theme().syntax().clone(),
20521                status: cx.theme().status().clone(),
20522                inlay_hints_style: make_inlay_hints_style(cx),
20523                inline_completion_styles: make_suggestion_styles(cx),
20524                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20525                show_underlines: !self.mode.is_minimap(),
20526            },
20527        )
20528    }
20529}
20530
20531impl EntityInputHandler for Editor {
20532    fn text_for_range(
20533        &mut self,
20534        range_utf16: Range<usize>,
20535        adjusted_range: &mut Option<Range<usize>>,
20536        _: &mut Window,
20537        cx: &mut Context<Self>,
20538    ) -> Option<String> {
20539        let snapshot = self.buffer.read(cx).read(cx);
20540        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20541        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20542        if (start.0..end.0) != range_utf16 {
20543            adjusted_range.replace(start.0..end.0);
20544        }
20545        Some(snapshot.text_for_range(start..end).collect())
20546    }
20547
20548    fn selected_text_range(
20549        &mut self,
20550        ignore_disabled_input: bool,
20551        _: &mut Window,
20552        cx: &mut Context<Self>,
20553    ) -> Option<UTF16Selection> {
20554        // Prevent the IME menu from appearing when holding down an alphabetic key
20555        // while input is disabled.
20556        if !ignore_disabled_input && !self.input_enabled {
20557            return None;
20558        }
20559
20560        let selection = self.selections.newest::<OffsetUtf16>(cx);
20561        let range = selection.range();
20562
20563        Some(UTF16Selection {
20564            range: range.start.0..range.end.0,
20565            reversed: selection.reversed,
20566        })
20567    }
20568
20569    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20570        let snapshot = self.buffer.read(cx).read(cx);
20571        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20572        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20573    }
20574
20575    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20576        self.clear_highlights::<InputComposition>(cx);
20577        self.ime_transaction.take();
20578    }
20579
20580    fn replace_text_in_range(
20581        &mut self,
20582        range_utf16: Option<Range<usize>>,
20583        text: &str,
20584        window: &mut Window,
20585        cx: &mut Context<Self>,
20586    ) {
20587        if !self.input_enabled {
20588            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20589            return;
20590        }
20591
20592        self.transact(window, cx, |this, window, cx| {
20593            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20594                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20595                Some(this.selection_replacement_ranges(range_utf16, cx))
20596            } else {
20597                this.marked_text_ranges(cx)
20598            };
20599
20600            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20601                let newest_selection_id = this.selections.newest_anchor().id;
20602                this.selections
20603                    .all::<OffsetUtf16>(cx)
20604                    .iter()
20605                    .zip(ranges_to_replace.iter())
20606                    .find_map(|(selection, range)| {
20607                        if selection.id == newest_selection_id {
20608                            Some(
20609                                (range.start.0 as isize - selection.head().0 as isize)
20610                                    ..(range.end.0 as isize - selection.head().0 as isize),
20611                            )
20612                        } else {
20613                            None
20614                        }
20615                    })
20616            });
20617
20618            cx.emit(EditorEvent::InputHandled {
20619                utf16_range_to_replace: range_to_replace,
20620                text: text.into(),
20621            });
20622
20623            if let Some(new_selected_ranges) = new_selected_ranges {
20624                this.change_selections(None, window, cx, |selections| {
20625                    selections.select_ranges(new_selected_ranges)
20626                });
20627                this.backspace(&Default::default(), window, cx);
20628            }
20629
20630            this.handle_input(text, window, cx);
20631        });
20632
20633        if let Some(transaction) = self.ime_transaction {
20634            self.buffer.update(cx, |buffer, cx| {
20635                buffer.group_until_transaction(transaction, cx);
20636            });
20637        }
20638
20639        self.unmark_text(window, cx);
20640    }
20641
20642    fn replace_and_mark_text_in_range(
20643        &mut self,
20644        range_utf16: Option<Range<usize>>,
20645        text: &str,
20646        new_selected_range_utf16: Option<Range<usize>>,
20647        window: &mut Window,
20648        cx: &mut Context<Self>,
20649    ) {
20650        if !self.input_enabled {
20651            return;
20652        }
20653
20654        let transaction = self.transact(window, cx, |this, window, cx| {
20655            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20656                let snapshot = this.buffer.read(cx).read(cx);
20657                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20658                    for marked_range in &mut marked_ranges {
20659                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20660                        marked_range.start.0 += relative_range_utf16.start;
20661                        marked_range.start =
20662                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20663                        marked_range.end =
20664                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20665                    }
20666                }
20667                Some(marked_ranges)
20668            } else if let Some(range_utf16) = range_utf16 {
20669                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20670                Some(this.selection_replacement_ranges(range_utf16, cx))
20671            } else {
20672                None
20673            };
20674
20675            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20676                let newest_selection_id = this.selections.newest_anchor().id;
20677                this.selections
20678                    .all::<OffsetUtf16>(cx)
20679                    .iter()
20680                    .zip(ranges_to_replace.iter())
20681                    .find_map(|(selection, range)| {
20682                        if selection.id == newest_selection_id {
20683                            Some(
20684                                (range.start.0 as isize - selection.head().0 as isize)
20685                                    ..(range.end.0 as isize - selection.head().0 as isize),
20686                            )
20687                        } else {
20688                            None
20689                        }
20690                    })
20691            });
20692
20693            cx.emit(EditorEvent::InputHandled {
20694                utf16_range_to_replace: range_to_replace,
20695                text: text.into(),
20696            });
20697
20698            if let Some(ranges) = ranges_to_replace {
20699                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20700            }
20701
20702            let marked_ranges = {
20703                let snapshot = this.buffer.read(cx).read(cx);
20704                this.selections
20705                    .disjoint_anchors()
20706                    .iter()
20707                    .map(|selection| {
20708                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20709                    })
20710                    .collect::<Vec<_>>()
20711            };
20712
20713            if text.is_empty() {
20714                this.unmark_text(window, cx);
20715            } else {
20716                this.highlight_text::<InputComposition>(
20717                    marked_ranges.clone(),
20718                    HighlightStyle {
20719                        underline: Some(UnderlineStyle {
20720                            thickness: px(1.),
20721                            color: None,
20722                            wavy: false,
20723                        }),
20724                        ..Default::default()
20725                    },
20726                    cx,
20727                );
20728            }
20729
20730            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20731            let use_autoclose = this.use_autoclose;
20732            let use_auto_surround = this.use_auto_surround;
20733            this.set_use_autoclose(false);
20734            this.set_use_auto_surround(false);
20735            this.handle_input(text, window, cx);
20736            this.set_use_autoclose(use_autoclose);
20737            this.set_use_auto_surround(use_auto_surround);
20738
20739            if let Some(new_selected_range) = new_selected_range_utf16 {
20740                let snapshot = this.buffer.read(cx).read(cx);
20741                let new_selected_ranges = marked_ranges
20742                    .into_iter()
20743                    .map(|marked_range| {
20744                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20745                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20746                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20747                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20748                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20749                    })
20750                    .collect::<Vec<_>>();
20751
20752                drop(snapshot);
20753                this.change_selections(None, window, cx, |selections| {
20754                    selections.select_ranges(new_selected_ranges)
20755                });
20756            }
20757        });
20758
20759        self.ime_transaction = self.ime_transaction.or(transaction);
20760        if let Some(transaction) = self.ime_transaction {
20761            self.buffer.update(cx, |buffer, cx| {
20762                buffer.group_until_transaction(transaction, cx);
20763            });
20764        }
20765
20766        if self.text_highlights::<InputComposition>(cx).is_none() {
20767            self.ime_transaction.take();
20768        }
20769    }
20770
20771    fn bounds_for_range(
20772        &mut self,
20773        range_utf16: Range<usize>,
20774        element_bounds: gpui::Bounds<Pixels>,
20775        window: &mut Window,
20776        cx: &mut Context<Self>,
20777    ) -> Option<gpui::Bounds<Pixels>> {
20778        let text_layout_details = self.text_layout_details(window);
20779        let gpui::Size {
20780            width: em_width,
20781            height: line_height,
20782        } = self.character_size(window);
20783
20784        let snapshot = self.snapshot(window, cx);
20785        let scroll_position = snapshot.scroll_position();
20786        let scroll_left = scroll_position.x * em_width;
20787
20788        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20789        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20790            + self.gutter_dimensions.width
20791            + self.gutter_dimensions.margin;
20792        let y = line_height * (start.row().as_f32() - scroll_position.y);
20793
20794        Some(Bounds {
20795            origin: element_bounds.origin + point(x, y),
20796            size: size(em_width, line_height),
20797        })
20798    }
20799
20800    fn character_index_for_point(
20801        &mut self,
20802        point: gpui::Point<Pixels>,
20803        _window: &mut Window,
20804        _cx: &mut Context<Self>,
20805    ) -> Option<usize> {
20806        let position_map = self.last_position_map.as_ref()?;
20807        if !position_map.text_hitbox.contains(&point) {
20808            return None;
20809        }
20810        let display_point = position_map.point_for_position(point).previous_valid;
20811        let anchor = position_map
20812            .snapshot
20813            .display_point_to_anchor(display_point, Bias::Left);
20814        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20815        Some(utf16_offset.0)
20816    }
20817}
20818
20819trait SelectionExt {
20820    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20821    fn spanned_rows(
20822        &self,
20823        include_end_if_at_line_start: bool,
20824        map: &DisplaySnapshot,
20825    ) -> Range<MultiBufferRow>;
20826}
20827
20828impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20829    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20830        let start = self
20831            .start
20832            .to_point(&map.buffer_snapshot)
20833            .to_display_point(map);
20834        let end = self
20835            .end
20836            .to_point(&map.buffer_snapshot)
20837            .to_display_point(map);
20838        if self.reversed {
20839            end..start
20840        } else {
20841            start..end
20842        }
20843    }
20844
20845    fn spanned_rows(
20846        &self,
20847        include_end_if_at_line_start: bool,
20848        map: &DisplaySnapshot,
20849    ) -> Range<MultiBufferRow> {
20850        let start = self.start.to_point(&map.buffer_snapshot);
20851        let mut end = self.end.to_point(&map.buffer_snapshot);
20852        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20853            end.row -= 1;
20854        }
20855
20856        let buffer_start = map.prev_line_boundary(start).0;
20857        let buffer_end = map.next_line_boundary(end).0;
20858        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20859    }
20860}
20861
20862impl<T: InvalidationRegion> InvalidationStack<T> {
20863    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20864    where
20865        S: Clone + ToOffset,
20866    {
20867        while let Some(region) = self.last() {
20868            let all_selections_inside_invalidation_ranges =
20869                if selections.len() == region.ranges().len() {
20870                    selections
20871                        .iter()
20872                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20873                        .all(|(selection, invalidation_range)| {
20874                            let head = selection.head().to_offset(buffer);
20875                            invalidation_range.start <= head && invalidation_range.end >= head
20876                        })
20877                } else {
20878                    false
20879                };
20880
20881            if all_selections_inside_invalidation_ranges {
20882                break;
20883            } else {
20884                self.pop();
20885            }
20886        }
20887    }
20888}
20889
20890impl<T> Default for InvalidationStack<T> {
20891    fn default() -> Self {
20892        Self(Default::default())
20893    }
20894}
20895
20896impl<T> Deref for InvalidationStack<T> {
20897    type Target = Vec<T>;
20898
20899    fn deref(&self) -> &Self::Target {
20900        &self.0
20901    }
20902}
20903
20904impl<T> DerefMut for InvalidationStack<T> {
20905    fn deref_mut(&mut self) -> &mut Self::Target {
20906        &mut self.0
20907    }
20908}
20909
20910impl InvalidationRegion for SnippetState {
20911    fn ranges(&self) -> &[Range<Anchor>] {
20912        &self.ranges[self.active_index]
20913    }
20914}
20915
20916fn inline_completion_edit_text(
20917    current_snapshot: &BufferSnapshot,
20918    edits: &[(Range<Anchor>, String)],
20919    edit_preview: &EditPreview,
20920    include_deletions: bool,
20921    cx: &App,
20922) -> HighlightedText {
20923    let edits = edits
20924        .iter()
20925        .map(|(anchor, text)| {
20926            (
20927                anchor.start.text_anchor..anchor.end.text_anchor,
20928                text.clone(),
20929            )
20930        })
20931        .collect::<Vec<_>>();
20932
20933    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
20934}
20935
20936pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
20937    match severity {
20938        lsp::DiagnosticSeverity::ERROR => colors.error,
20939        lsp::DiagnosticSeverity::WARNING => colors.warning,
20940        lsp::DiagnosticSeverity::INFORMATION => colors.info,
20941        lsp::DiagnosticSeverity::HINT => colors.info,
20942        _ => colors.ignored,
20943    }
20944}
20945
20946pub fn styled_runs_for_code_label<'a>(
20947    label: &'a CodeLabel,
20948    syntax_theme: &'a theme::SyntaxTheme,
20949) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
20950    let fade_out = HighlightStyle {
20951        fade_out: Some(0.35),
20952        ..Default::default()
20953    };
20954
20955    let mut prev_end = label.filter_range.end;
20956    label
20957        .runs
20958        .iter()
20959        .enumerate()
20960        .flat_map(move |(ix, (range, highlight_id))| {
20961            let style = if let Some(style) = highlight_id.style(syntax_theme) {
20962                style
20963            } else {
20964                return Default::default();
20965            };
20966            let mut muted_style = style;
20967            muted_style.highlight(fade_out);
20968
20969            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
20970            if range.start >= label.filter_range.end {
20971                if range.start > prev_end {
20972                    runs.push((prev_end..range.start, fade_out));
20973                }
20974                runs.push((range.clone(), muted_style));
20975            } else if range.end <= label.filter_range.end {
20976                runs.push((range.clone(), style));
20977            } else {
20978                runs.push((range.start..label.filter_range.end, style));
20979                runs.push((label.filter_range.end..range.end, muted_style));
20980            }
20981            prev_end = cmp::max(prev_end, range.end);
20982
20983            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
20984                runs.push((prev_end..label.text.len(), fade_out));
20985            }
20986
20987            runs
20988        })
20989}
20990
20991pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
20992    let mut prev_index = 0;
20993    let mut prev_codepoint: Option<char> = None;
20994    text.char_indices()
20995        .chain([(text.len(), '\0')])
20996        .filter_map(move |(index, codepoint)| {
20997            let prev_codepoint = prev_codepoint.replace(codepoint)?;
20998            let is_boundary = index == text.len()
20999                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21000                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21001            if is_boundary {
21002                let chunk = &text[prev_index..index];
21003                prev_index = index;
21004                Some(chunk)
21005            } else {
21006                None
21007            }
21008        })
21009}
21010
21011pub trait RangeToAnchorExt: Sized {
21012    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21013
21014    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21015        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21016        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21017    }
21018}
21019
21020impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21021    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21022        let start_offset = self.start.to_offset(snapshot);
21023        let end_offset = self.end.to_offset(snapshot);
21024        if start_offset == end_offset {
21025            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21026        } else {
21027            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21028        }
21029    }
21030}
21031
21032pub trait RowExt {
21033    fn as_f32(&self) -> f32;
21034
21035    fn next_row(&self) -> Self;
21036
21037    fn previous_row(&self) -> Self;
21038
21039    fn minus(&self, other: Self) -> u32;
21040}
21041
21042impl RowExt for DisplayRow {
21043    fn as_f32(&self) -> f32 {
21044        self.0 as f32
21045    }
21046
21047    fn next_row(&self) -> Self {
21048        Self(self.0 + 1)
21049    }
21050
21051    fn previous_row(&self) -> Self {
21052        Self(self.0.saturating_sub(1))
21053    }
21054
21055    fn minus(&self, other: Self) -> u32 {
21056        self.0 - other.0
21057    }
21058}
21059
21060impl RowExt for MultiBufferRow {
21061    fn as_f32(&self) -> f32 {
21062        self.0 as f32
21063    }
21064
21065    fn next_row(&self) -> Self {
21066        Self(self.0 + 1)
21067    }
21068
21069    fn previous_row(&self) -> Self {
21070        Self(self.0.saturating_sub(1))
21071    }
21072
21073    fn minus(&self, other: Self) -> u32 {
21074        self.0 - other.0
21075    }
21076}
21077
21078trait RowRangeExt {
21079    type Row;
21080
21081    fn len(&self) -> usize;
21082
21083    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21084}
21085
21086impl RowRangeExt for Range<MultiBufferRow> {
21087    type Row = MultiBufferRow;
21088
21089    fn len(&self) -> usize {
21090        (self.end.0 - self.start.0) as usize
21091    }
21092
21093    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21094        (self.start.0..self.end.0).map(MultiBufferRow)
21095    }
21096}
21097
21098impl RowRangeExt for Range<DisplayRow> {
21099    type Row = DisplayRow;
21100
21101    fn len(&self) -> usize {
21102        (self.end.0 - self.start.0) as usize
21103    }
21104
21105    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21106        (self.start.0..self.end.0).map(DisplayRow)
21107    }
21108}
21109
21110/// If select range has more than one line, we
21111/// just point the cursor to range.start.
21112fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21113    if range.start.row == range.end.row {
21114        range
21115    } else {
21116        range.start..range.start
21117    }
21118}
21119pub struct KillRing(ClipboardItem);
21120impl Global for KillRing {}
21121
21122const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21123
21124enum BreakpointPromptEditAction {
21125    Log,
21126    Condition,
21127    HitCondition,
21128}
21129
21130struct BreakpointPromptEditor {
21131    pub(crate) prompt: Entity<Editor>,
21132    editor: WeakEntity<Editor>,
21133    breakpoint_anchor: Anchor,
21134    breakpoint: Breakpoint,
21135    edit_action: BreakpointPromptEditAction,
21136    block_ids: HashSet<CustomBlockId>,
21137    editor_margins: Arc<Mutex<EditorMargins>>,
21138    _subscriptions: Vec<Subscription>,
21139}
21140
21141impl BreakpointPromptEditor {
21142    const MAX_LINES: u8 = 4;
21143
21144    fn new(
21145        editor: WeakEntity<Editor>,
21146        breakpoint_anchor: Anchor,
21147        breakpoint: Breakpoint,
21148        edit_action: BreakpointPromptEditAction,
21149        window: &mut Window,
21150        cx: &mut Context<Self>,
21151    ) -> Self {
21152        let base_text = match edit_action {
21153            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21154            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21155            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21156        }
21157        .map(|msg| msg.to_string())
21158        .unwrap_or_default();
21159
21160        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21161        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21162
21163        let prompt = cx.new(|cx| {
21164            let mut prompt = Editor::new(
21165                EditorMode::AutoHeight {
21166                    max_lines: Self::MAX_LINES as usize,
21167                },
21168                buffer,
21169                None,
21170                window,
21171                cx,
21172            );
21173            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21174            prompt.set_show_cursor_when_unfocused(false, cx);
21175            prompt.set_placeholder_text(
21176                match edit_action {
21177                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21178                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21179                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21180                },
21181                cx,
21182            );
21183
21184            prompt
21185        });
21186
21187        Self {
21188            prompt,
21189            editor,
21190            breakpoint_anchor,
21191            breakpoint,
21192            edit_action,
21193            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21194            block_ids: Default::default(),
21195            _subscriptions: vec![],
21196        }
21197    }
21198
21199    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21200        self.block_ids.extend(block_ids)
21201    }
21202
21203    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21204        if let Some(editor) = self.editor.upgrade() {
21205            let message = self
21206                .prompt
21207                .read(cx)
21208                .buffer
21209                .read(cx)
21210                .as_singleton()
21211                .expect("A multi buffer in breakpoint prompt isn't possible")
21212                .read(cx)
21213                .as_rope()
21214                .to_string();
21215
21216            editor.update(cx, |editor, cx| {
21217                editor.edit_breakpoint_at_anchor(
21218                    self.breakpoint_anchor,
21219                    self.breakpoint.clone(),
21220                    match self.edit_action {
21221                        BreakpointPromptEditAction::Log => {
21222                            BreakpointEditAction::EditLogMessage(message.into())
21223                        }
21224                        BreakpointPromptEditAction::Condition => {
21225                            BreakpointEditAction::EditCondition(message.into())
21226                        }
21227                        BreakpointPromptEditAction::HitCondition => {
21228                            BreakpointEditAction::EditHitCondition(message.into())
21229                        }
21230                    },
21231                    cx,
21232                );
21233
21234                editor.remove_blocks(self.block_ids.clone(), None, cx);
21235                cx.focus_self(window);
21236            });
21237        }
21238    }
21239
21240    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21241        self.editor
21242            .update(cx, |editor, cx| {
21243                editor.remove_blocks(self.block_ids.clone(), None, cx);
21244                window.focus(&editor.focus_handle);
21245            })
21246            .log_err();
21247    }
21248
21249    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21250        let settings = ThemeSettings::get_global(cx);
21251        let text_style = TextStyle {
21252            color: if self.prompt.read(cx).read_only(cx) {
21253                cx.theme().colors().text_disabled
21254            } else {
21255                cx.theme().colors().text
21256            },
21257            font_family: settings.buffer_font.family.clone(),
21258            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21259            font_size: settings.buffer_font_size(cx).into(),
21260            font_weight: settings.buffer_font.weight,
21261            line_height: relative(settings.buffer_line_height.value()),
21262            ..Default::default()
21263        };
21264        EditorElement::new(
21265            &self.prompt,
21266            EditorStyle {
21267                background: cx.theme().colors().editor_background,
21268                local_player: cx.theme().players().local(),
21269                text: text_style,
21270                ..Default::default()
21271            },
21272        )
21273    }
21274}
21275
21276impl Render for BreakpointPromptEditor {
21277    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21278        let editor_margins = *self.editor_margins.lock();
21279        let gutter_dimensions = editor_margins.gutter;
21280        h_flex()
21281            .key_context("Editor")
21282            .bg(cx.theme().colors().editor_background)
21283            .border_y_1()
21284            .border_color(cx.theme().status().info_border)
21285            .size_full()
21286            .py(window.line_height() / 2.5)
21287            .on_action(cx.listener(Self::confirm))
21288            .on_action(cx.listener(Self::cancel))
21289            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21290            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21291    }
21292}
21293
21294impl Focusable for BreakpointPromptEditor {
21295    fn focus_handle(&self, cx: &App) -> FocusHandle {
21296        self.prompt.focus_handle(cx)
21297    }
21298}
21299
21300fn all_edits_insertions_or_deletions(
21301    edits: &Vec<(Range<Anchor>, String)>,
21302    snapshot: &MultiBufferSnapshot,
21303) -> bool {
21304    let mut all_insertions = true;
21305    let mut all_deletions = true;
21306
21307    for (range, new_text) in edits.iter() {
21308        let range_is_empty = range.to_offset(&snapshot).is_empty();
21309        let text_is_empty = new_text.is_empty();
21310
21311        if range_is_empty != text_is_empty {
21312            if range_is_empty {
21313                all_deletions = false;
21314            } else {
21315                all_insertions = false;
21316            }
21317        } else {
21318            return false;
21319        }
21320
21321        if !all_insertions && !all_deletions {
21322            return false;
21323        }
21324    }
21325    all_insertions || all_deletions
21326}
21327
21328struct MissingEditPredictionKeybindingTooltip;
21329
21330impl Render for MissingEditPredictionKeybindingTooltip {
21331    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21332        ui::tooltip_container(window, cx, |container, _, cx| {
21333            container
21334                .flex_shrink_0()
21335                .max_w_80()
21336                .min_h(rems_from_px(124.))
21337                .justify_between()
21338                .child(
21339                    v_flex()
21340                        .flex_1()
21341                        .text_ui_sm(cx)
21342                        .child(Label::new("Conflict with Accept Keybinding"))
21343                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21344                )
21345                .child(
21346                    h_flex()
21347                        .pb_1()
21348                        .gap_1()
21349                        .items_end()
21350                        .w_full()
21351                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21352                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21353                        }))
21354                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21355                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21356                        })),
21357                )
21358        })
21359    }
21360}
21361
21362#[derive(Debug, Clone, Copy, PartialEq)]
21363pub struct LineHighlight {
21364    pub background: Background,
21365    pub border: Option<gpui::Hsla>,
21366    pub include_gutter: bool,
21367    pub type_id: Option<TypeId>,
21368}
21369
21370fn render_diff_hunk_controls(
21371    row: u32,
21372    status: &DiffHunkStatus,
21373    hunk_range: Range<Anchor>,
21374    is_created_file: bool,
21375    line_height: Pixels,
21376    editor: &Entity<Editor>,
21377    _window: &mut Window,
21378    cx: &mut App,
21379) -> AnyElement {
21380    h_flex()
21381        .h(line_height)
21382        .mr_1()
21383        .gap_1()
21384        .px_0p5()
21385        .pb_1()
21386        .border_x_1()
21387        .border_b_1()
21388        .border_color(cx.theme().colors().border_variant)
21389        .rounded_b_lg()
21390        .bg(cx.theme().colors().editor_background)
21391        .gap_1()
21392        .occlude()
21393        .shadow_md()
21394        .child(if status.has_secondary_hunk() {
21395            Button::new(("stage", row as u64), "Stage")
21396                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21397                .tooltip({
21398                    let focus_handle = editor.focus_handle(cx);
21399                    move |window, cx| {
21400                        Tooltip::for_action_in(
21401                            "Stage Hunk",
21402                            &::git::ToggleStaged,
21403                            &focus_handle,
21404                            window,
21405                            cx,
21406                        )
21407                    }
21408                })
21409                .on_click({
21410                    let editor = editor.clone();
21411                    move |_event, _window, cx| {
21412                        editor.update(cx, |editor, cx| {
21413                            editor.stage_or_unstage_diff_hunks(
21414                                true,
21415                                vec![hunk_range.start..hunk_range.start],
21416                                cx,
21417                            );
21418                        });
21419                    }
21420                })
21421        } else {
21422            Button::new(("unstage", row as u64), "Unstage")
21423                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21424                .tooltip({
21425                    let focus_handle = editor.focus_handle(cx);
21426                    move |window, cx| {
21427                        Tooltip::for_action_in(
21428                            "Unstage Hunk",
21429                            &::git::ToggleStaged,
21430                            &focus_handle,
21431                            window,
21432                            cx,
21433                        )
21434                    }
21435                })
21436                .on_click({
21437                    let editor = editor.clone();
21438                    move |_event, _window, cx| {
21439                        editor.update(cx, |editor, cx| {
21440                            editor.stage_or_unstage_diff_hunks(
21441                                false,
21442                                vec![hunk_range.start..hunk_range.start],
21443                                cx,
21444                            );
21445                        });
21446                    }
21447                })
21448        })
21449        .child(
21450            Button::new(("restore", row as u64), "Restore")
21451                .tooltip({
21452                    let focus_handle = editor.focus_handle(cx);
21453                    move |window, cx| {
21454                        Tooltip::for_action_in(
21455                            "Restore Hunk",
21456                            &::git::Restore,
21457                            &focus_handle,
21458                            window,
21459                            cx,
21460                        )
21461                    }
21462                })
21463                .on_click({
21464                    let editor = editor.clone();
21465                    move |_event, window, cx| {
21466                        editor.update(cx, |editor, cx| {
21467                            let snapshot = editor.snapshot(window, cx);
21468                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21469                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21470                        });
21471                    }
21472                })
21473                .disabled(is_created_file),
21474        )
21475        .when(
21476            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21477            |el| {
21478                el.child(
21479                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21480                        .shape(IconButtonShape::Square)
21481                        .icon_size(IconSize::Small)
21482                        // .disabled(!has_multiple_hunks)
21483                        .tooltip({
21484                            let focus_handle = editor.focus_handle(cx);
21485                            move |window, cx| {
21486                                Tooltip::for_action_in(
21487                                    "Next Hunk",
21488                                    &GoToHunk,
21489                                    &focus_handle,
21490                                    window,
21491                                    cx,
21492                                )
21493                            }
21494                        })
21495                        .on_click({
21496                            let editor = editor.clone();
21497                            move |_event, window, cx| {
21498                                editor.update(cx, |editor, cx| {
21499                                    let snapshot = editor.snapshot(window, cx);
21500                                    let position =
21501                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21502                                    editor.go_to_hunk_before_or_after_position(
21503                                        &snapshot,
21504                                        position,
21505                                        Direction::Next,
21506                                        window,
21507                                        cx,
21508                                    );
21509                                    editor.expand_selected_diff_hunks(cx);
21510                                });
21511                            }
21512                        }),
21513                )
21514                .child(
21515                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21516                        .shape(IconButtonShape::Square)
21517                        .icon_size(IconSize::Small)
21518                        // .disabled(!has_multiple_hunks)
21519                        .tooltip({
21520                            let focus_handle = editor.focus_handle(cx);
21521                            move |window, cx| {
21522                                Tooltip::for_action_in(
21523                                    "Previous Hunk",
21524                                    &GoToPreviousHunk,
21525                                    &focus_handle,
21526                                    window,
21527                                    cx,
21528                                )
21529                            }
21530                        })
21531                        .on_click({
21532                            let editor = editor.clone();
21533                            move |_event, window, cx| {
21534                                editor.update(cx, |editor, cx| {
21535                                    let snapshot = editor.snapshot(window, cx);
21536                                    let point =
21537                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21538                                    editor.go_to_hunk_before_or_after_position(
21539                                        &snapshot,
21540                                        point,
21541                                        Direction::Prev,
21542                                        window,
21543                                        cx,
21544                                    );
21545                                    editor.expand_selected_diff_hunks(cx);
21546                                });
21547                            }
21548                        }),
21549                )
21550            },
21551        )
21552        .into_any_element()
21553}