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};
  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    disable_expand_excerpt_buttons: bool,
  927    show_line_numbers: Option<bool>,
  928    use_relative_line_numbers: Option<bool>,
  929    show_git_diff_gutter: Option<bool>,
  930    show_code_actions: Option<bool>,
  931    show_runnables: Option<bool>,
  932    show_breakpoints: Option<bool>,
  933    show_wrap_guides: Option<bool>,
  934    show_indent_guides: Option<bool>,
  935    placeholder_text: Option<Arc<str>>,
  936    highlight_order: usize,
  937    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  938    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  939    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  940    scrollbar_marker_state: ScrollbarMarkerState,
  941    active_indent_guides_state: ActiveIndentGuidesState,
  942    nav_history: Option<ItemNavHistory>,
  943    context_menu: RefCell<Option<CodeContextMenu>>,
  944    context_menu_options: Option<ContextMenuOptions>,
  945    mouse_context_menu: Option<MouseContextMenu>,
  946    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  947    inline_blame_popover: Option<InlineBlamePopover>,
  948    signature_help_state: SignatureHelpState,
  949    auto_signature_help: Option<bool>,
  950    find_all_references_task_sources: Vec<Anchor>,
  951    next_completion_id: CompletionId,
  952    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  953    code_actions_task: Option<Task<Result<()>>>,
  954    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  955    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    document_highlights_task: Option<Task<()>>,
  957    linked_editing_range_task: Option<Task<Option<()>>>,
  958    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  959    pending_rename: Option<RenameState>,
  960    searchable: bool,
  961    cursor_shape: CursorShape,
  962    current_line_highlight: Option<CurrentLineHighlight>,
  963    collapse_matches: bool,
  964    autoindent_mode: Option<AutoindentMode>,
  965    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  966    input_enabled: bool,
  967    use_modal_editing: bool,
  968    read_only: bool,
  969    leader_id: Option<CollaboratorId>,
  970    remote_id: Option<ViewId>,
  971    pub hover_state: HoverState,
  972    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  973    gutter_hovered: bool,
  974    hovered_link_state: Option<HoveredLinkState>,
  975    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  976    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  977    active_inline_completion: Option<InlineCompletionState>,
  978    /// Used to prevent flickering as the user types while the menu is open
  979    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  980    edit_prediction_settings: EditPredictionSettings,
  981    inline_completions_hidden_for_vim_mode: bool,
  982    show_inline_completions_override: Option<bool>,
  983    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  984    edit_prediction_preview: EditPredictionPreview,
  985    edit_prediction_indent_conflict: bool,
  986    edit_prediction_requires_modifier_in_indent_conflict: bool,
  987    inlay_hint_cache: InlayHintCache,
  988    next_inlay_id: usize,
  989    _subscriptions: Vec<Subscription>,
  990    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  991    gutter_dimensions: GutterDimensions,
  992    style: Option<EditorStyle>,
  993    text_style_refinement: Option<TextStyleRefinement>,
  994    next_editor_action_id: EditorActionId,
  995    editor_actions:
  996        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  997    use_autoclose: bool,
  998    use_auto_surround: bool,
  999    auto_replace_emoji_shortcode: bool,
 1000    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1001    show_git_blame_gutter: bool,
 1002    show_git_blame_inline: bool,
 1003    show_git_blame_inline_delay_task: Option<Task<()>>,
 1004    git_blame_inline_enabled: bool,
 1005    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1006    serialize_dirty_buffers: bool,
 1007    show_selection_menu: Option<bool>,
 1008    blame: Option<Entity<GitBlame>>,
 1009    blame_subscription: Option<Subscription>,
 1010    custom_context_menu: Option<
 1011        Box<
 1012            dyn 'static
 1013                + Fn(
 1014                    &mut Self,
 1015                    DisplayPoint,
 1016                    &mut Window,
 1017                    &mut Context<Self>,
 1018                ) -> Option<Entity<ui::ContextMenu>>,
 1019        >,
 1020    >,
 1021    last_bounds: Option<Bounds<Pixels>>,
 1022    last_position_map: Option<Rc<PositionMap>>,
 1023    expect_bounds_change: Option<Bounds<Pixels>>,
 1024    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1025    tasks_update_task: Option<Task<()>>,
 1026    breakpoint_store: Option<Entity<BreakpointStore>>,
 1027    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1028    in_project_search: bool,
 1029    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1030    breadcrumb_header: Option<String>,
 1031    focused_block: Option<FocusedBlock>,
 1032    next_scroll_position: NextScrollCursorCenterTopBottom,
 1033    addons: HashMap<TypeId, Box<dyn Addon>>,
 1034    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1035    load_diff_task: Option<Shared<Task<()>>>,
 1036    /// Whether we are temporarily displaying a diff other than git's
 1037    temporary_diff_override: bool,
 1038    selection_mark_mode: bool,
 1039    toggle_fold_multiple_buffers: Task<()>,
 1040    _scroll_cursor_center_top_bottom_task: Task<()>,
 1041    serialize_selections: Task<()>,
 1042    serialize_folds: Task<()>,
 1043    mouse_cursor_hidden: bool,
 1044    minimap: Option<Entity<Self>>,
 1045    hide_mouse_mode: HideMouseMode,
 1046    pub change_list: ChangeList,
 1047    inline_value_cache: InlineValueCache,
 1048}
 1049
 1050#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1051enum NextScrollCursorCenterTopBottom {
 1052    #[default]
 1053    Center,
 1054    Top,
 1055    Bottom,
 1056}
 1057
 1058impl NextScrollCursorCenterTopBottom {
 1059    fn next(&self) -> Self {
 1060        match self {
 1061            Self::Center => Self::Top,
 1062            Self::Top => Self::Bottom,
 1063            Self::Bottom => Self::Center,
 1064        }
 1065    }
 1066}
 1067
 1068#[derive(Clone)]
 1069pub struct EditorSnapshot {
 1070    pub mode: EditorMode,
 1071    show_gutter: bool,
 1072    show_line_numbers: Option<bool>,
 1073    show_git_diff_gutter: Option<bool>,
 1074    show_runnables: Option<bool>,
 1075    show_breakpoints: Option<bool>,
 1076    git_blame_gutter_max_author_length: Option<usize>,
 1077    pub display_snapshot: DisplaySnapshot,
 1078    pub placeholder_text: Option<Arc<str>>,
 1079    is_focused: bool,
 1080    scroll_anchor: ScrollAnchor,
 1081    ongoing_scroll: OngoingScroll,
 1082    current_line_highlight: CurrentLineHighlight,
 1083    gutter_hovered: bool,
 1084}
 1085
 1086#[derive(Default, Debug, Clone, Copy)]
 1087pub struct GutterDimensions {
 1088    pub left_padding: Pixels,
 1089    pub right_padding: Pixels,
 1090    pub width: Pixels,
 1091    pub margin: Pixels,
 1092    pub git_blame_entries_width: Option<Pixels>,
 1093}
 1094
 1095impl GutterDimensions {
 1096    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1097        Self {
 1098            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1099            ..Default::default()
 1100        }
 1101    }
 1102
 1103    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1104        -cx.text_system().descent(font_id, font_size)
 1105    }
 1106    /// The full width of the space taken up by the gutter.
 1107    pub fn full_width(&self) -> Pixels {
 1108        self.margin + self.width
 1109    }
 1110
 1111    /// The width of the space reserved for the fold indicators,
 1112    /// use alongside 'justify_end' and `gutter_width` to
 1113    /// right align content with the line numbers
 1114    pub fn fold_area_width(&self) -> Pixels {
 1115        self.margin + self.right_padding
 1116    }
 1117}
 1118
 1119#[derive(Debug)]
 1120pub struct RemoteSelection {
 1121    pub replica_id: ReplicaId,
 1122    pub selection: Selection<Anchor>,
 1123    pub cursor_shape: CursorShape,
 1124    pub collaborator_id: CollaboratorId,
 1125    pub line_mode: bool,
 1126    pub user_name: Option<SharedString>,
 1127    pub color: PlayerColor,
 1128}
 1129
 1130#[derive(Clone, Debug)]
 1131struct SelectionHistoryEntry {
 1132    selections: Arc<[Selection<Anchor>]>,
 1133    select_next_state: Option<SelectNextState>,
 1134    select_prev_state: Option<SelectNextState>,
 1135    add_selections_state: Option<AddSelectionsState>,
 1136}
 1137
 1138enum SelectionHistoryMode {
 1139    Normal,
 1140    Undoing,
 1141    Redoing,
 1142}
 1143
 1144#[derive(Clone, PartialEq, Eq, Hash)]
 1145struct HoveredCursor {
 1146    replica_id: u16,
 1147    selection_id: usize,
 1148}
 1149
 1150impl Default for SelectionHistoryMode {
 1151    fn default() -> Self {
 1152        Self::Normal
 1153    }
 1154}
 1155
 1156#[derive(Default)]
 1157struct SelectionHistory {
 1158    #[allow(clippy::type_complexity)]
 1159    selections_by_transaction:
 1160        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1161    mode: SelectionHistoryMode,
 1162    undo_stack: VecDeque<SelectionHistoryEntry>,
 1163    redo_stack: VecDeque<SelectionHistoryEntry>,
 1164}
 1165
 1166impl SelectionHistory {
 1167    fn insert_transaction(
 1168        &mut self,
 1169        transaction_id: TransactionId,
 1170        selections: Arc<[Selection<Anchor>]>,
 1171    ) {
 1172        self.selections_by_transaction
 1173            .insert(transaction_id, (selections, None));
 1174    }
 1175
 1176    #[allow(clippy::type_complexity)]
 1177    fn transaction(
 1178        &self,
 1179        transaction_id: TransactionId,
 1180    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1181        self.selections_by_transaction.get(&transaction_id)
 1182    }
 1183
 1184    #[allow(clippy::type_complexity)]
 1185    fn transaction_mut(
 1186        &mut self,
 1187        transaction_id: TransactionId,
 1188    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1189        self.selections_by_transaction.get_mut(&transaction_id)
 1190    }
 1191
 1192    fn push(&mut self, entry: SelectionHistoryEntry) {
 1193        if !entry.selections.is_empty() {
 1194            match self.mode {
 1195                SelectionHistoryMode::Normal => {
 1196                    self.push_undo(entry);
 1197                    self.redo_stack.clear();
 1198                }
 1199                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1200                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1201            }
 1202        }
 1203    }
 1204
 1205    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1206        if self
 1207            .undo_stack
 1208            .back()
 1209            .map_or(true, |e| e.selections != entry.selections)
 1210        {
 1211            self.undo_stack.push_back(entry);
 1212            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1213                self.undo_stack.pop_front();
 1214            }
 1215        }
 1216    }
 1217
 1218    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1219        if self
 1220            .redo_stack
 1221            .back()
 1222            .map_or(true, |e| e.selections != entry.selections)
 1223        {
 1224            self.redo_stack.push_back(entry);
 1225            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1226                self.redo_stack.pop_front();
 1227            }
 1228        }
 1229    }
 1230}
 1231
 1232#[derive(Clone, Copy)]
 1233pub struct RowHighlightOptions {
 1234    pub autoscroll: bool,
 1235    pub include_gutter: bool,
 1236}
 1237
 1238impl Default for RowHighlightOptions {
 1239    fn default() -> Self {
 1240        Self {
 1241            autoscroll: Default::default(),
 1242            include_gutter: true,
 1243        }
 1244    }
 1245}
 1246
 1247struct RowHighlight {
 1248    index: usize,
 1249    range: Range<Anchor>,
 1250    color: Hsla,
 1251    options: RowHighlightOptions,
 1252    type_id: TypeId,
 1253}
 1254
 1255#[derive(Clone, Debug)]
 1256struct AddSelectionsState {
 1257    above: bool,
 1258    stack: Vec<usize>,
 1259}
 1260
 1261#[derive(Clone)]
 1262struct SelectNextState {
 1263    query: AhoCorasick,
 1264    wordwise: bool,
 1265    done: bool,
 1266}
 1267
 1268impl std::fmt::Debug for SelectNextState {
 1269    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1270        f.debug_struct(std::any::type_name::<Self>())
 1271            .field("wordwise", &self.wordwise)
 1272            .field("done", &self.done)
 1273            .finish()
 1274    }
 1275}
 1276
 1277#[derive(Debug)]
 1278struct AutocloseRegion {
 1279    selection_id: usize,
 1280    range: Range<Anchor>,
 1281    pair: BracketPair,
 1282}
 1283
 1284#[derive(Debug)]
 1285struct SnippetState {
 1286    ranges: Vec<Vec<Range<Anchor>>>,
 1287    active_index: usize,
 1288    choices: Vec<Option<Vec<String>>>,
 1289}
 1290
 1291#[doc(hidden)]
 1292pub struct RenameState {
 1293    pub range: Range<Anchor>,
 1294    pub old_name: Arc<str>,
 1295    pub editor: Entity<Editor>,
 1296    block_id: CustomBlockId,
 1297}
 1298
 1299struct InvalidationStack<T>(Vec<T>);
 1300
 1301struct RegisteredInlineCompletionProvider {
 1302    provider: Arc<dyn InlineCompletionProviderHandle>,
 1303    _subscription: Subscription,
 1304}
 1305
 1306#[derive(Debug, PartialEq, Eq)]
 1307pub struct ActiveDiagnosticGroup {
 1308    pub active_range: Range<Anchor>,
 1309    pub active_message: String,
 1310    pub group_id: usize,
 1311    pub blocks: HashSet<CustomBlockId>,
 1312}
 1313
 1314#[derive(Debug, PartialEq, Eq)]
 1315
 1316pub(crate) enum ActiveDiagnostic {
 1317    None,
 1318    All,
 1319    Group(ActiveDiagnosticGroup),
 1320}
 1321
 1322#[derive(Serialize, Deserialize, Clone, Debug)]
 1323pub struct ClipboardSelection {
 1324    /// The number of bytes in this selection.
 1325    pub len: usize,
 1326    /// Whether this was a full-line selection.
 1327    pub is_entire_line: bool,
 1328    /// The indentation of the first line when this content was originally copied.
 1329    pub first_line_indent: u32,
 1330}
 1331
 1332// selections, scroll behavior, was newest selection reversed
 1333type SelectSyntaxNodeHistoryState = (
 1334    Box<[Selection<usize>]>,
 1335    SelectSyntaxNodeScrollBehavior,
 1336    bool,
 1337);
 1338
 1339#[derive(Default)]
 1340struct SelectSyntaxNodeHistory {
 1341    stack: Vec<SelectSyntaxNodeHistoryState>,
 1342    // disable temporarily to allow changing selections without losing the stack
 1343    pub disable_clearing: bool,
 1344}
 1345
 1346impl SelectSyntaxNodeHistory {
 1347    pub fn try_clear(&mut self) {
 1348        if !self.disable_clearing {
 1349            self.stack.clear();
 1350        }
 1351    }
 1352
 1353    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1354        self.stack.push(selection);
 1355    }
 1356
 1357    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1358        self.stack.pop()
 1359    }
 1360}
 1361
 1362enum SelectSyntaxNodeScrollBehavior {
 1363    CursorTop,
 1364    FitSelection,
 1365    CursorBottom,
 1366}
 1367
 1368#[derive(Debug)]
 1369pub(crate) struct NavigationData {
 1370    cursor_anchor: Anchor,
 1371    cursor_position: Point,
 1372    scroll_anchor: ScrollAnchor,
 1373    scroll_top_row: u32,
 1374}
 1375
 1376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1377pub enum GotoDefinitionKind {
 1378    Symbol,
 1379    Declaration,
 1380    Type,
 1381    Implementation,
 1382}
 1383
 1384#[derive(Debug, Clone)]
 1385enum InlayHintRefreshReason {
 1386    ModifiersChanged(bool),
 1387    Toggle(bool),
 1388    SettingsChange(InlayHintSettings),
 1389    NewLinesShown,
 1390    BufferEdited(HashSet<Arc<Language>>),
 1391    RefreshRequested,
 1392    ExcerptsRemoved(Vec<ExcerptId>),
 1393}
 1394
 1395impl InlayHintRefreshReason {
 1396    fn description(&self) -> &'static str {
 1397        match self {
 1398            Self::ModifiersChanged(_) => "modifiers changed",
 1399            Self::Toggle(_) => "toggle",
 1400            Self::SettingsChange(_) => "settings change",
 1401            Self::NewLinesShown => "new lines shown",
 1402            Self::BufferEdited(_) => "buffer edited",
 1403            Self::RefreshRequested => "refresh requested",
 1404            Self::ExcerptsRemoved(_) => "excerpts removed",
 1405        }
 1406    }
 1407}
 1408
 1409pub enum FormatTarget {
 1410    Buffers,
 1411    Ranges(Vec<Range<MultiBufferPoint>>),
 1412}
 1413
 1414pub(crate) struct FocusedBlock {
 1415    id: BlockId,
 1416    focus_handle: WeakFocusHandle,
 1417}
 1418
 1419#[derive(Clone)]
 1420enum JumpData {
 1421    MultiBufferRow {
 1422        row: MultiBufferRow,
 1423        line_offset_from_top: u32,
 1424    },
 1425    MultiBufferPoint {
 1426        excerpt_id: ExcerptId,
 1427        position: Point,
 1428        anchor: text::Anchor,
 1429        line_offset_from_top: u32,
 1430    },
 1431}
 1432
 1433pub enum MultibufferSelectionMode {
 1434    First,
 1435    All,
 1436}
 1437
 1438#[derive(Clone, Copy, Debug, Default)]
 1439pub struct RewrapOptions {
 1440    pub override_language_settings: bool,
 1441    pub preserve_existing_whitespace: bool,
 1442}
 1443
 1444impl Editor {
 1445    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1446        let buffer = cx.new(|cx| Buffer::local("", cx));
 1447        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1448        Self::new(
 1449            EditorMode::SingleLine { auto_width: false },
 1450            buffer,
 1451            None,
 1452            window,
 1453            cx,
 1454        )
 1455    }
 1456
 1457    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1458        let buffer = cx.new(|cx| Buffer::local("", cx));
 1459        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1460        Self::new(EditorMode::full(), buffer, None, window, cx)
 1461    }
 1462
 1463    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1464        let buffer = cx.new(|cx| Buffer::local("", cx));
 1465        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1466        Self::new(
 1467            EditorMode::SingleLine { auto_width: true },
 1468            buffer,
 1469            None,
 1470            window,
 1471            cx,
 1472        )
 1473    }
 1474
 1475    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1476        let buffer = cx.new(|cx| Buffer::local("", cx));
 1477        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1478        Self::new(
 1479            EditorMode::AutoHeight { max_lines },
 1480            buffer,
 1481            None,
 1482            window,
 1483            cx,
 1484        )
 1485    }
 1486
 1487    pub fn for_buffer(
 1488        buffer: Entity<Buffer>,
 1489        project: Option<Entity<Project>>,
 1490        window: &mut Window,
 1491        cx: &mut Context<Self>,
 1492    ) -> Self {
 1493        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1494        Self::new(EditorMode::full(), buffer, project, window, cx)
 1495    }
 1496
 1497    pub fn for_multibuffer(
 1498        buffer: Entity<MultiBuffer>,
 1499        project: Option<Entity<Project>>,
 1500        window: &mut Window,
 1501        cx: &mut Context<Self>,
 1502    ) -> Self {
 1503        Self::new(EditorMode::full(), buffer, project, window, cx)
 1504    }
 1505
 1506    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1507        let mut clone = Self::new(
 1508            self.mode.clone(),
 1509            self.buffer.clone(),
 1510            self.project.clone(),
 1511            window,
 1512            cx,
 1513        );
 1514        self.display_map.update(cx, |display_map, cx| {
 1515            let snapshot = display_map.snapshot(cx);
 1516            clone.display_map.update(cx, |display_map, cx| {
 1517                display_map.set_state(&snapshot, cx);
 1518            });
 1519        });
 1520        clone.folds_did_change(cx);
 1521        clone.selections.clone_state(&self.selections);
 1522        clone.scroll_manager.clone_state(&self.scroll_manager);
 1523        clone.searchable = self.searchable;
 1524        clone.read_only = self.read_only;
 1525        clone
 1526    }
 1527
 1528    pub fn new(
 1529        mode: EditorMode,
 1530        buffer: Entity<MultiBuffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        Editor::new_internal(mode, buffer, project, None, window, cx)
 1536    }
 1537
 1538    fn new_internal(
 1539        mode: EditorMode,
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        display_map: Option<Entity<DisplayMap>>,
 1543        window: &mut Window,
 1544        cx: &mut Context<Self>,
 1545    ) -> Self {
 1546        debug_assert!(
 1547            display_map.is_none() || mode.is_minimap(),
 1548            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1549        );
 1550
 1551        let full_mode = mode.is_full();
 1552        let diagnostics_max_severity = if full_mode {
 1553            EditorSettings::get_global(cx)
 1554                .diagnostics_max_severity
 1555                .unwrap_or(DiagnosticSeverity::Hint)
 1556        } else {
 1557            DiagnosticSeverity::Off
 1558        };
 1559        let style = window.text_style();
 1560        let font_size = style.font_size.to_pixels(window.rem_size());
 1561        let editor = cx.entity().downgrade();
 1562        let fold_placeholder = FoldPlaceholder {
 1563            constrain_width: true,
 1564            render: Arc::new(move |fold_id, fold_range, cx| {
 1565                let editor = editor.clone();
 1566                div()
 1567                    .id(fold_id)
 1568                    .bg(cx.theme().colors().ghost_element_background)
 1569                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1570                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1571                    .rounded_xs()
 1572                    .size_full()
 1573                    .cursor_pointer()
 1574                    .child("")
 1575                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1576                    .on_click(move |_, _window, cx| {
 1577                        editor
 1578                            .update(cx, |editor, cx| {
 1579                                editor.unfold_ranges(
 1580                                    &[fold_range.start..fold_range.end],
 1581                                    true,
 1582                                    false,
 1583                                    cx,
 1584                                );
 1585                                cx.stop_propagation();
 1586                            })
 1587                            .ok();
 1588                    })
 1589                    .into_any()
 1590            }),
 1591            merge_adjacent: true,
 1592            ..FoldPlaceholder::default()
 1593        };
 1594        let display_map = display_map.unwrap_or_else(|| {
 1595            cx.new(|cx| {
 1596                DisplayMap::new(
 1597                    buffer.clone(),
 1598                    style.font(),
 1599                    font_size,
 1600                    None,
 1601                    FILE_HEADER_HEIGHT,
 1602                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1603                    fold_placeholder,
 1604                    diagnostics_max_severity,
 1605                    cx,
 1606                )
 1607            })
 1608        });
 1609
 1610        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1611
 1612        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1613
 1614        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1615            .then(|| language_settings::SoftWrap::None);
 1616
 1617        let mut project_subscriptions = Vec::new();
 1618        if mode.is_full() {
 1619            if let Some(project) = project.as_ref() {
 1620                project_subscriptions.push(cx.subscribe_in(
 1621                    project,
 1622                    window,
 1623                    |editor, _, event, window, cx| match event {
 1624                        project::Event::RefreshCodeLens => {
 1625                            // we always query lens with actions, without storing them, always refreshing them
 1626                        }
 1627                        project::Event::RefreshInlayHints => {
 1628                            editor
 1629                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1630                        }
 1631                        project::Event::SnippetEdit(id, snippet_edits) => {
 1632                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1633                                let focus_handle = editor.focus_handle(cx);
 1634                                if focus_handle.is_focused(window) {
 1635                                    let snapshot = buffer.read(cx).snapshot();
 1636                                    for (range, snippet) in snippet_edits {
 1637                                        let editor_range =
 1638                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1639                                        editor
 1640                                            .insert_snippet(
 1641                                                &[editor_range],
 1642                                                snippet.clone(),
 1643                                                window,
 1644                                                cx,
 1645                                            )
 1646                                            .ok();
 1647                                    }
 1648                                }
 1649                            }
 1650                        }
 1651                        _ => {}
 1652                    },
 1653                ));
 1654                if let Some(task_inventory) = project
 1655                    .read(cx)
 1656                    .task_store()
 1657                    .read(cx)
 1658                    .task_inventory()
 1659                    .cloned()
 1660                {
 1661                    project_subscriptions.push(cx.observe_in(
 1662                        &task_inventory,
 1663                        window,
 1664                        |editor, _, window, cx| {
 1665                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1666                        },
 1667                    ));
 1668                };
 1669
 1670                project_subscriptions.push(cx.subscribe_in(
 1671                    &project.read(cx).breakpoint_store(),
 1672                    window,
 1673                    |editor, _, event, window, cx| match event {
 1674                        BreakpointStoreEvent::ClearDebugLines => {
 1675                            editor.clear_row_highlights::<ActiveDebugLine>();
 1676                            editor.refresh_inline_values(cx);
 1677                        }
 1678                        BreakpointStoreEvent::SetDebugLine => {
 1679                            if editor.go_to_active_debug_line(window, cx) {
 1680                                cx.stop_propagation();
 1681                            }
 1682
 1683                            editor.refresh_inline_values(cx);
 1684                        }
 1685                        _ => {}
 1686                    },
 1687                ));
 1688            }
 1689        }
 1690
 1691        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1692
 1693        let inlay_hint_settings =
 1694            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1695        let focus_handle = cx.focus_handle();
 1696        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1697            .detach();
 1698        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1699            .detach();
 1700        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1701            .detach();
 1702        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1703            .detach();
 1704
 1705        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1706            Some(false)
 1707        } else {
 1708            None
 1709        };
 1710
 1711        let breakpoint_store = match (&mode, project.as_ref()) {
 1712            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1713            _ => None,
 1714        };
 1715
 1716        let mut code_action_providers = Vec::new();
 1717        let mut load_uncommitted_diff = None;
 1718        if let Some(project) = project.clone() {
 1719            load_uncommitted_diff = Some(
 1720                update_uncommitted_diff_for_buffer(
 1721                    cx.entity(),
 1722                    &project,
 1723                    buffer.read(cx).all_buffers(),
 1724                    buffer.clone(),
 1725                    cx,
 1726                )
 1727                .shared(),
 1728            );
 1729            code_action_providers.push(Rc::new(project) as Rc<_>);
 1730        }
 1731
 1732        let mut this = Self {
 1733            focus_handle,
 1734            show_cursor_when_unfocused: false,
 1735            last_focused_descendant: None,
 1736            buffer: buffer.clone(),
 1737            display_map: display_map.clone(),
 1738            selections,
 1739            scroll_manager: ScrollManager::new(cx),
 1740            columnar_selection_tail: None,
 1741            add_selections_state: None,
 1742            select_next_state: None,
 1743            select_prev_state: None,
 1744            selection_history: SelectionHistory::default(),
 1745            autoclose_regions: Vec::new(),
 1746            snippet_stack: InvalidationStack::default(),
 1747            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1748            ime_transaction: None,
 1749            active_diagnostics: ActiveDiagnostic::None,
 1750            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1751            inline_diagnostics_update: Task::ready(()),
 1752            inline_diagnostics: Vec::new(),
 1753            soft_wrap_mode_override,
 1754            diagnostics_max_severity,
 1755            hard_wrap: None,
 1756            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1757            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1758            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1759            project,
 1760            blink_manager: blink_manager.clone(),
 1761            show_local_selections: true,
 1762            show_scrollbars: full_mode,
 1763            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1764            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1765            show_gutter: mode.is_full(),
 1766            show_line_numbers: None,
 1767            use_relative_line_numbers: None,
 1768            disable_expand_excerpt_buttons: false,
 1769            show_git_diff_gutter: None,
 1770            show_code_actions: None,
 1771            show_runnables: None,
 1772            show_breakpoints: None,
 1773            show_wrap_guides: None,
 1774            show_indent_guides,
 1775            placeholder_text: None,
 1776            highlight_order: 0,
 1777            highlighted_rows: HashMap::default(),
 1778            background_highlights: TreeMap::default(),
 1779            gutter_highlights: TreeMap::default(),
 1780            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1781            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1782            nav_history: None,
 1783            context_menu: RefCell::new(None),
 1784            context_menu_options: None,
 1785            mouse_context_menu: None,
 1786            completion_tasks: Vec::new(),
 1787            inline_blame_popover: None,
 1788            signature_help_state: SignatureHelpState::default(),
 1789            auto_signature_help: None,
 1790            find_all_references_task_sources: Vec::new(),
 1791            next_completion_id: 0,
 1792            next_inlay_id: 0,
 1793            code_action_providers,
 1794            available_code_actions: None,
 1795            code_actions_task: None,
 1796            quick_selection_highlight_task: None,
 1797            debounced_selection_highlight_task: None,
 1798            document_highlights_task: None,
 1799            linked_editing_range_task: None,
 1800            pending_rename: None,
 1801            searchable: true,
 1802            cursor_shape: EditorSettings::get_global(cx)
 1803                .cursor_shape
 1804                .unwrap_or_default(),
 1805            current_line_highlight: None,
 1806            autoindent_mode: Some(AutoindentMode::EachLine),
 1807            collapse_matches: false,
 1808            workspace: None,
 1809            input_enabled: true,
 1810            use_modal_editing: mode.is_full(),
 1811            read_only: mode.is_minimap(),
 1812            use_autoclose: true,
 1813            use_auto_surround: true,
 1814            auto_replace_emoji_shortcode: false,
 1815            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1816            leader_id: None,
 1817            remote_id: None,
 1818            hover_state: HoverState::default(),
 1819            pending_mouse_down: None,
 1820            hovered_link_state: None,
 1821            edit_prediction_provider: None,
 1822            active_inline_completion: None,
 1823            stale_inline_completion_in_menu: None,
 1824            edit_prediction_preview: EditPredictionPreview::Inactive {
 1825                released_too_fast: false,
 1826            },
 1827            inline_diagnostics_enabled: mode.is_full(),
 1828            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1829            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1830
 1831            gutter_hovered: false,
 1832            pixel_position_of_newest_cursor: None,
 1833            last_bounds: None,
 1834            last_position_map: None,
 1835            expect_bounds_change: None,
 1836            gutter_dimensions: GutterDimensions::default(),
 1837            style: None,
 1838            show_cursor_names: false,
 1839            hovered_cursors: HashMap::default(),
 1840            next_editor_action_id: EditorActionId::default(),
 1841            editor_actions: Rc::default(),
 1842            inline_completions_hidden_for_vim_mode: false,
 1843            show_inline_completions_override: None,
 1844            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1845            edit_prediction_settings: EditPredictionSettings::Disabled,
 1846            edit_prediction_indent_conflict: false,
 1847            edit_prediction_requires_modifier_in_indent_conflict: true,
 1848            custom_context_menu: None,
 1849            show_git_blame_gutter: false,
 1850            show_git_blame_inline: false,
 1851            show_selection_menu: None,
 1852            show_git_blame_inline_delay_task: None,
 1853            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1854            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1855            serialize_dirty_buffers: !mode.is_minimap()
 1856                && ProjectSettings::get_global(cx)
 1857                    .session
 1858                    .restore_unsaved_buffers,
 1859            blame: None,
 1860            blame_subscription: None,
 1861            tasks: BTreeMap::default(),
 1862
 1863            breakpoint_store,
 1864            gutter_breakpoint_indicator: (None, None),
 1865            _subscriptions: vec![
 1866                cx.observe(&buffer, Self::on_buffer_changed),
 1867                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1868                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1869                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1870                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1871                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1872                cx.observe_window_activation(window, |editor, window, cx| {
 1873                    let active = window.is_window_active();
 1874                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1875                        if active {
 1876                            blink_manager.enable(cx);
 1877                        } else {
 1878                            blink_manager.disable(cx);
 1879                        }
 1880                    });
 1881                }),
 1882            ],
 1883            tasks_update_task: None,
 1884            linked_edit_ranges: Default::default(),
 1885            in_project_search: false,
 1886            previous_search_ranges: None,
 1887            breadcrumb_header: None,
 1888            focused_block: None,
 1889            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1890            addons: HashMap::default(),
 1891            registered_buffers: HashMap::default(),
 1892            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1893            selection_mark_mode: false,
 1894            toggle_fold_multiple_buffers: Task::ready(()),
 1895            serialize_selections: Task::ready(()),
 1896            serialize_folds: Task::ready(()),
 1897            text_style_refinement: None,
 1898            load_diff_task: load_uncommitted_diff,
 1899            temporary_diff_override: false,
 1900            mouse_cursor_hidden: false,
 1901            minimap: None,
 1902            hide_mouse_mode: EditorSettings::get_global(cx)
 1903                .hide_mouse
 1904                .unwrap_or_default(),
 1905            change_list: ChangeList::new(),
 1906            mode,
 1907        };
 1908        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1909            this._subscriptions
 1910                .push(cx.observe(breakpoints, |_, _, cx| {
 1911                    cx.notify();
 1912                }));
 1913        }
 1914        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1915        this._subscriptions.extend(project_subscriptions);
 1916
 1917        this._subscriptions.push(cx.subscribe_in(
 1918            &cx.entity(),
 1919            window,
 1920            |editor, _, e: &EditorEvent, window, cx| match e {
 1921                EditorEvent::ScrollPositionChanged { local, .. } => {
 1922                    if *local {
 1923                        let new_anchor = editor.scroll_manager.anchor();
 1924                        let snapshot = editor.snapshot(window, cx);
 1925                        editor.update_restoration_data(cx, move |data| {
 1926                            data.scroll_position = (
 1927                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1928                                new_anchor.offset,
 1929                            );
 1930                        });
 1931                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1932                        editor.inline_blame_popover.take();
 1933                    }
 1934                }
 1935                EditorEvent::Edited { .. } => {
 1936                    if !vim_enabled(cx) {
 1937                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1938                        let pop_state = editor
 1939                            .change_list
 1940                            .last()
 1941                            .map(|previous| {
 1942                                previous.len() == selections.len()
 1943                                    && previous.iter().enumerate().all(|(ix, p)| {
 1944                                        p.to_display_point(&map).row()
 1945                                            == selections[ix].head().row()
 1946                                    })
 1947                            })
 1948                            .unwrap_or(false);
 1949                        let new_positions = selections
 1950                            .into_iter()
 1951                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1952                            .collect();
 1953                        editor
 1954                            .change_list
 1955                            .push_to_change_list(pop_state, new_positions);
 1956                    }
 1957                }
 1958                _ => (),
 1959            },
 1960        ));
 1961
 1962        if let Some(dap_store) = this
 1963            .project
 1964            .as_ref()
 1965            .map(|project| project.read(cx).dap_store())
 1966        {
 1967            let weak_editor = cx.weak_entity();
 1968
 1969            this._subscriptions
 1970                .push(
 1971                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1972                        let session_entity = cx.entity();
 1973                        weak_editor
 1974                            .update(cx, |editor, cx| {
 1975                                editor._subscriptions.push(
 1976                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1977                                );
 1978                            })
 1979                            .ok();
 1980                    }),
 1981                );
 1982
 1983            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1984                this._subscriptions
 1985                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1986            }
 1987        }
 1988
 1989        this.end_selection(window, cx);
 1990        this.scroll_manager.show_scrollbars(window, cx);
 1991        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1992
 1993        if full_mode {
 1994            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1995            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1996
 1997            if this.git_blame_inline_enabled {
 1998                this.start_git_blame_inline(false, window, cx);
 1999            }
 2000
 2001            this.go_to_active_debug_line(window, cx);
 2002
 2003            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2004                if let Some(project) = this.project.as_ref() {
 2005                    let handle = project.update(cx, |project, cx| {
 2006                        project.register_buffer_with_language_servers(&buffer, cx)
 2007                    });
 2008                    this.registered_buffers
 2009                        .insert(buffer.read(cx).remote_id(), handle);
 2010                }
 2011            }
 2012
 2013            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2014        }
 2015
 2016        this.report_editor_event("Editor Opened", None, cx);
 2017        this
 2018    }
 2019
 2020    pub fn deploy_mouse_context_menu(
 2021        &mut self,
 2022        position: gpui::Point<Pixels>,
 2023        context_menu: Entity<ContextMenu>,
 2024        window: &mut Window,
 2025        cx: &mut Context<Self>,
 2026    ) {
 2027        self.mouse_context_menu = Some(MouseContextMenu::new(
 2028            self,
 2029            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2030            context_menu,
 2031            window,
 2032            cx,
 2033        ));
 2034    }
 2035
 2036    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2037        self.mouse_context_menu
 2038            .as_ref()
 2039            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2040    }
 2041
 2042    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2043        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2044    }
 2045
 2046    fn key_context_internal(
 2047        &self,
 2048        has_active_edit_prediction: bool,
 2049        window: &Window,
 2050        cx: &App,
 2051    ) -> KeyContext {
 2052        let mut key_context = KeyContext::new_with_defaults();
 2053        key_context.add("Editor");
 2054        let mode = match self.mode {
 2055            EditorMode::SingleLine { .. } => "single_line",
 2056            EditorMode::AutoHeight { .. } => "auto_height",
 2057            EditorMode::Minimap { .. } => "minimap",
 2058            EditorMode::Full { .. } => "full",
 2059        };
 2060
 2061        if EditorSettings::jupyter_enabled(cx) {
 2062            key_context.add("jupyter");
 2063        }
 2064
 2065        key_context.set("mode", mode);
 2066        if self.pending_rename.is_some() {
 2067            key_context.add("renaming");
 2068        }
 2069
 2070        match self.context_menu.borrow().as_ref() {
 2071            Some(CodeContextMenu::Completions(_)) => {
 2072                key_context.add("menu");
 2073                key_context.add("showing_completions");
 2074            }
 2075            Some(CodeContextMenu::CodeActions(_)) => {
 2076                key_context.add("menu");
 2077                key_context.add("showing_code_actions")
 2078            }
 2079            None => {}
 2080        }
 2081
 2082        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2083        if !self.focus_handle(cx).contains_focused(window, cx)
 2084            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2085        {
 2086            for addon in self.addons.values() {
 2087                addon.extend_key_context(&mut key_context, cx)
 2088            }
 2089        }
 2090
 2091        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2092            if let Some(extension) = singleton_buffer
 2093                .read(cx)
 2094                .file()
 2095                .and_then(|file| file.path().extension()?.to_str())
 2096            {
 2097                key_context.set("extension", extension.to_string());
 2098            }
 2099        } else {
 2100            key_context.add("multibuffer");
 2101        }
 2102
 2103        if has_active_edit_prediction {
 2104            if self.edit_prediction_in_conflict() {
 2105                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2106            } else {
 2107                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2108                key_context.add("copilot_suggestion");
 2109            }
 2110        }
 2111
 2112        if self.selection_mark_mode {
 2113            key_context.add("selection_mode");
 2114        }
 2115
 2116        key_context
 2117    }
 2118
 2119    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2120        self.mouse_cursor_hidden = match origin {
 2121            HideMouseCursorOrigin::TypingAction => {
 2122                matches!(
 2123                    self.hide_mouse_mode,
 2124                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2125                )
 2126            }
 2127            HideMouseCursorOrigin::MovementAction => {
 2128                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2129            }
 2130        };
 2131    }
 2132
 2133    pub fn edit_prediction_in_conflict(&self) -> bool {
 2134        if !self.show_edit_predictions_in_menu() {
 2135            return false;
 2136        }
 2137
 2138        let showing_completions = self
 2139            .context_menu
 2140            .borrow()
 2141            .as_ref()
 2142            .map_or(false, |context| {
 2143                matches!(context, CodeContextMenu::Completions(_))
 2144            });
 2145
 2146        showing_completions
 2147            || self.edit_prediction_requires_modifier()
 2148            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2149            // bindings to insert tab characters.
 2150            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2151    }
 2152
 2153    pub fn accept_edit_prediction_keybind(
 2154        &self,
 2155        window: &Window,
 2156        cx: &App,
 2157    ) -> AcceptEditPredictionBinding {
 2158        let key_context = self.key_context_internal(true, window, cx);
 2159        let in_conflict = self.edit_prediction_in_conflict();
 2160
 2161        AcceptEditPredictionBinding(
 2162            window
 2163                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2164                .into_iter()
 2165                .filter(|binding| {
 2166                    !in_conflict
 2167                        || binding
 2168                            .keystrokes()
 2169                            .first()
 2170                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2171                })
 2172                .rev()
 2173                .min_by_key(|binding| {
 2174                    binding
 2175                        .keystrokes()
 2176                        .first()
 2177                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2178                }),
 2179        )
 2180    }
 2181
 2182    pub fn new_file(
 2183        workspace: &mut Workspace,
 2184        _: &workspace::NewFile,
 2185        window: &mut Window,
 2186        cx: &mut Context<Workspace>,
 2187    ) {
 2188        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2189            "Failed to create buffer",
 2190            window,
 2191            cx,
 2192            |e, _, _| match e.error_code() {
 2193                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2194                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2195                e.error_tag("required").unwrap_or("the latest version")
 2196            )),
 2197                _ => None,
 2198            },
 2199        );
 2200    }
 2201
 2202    pub fn new_in_workspace(
 2203        workspace: &mut Workspace,
 2204        window: &mut Window,
 2205        cx: &mut Context<Workspace>,
 2206    ) -> Task<Result<Entity<Editor>>> {
 2207        let project = workspace.project().clone();
 2208        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2209
 2210        cx.spawn_in(window, async move |workspace, cx| {
 2211            let buffer = create.await?;
 2212            workspace.update_in(cx, |workspace, window, cx| {
 2213                let editor =
 2214                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2215                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2216                editor
 2217            })
 2218        })
 2219    }
 2220
 2221    fn new_file_vertical(
 2222        workspace: &mut Workspace,
 2223        _: &workspace::NewFileSplitVertical,
 2224        window: &mut Window,
 2225        cx: &mut Context<Workspace>,
 2226    ) {
 2227        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2228    }
 2229
 2230    fn new_file_horizontal(
 2231        workspace: &mut Workspace,
 2232        _: &workspace::NewFileSplitHorizontal,
 2233        window: &mut Window,
 2234        cx: &mut Context<Workspace>,
 2235    ) {
 2236        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2237    }
 2238
 2239    fn new_file_in_direction(
 2240        workspace: &mut Workspace,
 2241        direction: SplitDirection,
 2242        window: &mut Window,
 2243        cx: &mut Context<Workspace>,
 2244    ) {
 2245        let project = workspace.project().clone();
 2246        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2247
 2248        cx.spawn_in(window, async move |workspace, cx| {
 2249            let buffer = create.await?;
 2250            workspace.update_in(cx, move |workspace, window, cx| {
 2251                workspace.split_item(
 2252                    direction,
 2253                    Box::new(
 2254                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2255                    ),
 2256                    window,
 2257                    cx,
 2258                )
 2259            })?;
 2260            anyhow::Ok(())
 2261        })
 2262        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2263            match e.error_code() {
 2264                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2265                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2266                e.error_tag("required").unwrap_or("the latest version")
 2267            )),
 2268                _ => None,
 2269            }
 2270        });
 2271    }
 2272
 2273    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2274        self.leader_id
 2275    }
 2276
 2277    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2278        &self.buffer
 2279    }
 2280
 2281    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2282        self.workspace.as_ref()?.0.upgrade()
 2283    }
 2284
 2285    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2286        self.buffer().read(cx).title(cx)
 2287    }
 2288
 2289    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2290        let git_blame_gutter_max_author_length = self
 2291            .render_git_blame_gutter(cx)
 2292            .then(|| {
 2293                if let Some(blame) = self.blame.as_ref() {
 2294                    let max_author_length =
 2295                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2296                    Some(max_author_length)
 2297                } else {
 2298                    None
 2299                }
 2300            })
 2301            .flatten();
 2302
 2303        EditorSnapshot {
 2304            mode: self.mode.clone(),
 2305            show_gutter: self.show_gutter,
 2306            show_line_numbers: self.show_line_numbers,
 2307            show_git_diff_gutter: self.show_git_diff_gutter,
 2308            show_runnables: self.show_runnables,
 2309            show_breakpoints: self.show_breakpoints,
 2310            git_blame_gutter_max_author_length,
 2311            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2312            scroll_anchor: self.scroll_manager.anchor(),
 2313            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2314            placeholder_text: self.placeholder_text.clone(),
 2315            is_focused: self.focus_handle.is_focused(window),
 2316            current_line_highlight: self
 2317                .current_line_highlight
 2318                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2319            gutter_hovered: self.gutter_hovered,
 2320        }
 2321    }
 2322
 2323    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2324        self.buffer.read(cx).language_at(point, cx)
 2325    }
 2326
 2327    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2328        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2329    }
 2330
 2331    pub fn active_excerpt(
 2332        &self,
 2333        cx: &App,
 2334    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2335        self.buffer
 2336            .read(cx)
 2337            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2338    }
 2339
 2340    pub fn mode(&self) -> &EditorMode {
 2341        &self.mode
 2342    }
 2343
 2344    pub fn set_mode(&mut self, mode: EditorMode) {
 2345        self.mode = mode;
 2346    }
 2347
 2348    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2349        self.collaboration_hub.as_deref()
 2350    }
 2351
 2352    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2353        self.collaboration_hub = Some(hub);
 2354    }
 2355
 2356    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2357        self.in_project_search = in_project_search;
 2358    }
 2359
 2360    pub fn set_custom_context_menu(
 2361        &mut self,
 2362        f: impl 'static
 2363        + Fn(
 2364            &mut Self,
 2365            DisplayPoint,
 2366            &mut Window,
 2367            &mut Context<Self>,
 2368        ) -> Option<Entity<ui::ContextMenu>>,
 2369    ) {
 2370        self.custom_context_menu = Some(Box::new(f))
 2371    }
 2372
 2373    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2374        self.completion_provider = provider;
 2375    }
 2376
 2377    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2378        self.semantics_provider.clone()
 2379    }
 2380
 2381    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2382        self.semantics_provider = provider;
 2383    }
 2384
 2385    pub fn set_edit_prediction_provider<T>(
 2386        &mut self,
 2387        provider: Option<Entity<T>>,
 2388        window: &mut Window,
 2389        cx: &mut Context<Self>,
 2390    ) where
 2391        T: EditPredictionProvider,
 2392    {
 2393        self.edit_prediction_provider =
 2394            provider.map(|provider| RegisteredInlineCompletionProvider {
 2395                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2396                    if this.focus_handle.is_focused(window) {
 2397                        this.update_visible_inline_completion(window, cx);
 2398                    }
 2399                }),
 2400                provider: Arc::new(provider),
 2401            });
 2402        self.update_edit_prediction_settings(cx);
 2403        self.refresh_inline_completion(false, false, window, cx);
 2404    }
 2405
 2406    pub fn placeholder_text(&self) -> Option<&str> {
 2407        self.placeholder_text.as_deref()
 2408    }
 2409
 2410    pub fn set_placeholder_text(
 2411        &mut self,
 2412        placeholder_text: impl Into<Arc<str>>,
 2413        cx: &mut Context<Self>,
 2414    ) {
 2415        let placeholder_text = Some(placeholder_text.into());
 2416        if self.placeholder_text != placeholder_text {
 2417            self.placeholder_text = placeholder_text;
 2418            cx.notify();
 2419        }
 2420    }
 2421
 2422    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2423        self.cursor_shape = cursor_shape;
 2424
 2425        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2426        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2427
 2428        cx.notify();
 2429    }
 2430
 2431    pub fn set_current_line_highlight(
 2432        &mut self,
 2433        current_line_highlight: Option<CurrentLineHighlight>,
 2434    ) {
 2435        self.current_line_highlight = current_line_highlight;
 2436    }
 2437
 2438    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2439        self.collapse_matches = collapse_matches;
 2440    }
 2441
 2442    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2443        let buffers = self.buffer.read(cx).all_buffers();
 2444        let Some(project) = self.project.as_ref() else {
 2445            return;
 2446        };
 2447        project.update(cx, |project, cx| {
 2448            for buffer in buffers {
 2449                self.registered_buffers
 2450                    .entry(buffer.read(cx).remote_id())
 2451                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2452            }
 2453        })
 2454    }
 2455
 2456    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2457        if self.collapse_matches {
 2458            return range.start..range.start;
 2459        }
 2460        range.clone()
 2461    }
 2462
 2463    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2464        if self.display_map.read(cx).clip_at_line_ends != clip {
 2465            self.display_map
 2466                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2467        }
 2468    }
 2469
 2470    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2471        self.input_enabled = input_enabled;
 2472    }
 2473
 2474    pub fn set_inline_completions_hidden_for_vim_mode(
 2475        &mut self,
 2476        hidden: bool,
 2477        window: &mut Window,
 2478        cx: &mut Context<Self>,
 2479    ) {
 2480        if hidden != self.inline_completions_hidden_for_vim_mode {
 2481            self.inline_completions_hidden_for_vim_mode = hidden;
 2482            if hidden {
 2483                self.update_visible_inline_completion(window, cx);
 2484            } else {
 2485                self.refresh_inline_completion(true, false, window, cx);
 2486            }
 2487        }
 2488    }
 2489
 2490    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2491        self.menu_inline_completions_policy = value;
 2492    }
 2493
 2494    pub fn set_autoindent(&mut self, autoindent: bool) {
 2495        if autoindent {
 2496            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2497        } else {
 2498            self.autoindent_mode = None;
 2499        }
 2500    }
 2501
 2502    pub fn read_only(&self, cx: &App) -> bool {
 2503        self.read_only || self.buffer.read(cx).read_only()
 2504    }
 2505
 2506    pub fn set_read_only(&mut self, read_only: bool) {
 2507        self.read_only = read_only;
 2508    }
 2509
 2510    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2511        self.use_autoclose = autoclose;
 2512    }
 2513
 2514    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2515        self.use_auto_surround = auto_surround;
 2516    }
 2517
 2518    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2519        self.auto_replace_emoji_shortcode = auto_replace;
 2520    }
 2521
 2522    pub fn toggle_edit_predictions(
 2523        &mut self,
 2524        _: &ToggleEditPrediction,
 2525        window: &mut Window,
 2526        cx: &mut Context<Self>,
 2527    ) {
 2528        if self.show_inline_completions_override.is_some() {
 2529            self.set_show_edit_predictions(None, window, cx);
 2530        } else {
 2531            let show_edit_predictions = !self.edit_predictions_enabled();
 2532            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2533        }
 2534    }
 2535
 2536    pub fn set_show_edit_predictions(
 2537        &mut self,
 2538        show_edit_predictions: Option<bool>,
 2539        window: &mut Window,
 2540        cx: &mut Context<Self>,
 2541    ) {
 2542        self.show_inline_completions_override = show_edit_predictions;
 2543        self.update_edit_prediction_settings(cx);
 2544
 2545        if let Some(false) = show_edit_predictions {
 2546            self.discard_inline_completion(false, cx);
 2547        } else {
 2548            self.refresh_inline_completion(false, true, window, cx);
 2549        }
 2550    }
 2551
 2552    fn inline_completions_disabled_in_scope(
 2553        &self,
 2554        buffer: &Entity<Buffer>,
 2555        buffer_position: language::Anchor,
 2556        cx: &App,
 2557    ) -> bool {
 2558        let snapshot = buffer.read(cx).snapshot();
 2559        let settings = snapshot.settings_at(buffer_position, cx);
 2560
 2561        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2562            return false;
 2563        };
 2564
 2565        scope.override_name().map_or(false, |scope_name| {
 2566            settings
 2567                .edit_predictions_disabled_in
 2568                .iter()
 2569                .any(|s| s == scope_name)
 2570        })
 2571    }
 2572
 2573    pub fn set_use_modal_editing(&mut self, to: bool) {
 2574        self.use_modal_editing = to;
 2575    }
 2576
 2577    pub fn use_modal_editing(&self) -> bool {
 2578        self.use_modal_editing
 2579    }
 2580
 2581    fn selections_did_change(
 2582        &mut self,
 2583        local: bool,
 2584        old_cursor_position: &Anchor,
 2585        show_completions: bool,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        window.invalidate_character_coordinates();
 2590
 2591        // Copy selections to primary selection buffer
 2592        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2593        if local {
 2594            let selections = self.selections.all::<usize>(cx);
 2595            let buffer_handle = self.buffer.read(cx).read(cx);
 2596
 2597            let mut text = String::new();
 2598            for (index, selection) in selections.iter().enumerate() {
 2599                let text_for_selection = buffer_handle
 2600                    .text_for_range(selection.start..selection.end)
 2601                    .collect::<String>();
 2602
 2603                text.push_str(&text_for_selection);
 2604                if index != selections.len() - 1 {
 2605                    text.push('\n');
 2606                }
 2607            }
 2608
 2609            if !text.is_empty() {
 2610                cx.write_to_primary(ClipboardItem::new_string(text));
 2611            }
 2612        }
 2613
 2614        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2615            self.buffer.update(cx, |buffer, cx| {
 2616                buffer.set_active_selections(
 2617                    &self.selections.disjoint_anchors(),
 2618                    self.selections.line_mode,
 2619                    self.cursor_shape,
 2620                    cx,
 2621                )
 2622            });
 2623        }
 2624        let display_map = self
 2625            .display_map
 2626            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2627        let buffer = &display_map.buffer_snapshot;
 2628        self.add_selections_state = None;
 2629        self.select_next_state = None;
 2630        self.select_prev_state = None;
 2631        self.select_syntax_node_history.try_clear();
 2632        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2633        self.snippet_stack
 2634            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2635        self.take_rename(false, window, cx);
 2636
 2637        let new_cursor_position = self.selections.newest_anchor().head();
 2638
 2639        self.push_to_nav_history(
 2640            *old_cursor_position,
 2641            Some(new_cursor_position.to_point(buffer)),
 2642            false,
 2643            cx,
 2644        );
 2645
 2646        if local {
 2647            let new_cursor_position = self.selections.newest_anchor().head();
 2648            let mut context_menu = self.context_menu.borrow_mut();
 2649            let completion_menu = match context_menu.as_ref() {
 2650                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2651                _ => {
 2652                    *context_menu = None;
 2653                    None
 2654                }
 2655            };
 2656            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2657                if !self.registered_buffers.contains_key(&buffer_id) {
 2658                    if let Some(project) = self.project.as_ref() {
 2659                        project.update(cx, |project, cx| {
 2660                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2661                                return;
 2662                            };
 2663                            self.registered_buffers.insert(
 2664                                buffer_id,
 2665                                project.register_buffer_with_language_servers(&buffer, cx),
 2666                            );
 2667                        })
 2668                    }
 2669                }
 2670            }
 2671
 2672            if let Some(completion_menu) = completion_menu {
 2673                let cursor_position = new_cursor_position.to_offset(buffer);
 2674                let (word_range, kind) =
 2675                    buffer.surrounding_word(completion_menu.initial_position, true);
 2676                if kind == Some(CharKind::Word)
 2677                    && word_range.to_inclusive().contains(&cursor_position)
 2678                {
 2679                    let mut completion_menu = completion_menu.clone();
 2680                    drop(context_menu);
 2681
 2682                    let query = Self::completion_query(buffer, cursor_position);
 2683                    cx.spawn(async move |this, cx| {
 2684                        completion_menu
 2685                            .filter(query.as_deref(), cx.background_executor().clone())
 2686                            .await;
 2687
 2688                        this.update(cx, |this, cx| {
 2689                            let mut context_menu = this.context_menu.borrow_mut();
 2690                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2691                            else {
 2692                                return;
 2693                            };
 2694
 2695                            if menu.id > completion_menu.id {
 2696                                return;
 2697                            }
 2698
 2699                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2700                            drop(context_menu);
 2701                            cx.notify();
 2702                        })
 2703                    })
 2704                    .detach();
 2705
 2706                    if show_completions {
 2707                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2708                    }
 2709                } else {
 2710                    drop(context_menu);
 2711                    self.hide_context_menu(window, cx);
 2712                }
 2713            } else {
 2714                drop(context_menu);
 2715            }
 2716
 2717            hide_hover(self, cx);
 2718
 2719            if old_cursor_position.to_display_point(&display_map).row()
 2720                != new_cursor_position.to_display_point(&display_map).row()
 2721            {
 2722                self.available_code_actions.take();
 2723            }
 2724            self.refresh_code_actions(window, cx);
 2725            self.refresh_document_highlights(cx);
 2726            self.refresh_selected_text_highlights(false, window, cx);
 2727            refresh_matching_bracket_highlights(self, window, cx);
 2728            self.update_visible_inline_completion(window, cx);
 2729            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2730            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2731            self.inline_blame_popover.take();
 2732            if self.git_blame_inline_enabled {
 2733                self.start_inline_blame_timer(window, cx);
 2734            }
 2735        }
 2736
 2737        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2738        cx.emit(EditorEvent::SelectionsChanged { local });
 2739
 2740        let selections = &self.selections.disjoint;
 2741        if selections.len() == 1 {
 2742            cx.emit(SearchEvent::ActiveMatchChanged)
 2743        }
 2744        if local {
 2745            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2746                let inmemory_selections = selections
 2747                    .iter()
 2748                    .map(|s| {
 2749                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2750                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2751                    })
 2752                    .collect();
 2753                self.update_restoration_data(cx, |data| {
 2754                    data.selections = inmemory_selections;
 2755                });
 2756
 2757                if WorkspaceSettings::get(None, cx).restore_on_startup
 2758                    != RestoreOnStartupBehavior::None
 2759                {
 2760                    if let Some(workspace_id) =
 2761                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2762                    {
 2763                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2764                        let selections = selections.clone();
 2765                        let background_executor = cx.background_executor().clone();
 2766                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2767                        self.serialize_selections = cx.background_spawn(async move {
 2768                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2769                    let db_selections = selections
 2770                        .iter()
 2771                        .map(|selection| {
 2772                            (
 2773                                selection.start.to_offset(&snapshot),
 2774                                selection.end.to_offset(&snapshot),
 2775                            )
 2776                        })
 2777                        .collect();
 2778
 2779                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2780                        .await
 2781                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2782                        .log_err();
 2783                });
 2784                    }
 2785                }
 2786            }
 2787        }
 2788
 2789        cx.notify();
 2790    }
 2791
 2792    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2793        use text::ToOffset as _;
 2794        use text::ToPoint as _;
 2795
 2796        if self.mode.is_minimap()
 2797            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2798        {
 2799            return;
 2800        }
 2801
 2802        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2803            return;
 2804        };
 2805
 2806        let snapshot = singleton.read(cx).snapshot();
 2807        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2808            let display_snapshot = display_map.snapshot(cx);
 2809
 2810            display_snapshot
 2811                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2812                .map(|fold| {
 2813                    fold.range.start.text_anchor.to_point(&snapshot)
 2814                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2815                })
 2816                .collect()
 2817        });
 2818        self.update_restoration_data(cx, |data| {
 2819            data.folds = inmemory_folds;
 2820        });
 2821
 2822        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2823            return;
 2824        };
 2825        let background_executor = cx.background_executor().clone();
 2826        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2827        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2828            display_map
 2829                .snapshot(cx)
 2830                .folds_in_range(0..snapshot.len())
 2831                .map(|fold| {
 2832                    (
 2833                        fold.range.start.text_anchor.to_offset(&snapshot),
 2834                        fold.range.end.text_anchor.to_offset(&snapshot),
 2835                    )
 2836                })
 2837                .collect()
 2838        });
 2839        self.serialize_folds = cx.background_spawn(async move {
 2840            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2841            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2842                .await
 2843                .with_context(|| {
 2844                    format!(
 2845                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2846                    )
 2847                })
 2848                .log_err();
 2849        });
 2850    }
 2851
 2852    pub fn sync_selections(
 2853        &mut self,
 2854        other: Entity<Editor>,
 2855        cx: &mut Context<Self>,
 2856    ) -> gpui::Subscription {
 2857        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2858        self.selections.change_with(cx, |selections| {
 2859            selections.select_anchors(other_selections);
 2860        });
 2861
 2862        let other_subscription =
 2863            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2864                EditorEvent::SelectionsChanged { local: true } => {
 2865                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2866                    if other_selections.is_empty() {
 2867                        return;
 2868                    }
 2869                    this.selections.change_with(cx, |selections| {
 2870                        selections.select_anchors(other_selections);
 2871                    });
 2872                }
 2873                _ => {}
 2874            });
 2875
 2876        let this_subscription =
 2877            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2878                EditorEvent::SelectionsChanged { local: true } => {
 2879                    let these_selections = this.selections.disjoint.to_vec();
 2880                    if these_selections.is_empty() {
 2881                        return;
 2882                    }
 2883                    other.update(cx, |other_editor, cx| {
 2884                        other_editor.selections.change_with(cx, |selections| {
 2885                            selections.select_anchors(these_selections);
 2886                        })
 2887                    });
 2888                }
 2889                _ => {}
 2890            });
 2891
 2892        Subscription::join(other_subscription, this_subscription)
 2893    }
 2894
 2895    pub fn change_selections<R>(
 2896        &mut self,
 2897        autoscroll: Option<Autoscroll>,
 2898        window: &mut Window,
 2899        cx: &mut Context<Self>,
 2900        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2901    ) -> R {
 2902        self.change_selections_inner(autoscroll, true, window, cx, change)
 2903    }
 2904
 2905    fn change_selections_inner<R>(
 2906        &mut self,
 2907        autoscroll: Option<Autoscroll>,
 2908        request_completions: bool,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2912    ) -> R {
 2913        let old_cursor_position = self.selections.newest_anchor().head();
 2914        self.push_to_selection_history();
 2915
 2916        let (changed, result) = self.selections.change_with(cx, change);
 2917
 2918        if changed {
 2919            if let Some(autoscroll) = autoscroll {
 2920                self.request_autoscroll(autoscroll, cx);
 2921            }
 2922            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2923
 2924            if self.should_open_signature_help_automatically(
 2925                &old_cursor_position,
 2926                self.signature_help_state.backspace_pressed(),
 2927                cx,
 2928            ) {
 2929                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2930            }
 2931            self.signature_help_state.set_backspace_pressed(false);
 2932        }
 2933
 2934        result
 2935    }
 2936
 2937    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2938    where
 2939        I: IntoIterator<Item = (Range<S>, T)>,
 2940        S: ToOffset,
 2941        T: Into<Arc<str>>,
 2942    {
 2943        if self.read_only(cx) {
 2944            return;
 2945        }
 2946
 2947        self.buffer
 2948            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2949    }
 2950
 2951    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2952    where
 2953        I: IntoIterator<Item = (Range<S>, T)>,
 2954        S: ToOffset,
 2955        T: Into<Arc<str>>,
 2956    {
 2957        if self.read_only(cx) {
 2958            return;
 2959        }
 2960
 2961        self.buffer.update(cx, |buffer, cx| {
 2962            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2963        });
 2964    }
 2965
 2966    pub fn edit_with_block_indent<I, S, T>(
 2967        &mut self,
 2968        edits: I,
 2969        original_indent_columns: Vec<Option<u32>>,
 2970        cx: &mut Context<Self>,
 2971    ) where
 2972        I: IntoIterator<Item = (Range<S>, T)>,
 2973        S: ToOffset,
 2974        T: Into<Arc<str>>,
 2975    {
 2976        if self.read_only(cx) {
 2977            return;
 2978        }
 2979
 2980        self.buffer.update(cx, |buffer, cx| {
 2981            buffer.edit(
 2982                edits,
 2983                Some(AutoindentMode::Block {
 2984                    original_indent_columns,
 2985                }),
 2986                cx,
 2987            )
 2988        });
 2989    }
 2990
 2991    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2992        self.hide_context_menu(window, cx);
 2993
 2994        match phase {
 2995            SelectPhase::Begin {
 2996                position,
 2997                add,
 2998                click_count,
 2999            } => self.begin_selection(position, add, click_count, window, cx),
 3000            SelectPhase::BeginColumnar {
 3001                position,
 3002                goal_column,
 3003                reset,
 3004            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3005            SelectPhase::Extend {
 3006                position,
 3007                click_count,
 3008            } => self.extend_selection(position, click_count, window, cx),
 3009            SelectPhase::Update {
 3010                position,
 3011                goal_column,
 3012                scroll_delta,
 3013            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3014            SelectPhase::End => self.end_selection(window, cx),
 3015        }
 3016    }
 3017
 3018    fn extend_selection(
 3019        &mut self,
 3020        position: DisplayPoint,
 3021        click_count: usize,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024    ) {
 3025        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3026        let tail = self.selections.newest::<usize>(cx).tail();
 3027        self.begin_selection(position, false, click_count, window, cx);
 3028
 3029        let position = position.to_offset(&display_map, Bias::Left);
 3030        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3031
 3032        let mut pending_selection = self
 3033            .selections
 3034            .pending_anchor()
 3035            .expect("extend_selection not called with pending selection");
 3036        if position >= tail {
 3037            pending_selection.start = tail_anchor;
 3038        } else {
 3039            pending_selection.end = tail_anchor;
 3040            pending_selection.reversed = true;
 3041        }
 3042
 3043        let mut pending_mode = self.selections.pending_mode().unwrap();
 3044        match &mut pending_mode {
 3045            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3046            _ => {}
 3047        }
 3048
 3049        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3050
 3051        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3052            s.set_pending(pending_selection, pending_mode)
 3053        });
 3054    }
 3055
 3056    fn begin_selection(
 3057        &mut self,
 3058        position: DisplayPoint,
 3059        add: bool,
 3060        click_count: usize,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063    ) {
 3064        if !self.focus_handle.is_focused(window) {
 3065            self.last_focused_descendant = None;
 3066            window.focus(&self.focus_handle);
 3067        }
 3068
 3069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3070        let buffer = &display_map.buffer_snapshot;
 3071        let position = display_map.clip_point(position, Bias::Left);
 3072
 3073        let start;
 3074        let end;
 3075        let mode;
 3076        let mut auto_scroll;
 3077        match click_count {
 3078            1 => {
 3079                start = buffer.anchor_before(position.to_point(&display_map));
 3080                end = start;
 3081                mode = SelectMode::Character;
 3082                auto_scroll = true;
 3083            }
 3084            2 => {
 3085                let range = movement::surrounding_word(&display_map, position);
 3086                start = buffer.anchor_before(range.start.to_point(&display_map));
 3087                end = buffer.anchor_before(range.end.to_point(&display_map));
 3088                mode = SelectMode::Word(start..end);
 3089                auto_scroll = true;
 3090            }
 3091            3 => {
 3092                let position = display_map
 3093                    .clip_point(position, Bias::Left)
 3094                    .to_point(&display_map);
 3095                let line_start = display_map.prev_line_boundary(position).0;
 3096                let next_line_start = buffer.clip_point(
 3097                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3098                    Bias::Left,
 3099                );
 3100                start = buffer.anchor_before(line_start);
 3101                end = buffer.anchor_before(next_line_start);
 3102                mode = SelectMode::Line(start..end);
 3103                auto_scroll = true;
 3104            }
 3105            _ => {
 3106                start = buffer.anchor_before(0);
 3107                end = buffer.anchor_before(buffer.len());
 3108                mode = SelectMode::All;
 3109                auto_scroll = false;
 3110            }
 3111        }
 3112        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3113
 3114        let point_to_delete: Option<usize> = {
 3115            let selected_points: Vec<Selection<Point>> =
 3116                self.selections.disjoint_in_range(start..end, cx);
 3117
 3118            if !add || click_count > 1 {
 3119                None
 3120            } else if !selected_points.is_empty() {
 3121                Some(selected_points[0].id)
 3122            } else {
 3123                let clicked_point_already_selected =
 3124                    self.selections.disjoint.iter().find(|selection| {
 3125                        selection.start.to_point(buffer) == start.to_point(buffer)
 3126                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3127                    });
 3128
 3129                clicked_point_already_selected.map(|selection| selection.id)
 3130            }
 3131        };
 3132
 3133        let selections_count = self.selections.count();
 3134
 3135        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3136            if let Some(point_to_delete) = point_to_delete {
 3137                s.delete(point_to_delete);
 3138
 3139                if selections_count == 1 {
 3140                    s.set_pending_anchor_range(start..end, mode);
 3141                }
 3142            } else {
 3143                if !add {
 3144                    s.clear_disjoint();
 3145                }
 3146
 3147                s.set_pending_anchor_range(start..end, mode);
 3148            }
 3149        });
 3150    }
 3151
 3152    fn begin_columnar_selection(
 3153        &mut self,
 3154        position: DisplayPoint,
 3155        goal_column: u32,
 3156        reset: bool,
 3157        window: &mut Window,
 3158        cx: &mut Context<Self>,
 3159    ) {
 3160        if !self.focus_handle.is_focused(window) {
 3161            self.last_focused_descendant = None;
 3162            window.focus(&self.focus_handle);
 3163        }
 3164
 3165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3166
 3167        if reset {
 3168            let pointer_position = display_map
 3169                .buffer_snapshot
 3170                .anchor_before(position.to_point(&display_map));
 3171
 3172            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3173                s.clear_disjoint();
 3174                s.set_pending_anchor_range(
 3175                    pointer_position..pointer_position,
 3176                    SelectMode::Character,
 3177                );
 3178            });
 3179        }
 3180
 3181        let tail = self.selections.newest::<Point>(cx).tail();
 3182        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3183
 3184        if !reset {
 3185            self.select_columns(
 3186                tail.to_display_point(&display_map),
 3187                position,
 3188                goal_column,
 3189                &display_map,
 3190                window,
 3191                cx,
 3192            );
 3193        }
 3194    }
 3195
 3196    fn update_selection(
 3197        &mut self,
 3198        position: DisplayPoint,
 3199        goal_column: u32,
 3200        scroll_delta: gpui::Point<f32>,
 3201        window: &mut Window,
 3202        cx: &mut Context<Self>,
 3203    ) {
 3204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3205
 3206        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3207            let tail = tail.to_display_point(&display_map);
 3208            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3209        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3210            let buffer = self.buffer.read(cx).snapshot(cx);
 3211            let head;
 3212            let tail;
 3213            let mode = self.selections.pending_mode().unwrap();
 3214            match &mode {
 3215                SelectMode::Character => {
 3216                    head = position.to_point(&display_map);
 3217                    tail = pending.tail().to_point(&buffer);
 3218                }
 3219                SelectMode::Word(original_range) => {
 3220                    let original_display_range = original_range.start.to_display_point(&display_map)
 3221                        ..original_range.end.to_display_point(&display_map);
 3222                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3223                        ..original_display_range.end.to_point(&display_map);
 3224                    if movement::is_inside_word(&display_map, position)
 3225                        || original_display_range.contains(&position)
 3226                    {
 3227                        let word_range = movement::surrounding_word(&display_map, position);
 3228                        if word_range.start < original_display_range.start {
 3229                            head = word_range.start.to_point(&display_map);
 3230                        } else {
 3231                            head = word_range.end.to_point(&display_map);
 3232                        }
 3233                    } else {
 3234                        head = position.to_point(&display_map);
 3235                    }
 3236
 3237                    if head <= original_buffer_range.start {
 3238                        tail = original_buffer_range.end;
 3239                    } else {
 3240                        tail = original_buffer_range.start;
 3241                    }
 3242                }
 3243                SelectMode::Line(original_range) => {
 3244                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3245
 3246                    let position = display_map
 3247                        .clip_point(position, Bias::Left)
 3248                        .to_point(&display_map);
 3249                    let line_start = display_map.prev_line_boundary(position).0;
 3250                    let next_line_start = buffer.clip_point(
 3251                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3252                        Bias::Left,
 3253                    );
 3254
 3255                    if line_start < original_range.start {
 3256                        head = line_start
 3257                    } else {
 3258                        head = next_line_start
 3259                    }
 3260
 3261                    if head <= original_range.start {
 3262                        tail = original_range.end;
 3263                    } else {
 3264                        tail = original_range.start;
 3265                    }
 3266                }
 3267                SelectMode::All => {
 3268                    return;
 3269                }
 3270            };
 3271
 3272            if head < tail {
 3273                pending.start = buffer.anchor_before(head);
 3274                pending.end = buffer.anchor_before(tail);
 3275                pending.reversed = true;
 3276            } else {
 3277                pending.start = buffer.anchor_before(tail);
 3278                pending.end = buffer.anchor_before(head);
 3279                pending.reversed = false;
 3280            }
 3281
 3282            self.change_selections(None, window, cx, |s| {
 3283                s.set_pending(pending, mode);
 3284            });
 3285        } else {
 3286            log::error!("update_selection dispatched with no pending selection");
 3287            return;
 3288        }
 3289
 3290        self.apply_scroll_delta(scroll_delta, window, cx);
 3291        cx.notify();
 3292    }
 3293
 3294    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3295        self.columnar_selection_tail.take();
 3296        if self.selections.pending_anchor().is_some() {
 3297            let selections = self.selections.all::<usize>(cx);
 3298            self.change_selections(None, window, cx, |s| {
 3299                s.select(selections);
 3300                s.clear_pending();
 3301            });
 3302        }
 3303    }
 3304
 3305    fn select_columns(
 3306        &mut self,
 3307        tail: DisplayPoint,
 3308        head: DisplayPoint,
 3309        goal_column: u32,
 3310        display_map: &DisplaySnapshot,
 3311        window: &mut Window,
 3312        cx: &mut Context<Self>,
 3313    ) {
 3314        let start_row = cmp::min(tail.row(), head.row());
 3315        let end_row = cmp::max(tail.row(), head.row());
 3316        let start_column = cmp::min(tail.column(), goal_column);
 3317        let end_column = cmp::max(tail.column(), goal_column);
 3318        let reversed = start_column < tail.column();
 3319
 3320        let selection_ranges = (start_row.0..=end_row.0)
 3321            .map(DisplayRow)
 3322            .filter_map(|row| {
 3323                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3324                    let start = display_map
 3325                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3326                        .to_point(display_map);
 3327                    let end = display_map
 3328                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3329                        .to_point(display_map);
 3330                    if reversed {
 3331                        Some(end..start)
 3332                    } else {
 3333                        Some(start..end)
 3334                    }
 3335                } else {
 3336                    None
 3337                }
 3338            })
 3339            .collect::<Vec<_>>();
 3340
 3341        self.change_selections(None, window, cx, |s| {
 3342            s.select_ranges(selection_ranges);
 3343        });
 3344        cx.notify();
 3345    }
 3346
 3347    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3348        self.selections
 3349            .all_adjusted(cx)
 3350            .iter()
 3351            .any(|selection| !selection.is_empty())
 3352    }
 3353
 3354    pub fn has_pending_nonempty_selection(&self) -> bool {
 3355        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3356            Some(Selection { start, end, .. }) => start != end,
 3357            None => false,
 3358        };
 3359
 3360        pending_nonempty_selection
 3361            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3362    }
 3363
 3364    pub fn has_pending_selection(&self) -> bool {
 3365        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3366    }
 3367
 3368    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3369        self.selection_mark_mode = false;
 3370
 3371        if self.clear_expanded_diff_hunks(cx) {
 3372            cx.notify();
 3373            return;
 3374        }
 3375        if self.dismiss_menus_and_popups(true, window, cx) {
 3376            return;
 3377        }
 3378
 3379        if self.mode.is_full()
 3380            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3381        {
 3382            return;
 3383        }
 3384
 3385        cx.propagate();
 3386    }
 3387
 3388    pub fn dismiss_menus_and_popups(
 3389        &mut self,
 3390        is_user_requested: bool,
 3391        window: &mut Window,
 3392        cx: &mut Context<Self>,
 3393    ) -> bool {
 3394        if self.take_rename(false, window, cx).is_some() {
 3395            return true;
 3396        }
 3397
 3398        if hide_hover(self, cx) {
 3399            return true;
 3400        }
 3401
 3402        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3403            return true;
 3404        }
 3405
 3406        if self.hide_context_menu(window, cx).is_some() {
 3407            return true;
 3408        }
 3409
 3410        if self.mouse_context_menu.take().is_some() {
 3411            return true;
 3412        }
 3413
 3414        if is_user_requested && self.discard_inline_completion(true, cx) {
 3415            return true;
 3416        }
 3417
 3418        if self.snippet_stack.pop().is_some() {
 3419            return true;
 3420        }
 3421
 3422        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3423            self.dismiss_diagnostics(cx);
 3424            return true;
 3425        }
 3426
 3427        false
 3428    }
 3429
 3430    fn linked_editing_ranges_for(
 3431        &self,
 3432        selection: Range<text::Anchor>,
 3433        cx: &App,
 3434    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3435        if self.linked_edit_ranges.is_empty() {
 3436            return None;
 3437        }
 3438        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3439            selection.end.buffer_id.and_then(|end_buffer_id| {
 3440                if selection.start.buffer_id != Some(end_buffer_id) {
 3441                    return None;
 3442                }
 3443                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3444                let snapshot = buffer.read(cx).snapshot();
 3445                self.linked_edit_ranges
 3446                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3447                    .map(|ranges| (ranges, snapshot, buffer))
 3448            })?;
 3449        use text::ToOffset as TO;
 3450        // find offset from the start of current range to current cursor position
 3451        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3452
 3453        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3454        let start_difference = start_offset - start_byte_offset;
 3455        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3456        let end_difference = end_offset - start_byte_offset;
 3457        // Current range has associated linked ranges.
 3458        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3459        for range in linked_ranges.iter() {
 3460            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3461            let end_offset = start_offset + end_difference;
 3462            let start_offset = start_offset + start_difference;
 3463            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3464                continue;
 3465            }
 3466            if self.selections.disjoint_anchor_ranges().any(|s| {
 3467                if s.start.buffer_id != selection.start.buffer_id
 3468                    || s.end.buffer_id != selection.end.buffer_id
 3469                {
 3470                    return false;
 3471                }
 3472                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3473                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3474            }) {
 3475                continue;
 3476            }
 3477            let start = buffer_snapshot.anchor_after(start_offset);
 3478            let end = buffer_snapshot.anchor_after(end_offset);
 3479            linked_edits
 3480                .entry(buffer.clone())
 3481                .or_default()
 3482                .push(start..end);
 3483        }
 3484        Some(linked_edits)
 3485    }
 3486
 3487    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3488        let text: Arc<str> = text.into();
 3489
 3490        if self.read_only(cx) {
 3491            return;
 3492        }
 3493
 3494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3495
 3496        let selections = self.selections.all_adjusted(cx);
 3497        let mut bracket_inserted = false;
 3498        let mut edits = Vec::new();
 3499        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3500        let mut new_selections = Vec::with_capacity(selections.len());
 3501        let mut new_autoclose_regions = Vec::new();
 3502        let snapshot = self.buffer.read(cx).read(cx);
 3503        let mut clear_linked_edit_ranges = false;
 3504
 3505        for (selection, autoclose_region) in
 3506            self.selections_with_autoclose_regions(selections, &snapshot)
 3507        {
 3508            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3509                // Determine if the inserted text matches the opening or closing
 3510                // bracket of any of this language's bracket pairs.
 3511                let mut bracket_pair = None;
 3512                let mut is_bracket_pair_start = false;
 3513                let mut is_bracket_pair_end = false;
 3514                if !text.is_empty() {
 3515                    let mut bracket_pair_matching_end = None;
 3516                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3517                    //  and they are removing the character that triggered IME popup.
 3518                    for (pair, enabled) in scope.brackets() {
 3519                        if !pair.close && !pair.surround {
 3520                            continue;
 3521                        }
 3522
 3523                        if enabled && pair.start.ends_with(text.as_ref()) {
 3524                            let prefix_len = pair.start.len() - text.len();
 3525                            let preceding_text_matches_prefix = prefix_len == 0
 3526                                || (selection.start.column >= (prefix_len as u32)
 3527                                    && snapshot.contains_str_at(
 3528                                        Point::new(
 3529                                            selection.start.row,
 3530                                            selection.start.column - (prefix_len as u32),
 3531                                        ),
 3532                                        &pair.start[..prefix_len],
 3533                                    ));
 3534                            if preceding_text_matches_prefix {
 3535                                bracket_pair = Some(pair.clone());
 3536                                is_bracket_pair_start = true;
 3537                                break;
 3538                            }
 3539                        }
 3540                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3541                        {
 3542                            // take first bracket pair matching end, but don't break in case a later bracket
 3543                            // pair matches start
 3544                            bracket_pair_matching_end = Some(pair.clone());
 3545                        }
 3546                    }
 3547                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3548                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3549                        is_bracket_pair_end = true;
 3550                    }
 3551                }
 3552
 3553                if let Some(bracket_pair) = bracket_pair {
 3554                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3555                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3556                    let auto_surround =
 3557                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3558                    if selection.is_empty() {
 3559                        if is_bracket_pair_start {
 3560                            // If the inserted text is a suffix of an opening bracket and the
 3561                            // selection is preceded by the rest of the opening bracket, then
 3562                            // insert the closing bracket.
 3563                            let following_text_allows_autoclose = snapshot
 3564                                .chars_at(selection.start)
 3565                                .next()
 3566                                .map_or(true, |c| scope.should_autoclose_before(c));
 3567
 3568                            let preceding_text_allows_autoclose = selection.start.column == 0
 3569                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3570                                    true,
 3571                                    |c| {
 3572                                        bracket_pair.start != bracket_pair.end
 3573                                            || !snapshot
 3574                                                .char_classifier_at(selection.start)
 3575                                                .is_word(c)
 3576                                    },
 3577                                );
 3578
 3579                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3580                                && bracket_pair.start.len() == 1
 3581                            {
 3582                                let target = bracket_pair.start.chars().next().unwrap();
 3583                                let current_line_count = snapshot
 3584                                    .reversed_chars_at(selection.start)
 3585                                    .take_while(|&c| c != '\n')
 3586                                    .filter(|&c| c == target)
 3587                                    .count();
 3588                                current_line_count % 2 == 1
 3589                            } else {
 3590                                false
 3591                            };
 3592
 3593                            if autoclose
 3594                                && bracket_pair.close
 3595                                && following_text_allows_autoclose
 3596                                && preceding_text_allows_autoclose
 3597                                && !is_closing_quote
 3598                            {
 3599                                let anchor = snapshot.anchor_before(selection.end);
 3600                                new_selections.push((selection.map(|_| anchor), text.len()));
 3601                                new_autoclose_regions.push((
 3602                                    anchor,
 3603                                    text.len(),
 3604                                    selection.id,
 3605                                    bracket_pair.clone(),
 3606                                ));
 3607                                edits.push((
 3608                                    selection.range(),
 3609                                    format!("{}{}", text, bracket_pair.end).into(),
 3610                                ));
 3611                                bracket_inserted = true;
 3612                                continue;
 3613                            }
 3614                        }
 3615
 3616                        if let Some(region) = autoclose_region {
 3617                            // If the selection is followed by an auto-inserted closing bracket,
 3618                            // then don't insert that closing bracket again; just move the selection
 3619                            // past the closing bracket.
 3620                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3621                                && text.as_ref() == region.pair.end.as_str();
 3622                            if should_skip {
 3623                                let anchor = snapshot.anchor_after(selection.end);
 3624                                new_selections
 3625                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3626                                continue;
 3627                            }
 3628                        }
 3629
 3630                        let always_treat_brackets_as_autoclosed = snapshot
 3631                            .language_settings_at(selection.start, cx)
 3632                            .always_treat_brackets_as_autoclosed;
 3633                        if always_treat_brackets_as_autoclosed
 3634                            && is_bracket_pair_end
 3635                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3636                        {
 3637                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3638                            // and the inserted text is a closing bracket and the selection is followed
 3639                            // by the closing bracket then move the selection past the closing bracket.
 3640                            let anchor = snapshot.anchor_after(selection.end);
 3641                            new_selections.push((selection.map(|_| anchor), text.len()));
 3642                            continue;
 3643                        }
 3644                    }
 3645                    // If an opening bracket is 1 character long and is typed while
 3646                    // text is selected, then surround that text with the bracket pair.
 3647                    else if auto_surround
 3648                        && bracket_pair.surround
 3649                        && is_bracket_pair_start
 3650                        && bracket_pair.start.chars().count() == 1
 3651                    {
 3652                        edits.push((selection.start..selection.start, text.clone()));
 3653                        edits.push((
 3654                            selection.end..selection.end,
 3655                            bracket_pair.end.as_str().into(),
 3656                        ));
 3657                        bracket_inserted = true;
 3658                        new_selections.push((
 3659                            Selection {
 3660                                id: selection.id,
 3661                                start: snapshot.anchor_after(selection.start),
 3662                                end: snapshot.anchor_before(selection.end),
 3663                                reversed: selection.reversed,
 3664                                goal: selection.goal,
 3665                            },
 3666                            0,
 3667                        ));
 3668                        continue;
 3669                    }
 3670                }
 3671            }
 3672
 3673            if self.auto_replace_emoji_shortcode
 3674                && selection.is_empty()
 3675                && text.as_ref().ends_with(':')
 3676            {
 3677                if let Some(possible_emoji_short_code) =
 3678                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3679                {
 3680                    if !possible_emoji_short_code.is_empty() {
 3681                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3682                            let emoji_shortcode_start = Point::new(
 3683                                selection.start.row,
 3684                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3685                            );
 3686
 3687                            // Remove shortcode from buffer
 3688                            edits.push((
 3689                                emoji_shortcode_start..selection.start,
 3690                                "".to_string().into(),
 3691                            ));
 3692                            new_selections.push((
 3693                                Selection {
 3694                                    id: selection.id,
 3695                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3696                                    end: snapshot.anchor_before(selection.start),
 3697                                    reversed: selection.reversed,
 3698                                    goal: selection.goal,
 3699                                },
 3700                                0,
 3701                            ));
 3702
 3703                            // Insert emoji
 3704                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3705                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3706                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3707
 3708                            continue;
 3709                        }
 3710                    }
 3711                }
 3712            }
 3713
 3714            // If not handling any auto-close operation, then just replace the selected
 3715            // text with the given input and move the selection to the end of the
 3716            // newly inserted text.
 3717            let anchor = snapshot.anchor_after(selection.end);
 3718            if !self.linked_edit_ranges.is_empty() {
 3719                let start_anchor = snapshot.anchor_before(selection.start);
 3720
 3721                let is_word_char = text.chars().next().map_or(true, |char| {
 3722                    let classifier = snapshot
 3723                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3724                        .ignore_punctuation(true);
 3725                    classifier.is_word(char)
 3726                });
 3727
 3728                if is_word_char {
 3729                    if let Some(ranges) = self
 3730                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3731                    {
 3732                        for (buffer, edits) in ranges {
 3733                            linked_edits
 3734                                .entry(buffer.clone())
 3735                                .or_default()
 3736                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3737                        }
 3738                    }
 3739                } else {
 3740                    clear_linked_edit_ranges = true;
 3741                }
 3742            }
 3743
 3744            new_selections.push((selection.map(|_| anchor), 0));
 3745            edits.push((selection.start..selection.end, text.clone()));
 3746        }
 3747
 3748        drop(snapshot);
 3749
 3750        self.transact(window, cx, |this, window, cx| {
 3751            if clear_linked_edit_ranges {
 3752                this.linked_edit_ranges.clear();
 3753            }
 3754            let initial_buffer_versions =
 3755                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3756
 3757            this.buffer.update(cx, |buffer, cx| {
 3758                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3759            });
 3760            for (buffer, edits) in linked_edits {
 3761                buffer.update(cx, |buffer, cx| {
 3762                    let snapshot = buffer.snapshot();
 3763                    let edits = edits
 3764                        .into_iter()
 3765                        .map(|(range, text)| {
 3766                            use text::ToPoint as TP;
 3767                            let end_point = TP::to_point(&range.end, &snapshot);
 3768                            let start_point = TP::to_point(&range.start, &snapshot);
 3769                            (start_point..end_point, text)
 3770                        })
 3771                        .sorted_by_key(|(range, _)| range.start);
 3772                    buffer.edit(edits, None, cx);
 3773                })
 3774            }
 3775            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3776            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3777            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3778            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3779                .zip(new_selection_deltas)
 3780                .map(|(selection, delta)| Selection {
 3781                    id: selection.id,
 3782                    start: selection.start + delta,
 3783                    end: selection.end + delta,
 3784                    reversed: selection.reversed,
 3785                    goal: SelectionGoal::None,
 3786                })
 3787                .collect::<Vec<_>>();
 3788
 3789            let mut i = 0;
 3790            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3791                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3792                let start = map.buffer_snapshot.anchor_before(position);
 3793                let end = map.buffer_snapshot.anchor_after(position);
 3794                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3795                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3796                        Ordering::Less => i += 1,
 3797                        Ordering::Greater => break,
 3798                        Ordering::Equal => {
 3799                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3800                                Ordering::Less => i += 1,
 3801                                Ordering::Equal => break,
 3802                                Ordering::Greater => break,
 3803                            }
 3804                        }
 3805                    }
 3806                }
 3807                this.autoclose_regions.insert(
 3808                    i,
 3809                    AutocloseRegion {
 3810                        selection_id,
 3811                        range: start..end,
 3812                        pair,
 3813                    },
 3814                );
 3815            }
 3816
 3817            let had_active_inline_completion = this.has_active_inline_completion();
 3818            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3819                s.select(new_selections)
 3820            });
 3821
 3822            if !bracket_inserted {
 3823                if let Some(on_type_format_task) =
 3824                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3825                {
 3826                    on_type_format_task.detach_and_log_err(cx);
 3827                }
 3828            }
 3829
 3830            let editor_settings = EditorSettings::get_global(cx);
 3831            if bracket_inserted
 3832                && (editor_settings.auto_signature_help
 3833                    || editor_settings.show_signature_help_after_edits)
 3834            {
 3835                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3836            }
 3837
 3838            let trigger_in_words =
 3839                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3840            if this.hard_wrap.is_some() {
 3841                let latest: Range<Point> = this.selections.newest(cx).range();
 3842                if latest.is_empty()
 3843                    && this
 3844                        .buffer()
 3845                        .read(cx)
 3846                        .snapshot(cx)
 3847                        .line_len(MultiBufferRow(latest.start.row))
 3848                        == latest.start.column
 3849                {
 3850                    this.rewrap_impl(
 3851                        RewrapOptions {
 3852                            override_language_settings: true,
 3853                            preserve_existing_whitespace: true,
 3854                        },
 3855                        cx,
 3856                    )
 3857                }
 3858            }
 3859            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3860            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3861            this.refresh_inline_completion(true, false, window, cx);
 3862            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3863        });
 3864    }
 3865
 3866    fn find_possible_emoji_shortcode_at_position(
 3867        snapshot: &MultiBufferSnapshot,
 3868        position: Point,
 3869    ) -> Option<String> {
 3870        let mut chars = Vec::new();
 3871        let mut found_colon = false;
 3872        for char in snapshot.reversed_chars_at(position).take(100) {
 3873            // Found a possible emoji shortcode in the middle of the buffer
 3874            if found_colon {
 3875                if char.is_whitespace() {
 3876                    chars.reverse();
 3877                    return Some(chars.iter().collect());
 3878                }
 3879                // If the previous character is not a whitespace, we are in the middle of a word
 3880                // and we only want to complete the shortcode if the word is made up of other emojis
 3881                let mut containing_word = String::new();
 3882                for ch in snapshot
 3883                    .reversed_chars_at(position)
 3884                    .skip(chars.len() + 1)
 3885                    .take(100)
 3886                {
 3887                    if ch.is_whitespace() {
 3888                        break;
 3889                    }
 3890                    containing_word.push(ch);
 3891                }
 3892                let containing_word = containing_word.chars().rev().collect::<String>();
 3893                if util::word_consists_of_emojis(containing_word.as_str()) {
 3894                    chars.reverse();
 3895                    return Some(chars.iter().collect());
 3896                }
 3897            }
 3898
 3899            if char.is_whitespace() || !char.is_ascii() {
 3900                return None;
 3901            }
 3902            if char == ':' {
 3903                found_colon = true;
 3904            } else {
 3905                chars.push(char);
 3906            }
 3907        }
 3908        // Found a possible emoji shortcode at the beginning of the buffer
 3909        chars.reverse();
 3910        Some(chars.iter().collect())
 3911    }
 3912
 3913    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3915        self.transact(window, cx, |this, window, cx| {
 3916            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3917                let selections = this.selections.all::<usize>(cx);
 3918                let multi_buffer = this.buffer.read(cx);
 3919                let buffer = multi_buffer.snapshot(cx);
 3920                selections
 3921                    .iter()
 3922                    .map(|selection| {
 3923                        let start_point = selection.start.to_point(&buffer);
 3924                        let mut existing_indent =
 3925                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3926                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3927                        let start = selection.start;
 3928                        let end = selection.end;
 3929                        let selection_is_empty = start == end;
 3930                        let language_scope = buffer.language_scope_at(start);
 3931                        let (
 3932                            comment_delimiter,
 3933                            doc_delimiter,
 3934                            insert_extra_newline,
 3935                            indent_on_newline,
 3936                            indent_on_extra_newline,
 3937                        ) = if let Some(language) = &language_scope {
 3938                            let mut insert_extra_newline =
 3939                                insert_extra_newline_brackets(&buffer, start..end, language)
 3940                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3941
 3942                            // Comment extension on newline is allowed only for cursor selections
 3943                            let comment_delimiter = maybe!({
 3944                                if !selection_is_empty {
 3945                                    return None;
 3946                                }
 3947
 3948                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3949                                    return None;
 3950                                }
 3951
 3952                                let delimiters = language.line_comment_prefixes();
 3953                                let max_len_of_delimiter =
 3954                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3955                                let (snapshot, range) =
 3956                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3957
 3958                                let num_of_whitespaces = snapshot
 3959                                    .chars_for_range(range.clone())
 3960                                    .take_while(|c| c.is_whitespace())
 3961                                    .count();
 3962                                let comment_candidate = snapshot
 3963                                    .chars_for_range(range)
 3964                                    .skip(num_of_whitespaces)
 3965                                    .take(max_len_of_delimiter)
 3966                                    .collect::<String>();
 3967                                let (delimiter, trimmed_len) = delimiters
 3968                                    .iter()
 3969                                    .filter_map(|delimiter| {
 3970                                        let prefix = delimiter.trim_end();
 3971                                        if comment_candidate.starts_with(prefix) {
 3972                                            Some((delimiter, prefix.len()))
 3973                                        } else {
 3974                                            None
 3975                                        }
 3976                                    })
 3977                                    .max_by_key(|(_, len)| *len)?;
 3978
 3979                                let cursor_is_placed_after_comment_marker =
 3980                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3981                                if cursor_is_placed_after_comment_marker {
 3982                                    Some(delimiter.clone())
 3983                                } else {
 3984                                    None
 3985                                }
 3986                            });
 3987
 3988                            let mut indent_on_newline = IndentSize::spaces(0);
 3989                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3990
 3991                            let doc_delimiter = maybe!({
 3992                                if !selection_is_empty {
 3993                                    return None;
 3994                                }
 3995
 3996                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3997                                    return None;
 3998                                }
 3999
 4000                                let DocumentationConfig {
 4001                                    start: start_tag,
 4002                                    end: end_tag,
 4003                                    prefix: delimiter,
 4004                                    tab_size: len,
 4005                                } = language.documentation()?;
 4006
 4007                                let is_within_block_comment = buffer
 4008                                    .language_scope_at(start_point)
 4009                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4010                                if !is_within_block_comment {
 4011                                    return None;
 4012                                }
 4013
 4014                                let (snapshot, range) =
 4015                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4016
 4017                                let num_of_whitespaces = snapshot
 4018                                    .chars_for_range(range.clone())
 4019                                    .take_while(|c| c.is_whitespace())
 4020                                    .count();
 4021
 4022                                // 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.
 4023                                let column = start_point.column;
 4024                                let cursor_is_after_start_tag = {
 4025                                    let start_tag_len = start_tag.len();
 4026                                    let start_tag_line = snapshot
 4027                                        .chars_for_range(range.clone())
 4028                                        .skip(num_of_whitespaces)
 4029                                        .take(start_tag_len)
 4030                                        .collect::<String>();
 4031                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4032                                        num_of_whitespaces + start_tag_len <= column as usize
 4033                                    } else {
 4034                                        false
 4035                                    }
 4036                                };
 4037
 4038                                let cursor_is_after_delimiter = {
 4039                                    let delimiter_trim = delimiter.trim_end();
 4040                                    let delimiter_line = snapshot
 4041                                        .chars_for_range(range.clone())
 4042                                        .skip(num_of_whitespaces)
 4043                                        .take(delimiter_trim.len())
 4044                                        .collect::<String>();
 4045                                    if delimiter_line.starts_with(delimiter_trim) {
 4046                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4047                                    } else {
 4048                                        false
 4049                                    }
 4050                                };
 4051
 4052                                let cursor_is_before_end_tag_if_exists = {
 4053                                    let mut char_position = 0u32;
 4054                                    let mut end_tag_offset = None;
 4055
 4056                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4057                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4058                                            let chars_before_match =
 4059                                                chunk[..byte_pos].chars().count() as u32;
 4060                                            end_tag_offset =
 4061                                                Some(char_position + chars_before_match);
 4062                                            break 'outer;
 4063                                        }
 4064                                        char_position += chunk.chars().count() as u32;
 4065                                    }
 4066
 4067                                    if let Some(end_tag_offset) = end_tag_offset {
 4068                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4069                                        if cursor_is_after_start_tag {
 4070                                            if cursor_is_before_end_tag {
 4071                                                insert_extra_newline = true;
 4072                                            }
 4073                                            let cursor_is_at_start_of_end_tag =
 4074                                                column == end_tag_offset;
 4075                                            if cursor_is_at_start_of_end_tag {
 4076                                                indent_on_extra_newline.len = (*len).into();
 4077                                            }
 4078                                        }
 4079                                        cursor_is_before_end_tag
 4080                                    } else {
 4081                                        true
 4082                                    }
 4083                                };
 4084
 4085                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4086                                    && cursor_is_before_end_tag_if_exists
 4087                                {
 4088                                    if cursor_is_after_start_tag {
 4089                                        indent_on_newline.len = (*len).into();
 4090                                    }
 4091                                    Some(delimiter.clone())
 4092                                } else {
 4093                                    None
 4094                                }
 4095                            });
 4096
 4097                            (
 4098                                comment_delimiter,
 4099                                doc_delimiter,
 4100                                insert_extra_newline,
 4101                                indent_on_newline,
 4102                                indent_on_extra_newline,
 4103                            )
 4104                        } else {
 4105                            (
 4106                                None,
 4107                                None,
 4108                                false,
 4109                                IndentSize::default(),
 4110                                IndentSize::default(),
 4111                            )
 4112                        };
 4113
 4114                        let prevent_auto_indent = doc_delimiter.is_some();
 4115                        let delimiter = comment_delimiter.or(doc_delimiter);
 4116
 4117                        let capacity_for_delimiter =
 4118                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4119                        let mut new_text = String::with_capacity(
 4120                            1 + capacity_for_delimiter
 4121                                + existing_indent.len as usize
 4122                                + indent_on_newline.len as usize
 4123                                + indent_on_extra_newline.len as usize,
 4124                        );
 4125                        new_text.push('\n');
 4126                        new_text.extend(existing_indent.chars());
 4127                        new_text.extend(indent_on_newline.chars());
 4128
 4129                        if let Some(delimiter) = &delimiter {
 4130                            new_text.push_str(delimiter);
 4131                        }
 4132
 4133                        if insert_extra_newline {
 4134                            new_text.push('\n');
 4135                            new_text.extend(existing_indent.chars());
 4136                            new_text.extend(indent_on_extra_newline.chars());
 4137                        }
 4138
 4139                        let anchor = buffer.anchor_after(end);
 4140                        let new_selection = selection.map(|_| anchor);
 4141                        (
 4142                            ((start..end, new_text), prevent_auto_indent),
 4143                            (insert_extra_newline, new_selection),
 4144                        )
 4145                    })
 4146                    .unzip()
 4147            };
 4148
 4149            let mut auto_indent_edits = Vec::new();
 4150            let mut edits = Vec::new();
 4151            for (edit, prevent_auto_indent) in edits_with_flags {
 4152                if prevent_auto_indent {
 4153                    edits.push(edit);
 4154                } else {
 4155                    auto_indent_edits.push(edit);
 4156                }
 4157            }
 4158            if !edits.is_empty() {
 4159                this.edit(edits, cx);
 4160            }
 4161            if !auto_indent_edits.is_empty() {
 4162                this.edit_with_autoindent(auto_indent_edits, cx);
 4163            }
 4164
 4165            let buffer = this.buffer.read(cx).snapshot(cx);
 4166            let new_selections = selection_info
 4167                .into_iter()
 4168                .map(|(extra_newline_inserted, new_selection)| {
 4169                    let mut cursor = new_selection.end.to_point(&buffer);
 4170                    if extra_newline_inserted {
 4171                        cursor.row -= 1;
 4172                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4173                    }
 4174                    new_selection.map(|_| cursor)
 4175                })
 4176                .collect();
 4177
 4178            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4179                s.select(new_selections)
 4180            });
 4181            this.refresh_inline_completion(true, false, window, cx);
 4182        });
 4183    }
 4184
 4185    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4186        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4187
 4188        let buffer = self.buffer.read(cx);
 4189        let snapshot = buffer.snapshot(cx);
 4190
 4191        let mut edits = Vec::new();
 4192        let mut rows = Vec::new();
 4193
 4194        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4195            let cursor = selection.head();
 4196            let row = cursor.row;
 4197
 4198            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4199
 4200            let newline = "\n".to_string();
 4201            edits.push((start_of_line..start_of_line, newline));
 4202
 4203            rows.push(row + rows_inserted as u32);
 4204        }
 4205
 4206        self.transact(window, cx, |editor, window, cx| {
 4207            editor.edit(edits, cx);
 4208
 4209            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4210                let mut index = 0;
 4211                s.move_cursors_with(|map, _, _| {
 4212                    let row = rows[index];
 4213                    index += 1;
 4214
 4215                    let point = Point::new(row, 0);
 4216                    let boundary = map.next_line_boundary(point).1;
 4217                    let clipped = map.clip_point(boundary, Bias::Left);
 4218
 4219                    (clipped, SelectionGoal::None)
 4220                });
 4221            });
 4222
 4223            let mut indent_edits = Vec::new();
 4224            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4225            for row in rows {
 4226                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4227                for (row, indent) in indents {
 4228                    if indent.len == 0 {
 4229                        continue;
 4230                    }
 4231
 4232                    let text = match indent.kind {
 4233                        IndentKind::Space => " ".repeat(indent.len as usize),
 4234                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4235                    };
 4236                    let point = Point::new(row.0, 0);
 4237                    indent_edits.push((point..point, text));
 4238                }
 4239            }
 4240            editor.edit(indent_edits, cx);
 4241        });
 4242    }
 4243
 4244    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4245        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4246
 4247        let buffer = self.buffer.read(cx);
 4248        let snapshot = buffer.snapshot(cx);
 4249
 4250        let mut edits = Vec::new();
 4251        let mut rows = Vec::new();
 4252        let mut rows_inserted = 0;
 4253
 4254        for selection in self.selections.all_adjusted(cx) {
 4255            let cursor = selection.head();
 4256            let row = cursor.row;
 4257
 4258            let point = Point::new(row + 1, 0);
 4259            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4260
 4261            let newline = "\n".to_string();
 4262            edits.push((start_of_line..start_of_line, newline));
 4263
 4264            rows_inserted += 1;
 4265            rows.push(row + rows_inserted);
 4266        }
 4267
 4268        self.transact(window, cx, |editor, window, cx| {
 4269            editor.edit(edits, cx);
 4270
 4271            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4272                let mut index = 0;
 4273                s.move_cursors_with(|map, _, _| {
 4274                    let row = rows[index];
 4275                    index += 1;
 4276
 4277                    let point = Point::new(row, 0);
 4278                    let boundary = map.next_line_boundary(point).1;
 4279                    let clipped = map.clip_point(boundary, Bias::Left);
 4280
 4281                    (clipped, SelectionGoal::None)
 4282                });
 4283            });
 4284
 4285            let mut indent_edits = Vec::new();
 4286            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4287            for row in rows {
 4288                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4289                for (row, indent) in indents {
 4290                    if indent.len == 0 {
 4291                        continue;
 4292                    }
 4293
 4294                    let text = match indent.kind {
 4295                        IndentKind::Space => " ".repeat(indent.len as usize),
 4296                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4297                    };
 4298                    let point = Point::new(row.0, 0);
 4299                    indent_edits.push((point..point, text));
 4300                }
 4301            }
 4302            editor.edit(indent_edits, cx);
 4303        });
 4304    }
 4305
 4306    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4307        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4308            original_indent_columns: Vec::new(),
 4309        });
 4310        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4311    }
 4312
 4313    fn insert_with_autoindent_mode(
 4314        &mut self,
 4315        text: &str,
 4316        autoindent_mode: Option<AutoindentMode>,
 4317        window: &mut Window,
 4318        cx: &mut Context<Self>,
 4319    ) {
 4320        if self.read_only(cx) {
 4321            return;
 4322        }
 4323
 4324        let text: Arc<str> = text.into();
 4325        self.transact(window, cx, |this, window, cx| {
 4326            let old_selections = this.selections.all_adjusted(cx);
 4327            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4328                let anchors = {
 4329                    let snapshot = buffer.read(cx);
 4330                    old_selections
 4331                        .iter()
 4332                        .map(|s| {
 4333                            let anchor = snapshot.anchor_after(s.head());
 4334                            s.map(|_| anchor)
 4335                        })
 4336                        .collect::<Vec<_>>()
 4337                };
 4338                buffer.edit(
 4339                    old_selections
 4340                        .iter()
 4341                        .map(|s| (s.start..s.end, text.clone())),
 4342                    autoindent_mode,
 4343                    cx,
 4344                );
 4345                anchors
 4346            });
 4347
 4348            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4349                s.select_anchors(selection_anchors);
 4350            });
 4351
 4352            cx.notify();
 4353        });
 4354    }
 4355
 4356    fn trigger_completion_on_input(
 4357        &mut self,
 4358        text: &str,
 4359        trigger_in_words: bool,
 4360        window: &mut Window,
 4361        cx: &mut Context<Self>,
 4362    ) {
 4363        let ignore_completion_provider = self
 4364            .context_menu
 4365            .borrow()
 4366            .as_ref()
 4367            .map(|menu| match menu {
 4368                CodeContextMenu::Completions(completions_menu) => {
 4369                    completions_menu.ignore_completion_provider
 4370                }
 4371                CodeContextMenu::CodeActions(_) => false,
 4372            })
 4373            .unwrap_or(false);
 4374
 4375        if ignore_completion_provider {
 4376            self.show_word_completions(&ShowWordCompletions, window, cx);
 4377        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4378            self.show_completions(
 4379                &ShowCompletions {
 4380                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4381                },
 4382                window,
 4383                cx,
 4384            );
 4385        } else {
 4386            self.hide_context_menu(window, cx);
 4387        }
 4388    }
 4389
 4390    fn is_completion_trigger(
 4391        &self,
 4392        text: &str,
 4393        trigger_in_words: bool,
 4394        cx: &mut Context<Self>,
 4395    ) -> bool {
 4396        let position = self.selections.newest_anchor().head();
 4397        let multibuffer = self.buffer.read(cx);
 4398        let Some(buffer) = position
 4399            .buffer_id
 4400            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4401        else {
 4402            return false;
 4403        };
 4404
 4405        if let Some(completion_provider) = &self.completion_provider {
 4406            completion_provider.is_completion_trigger(
 4407                &buffer,
 4408                position.text_anchor,
 4409                text,
 4410                trigger_in_words,
 4411                cx,
 4412            )
 4413        } else {
 4414            false
 4415        }
 4416    }
 4417
 4418    /// If any empty selections is touching the start of its innermost containing autoclose
 4419    /// region, expand it to select the brackets.
 4420    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4421        let selections = self.selections.all::<usize>(cx);
 4422        let buffer = self.buffer.read(cx).read(cx);
 4423        let new_selections = self
 4424            .selections_with_autoclose_regions(selections, &buffer)
 4425            .map(|(mut selection, region)| {
 4426                if !selection.is_empty() {
 4427                    return selection;
 4428                }
 4429
 4430                if let Some(region) = region {
 4431                    let mut range = region.range.to_offset(&buffer);
 4432                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4433                        range.start -= region.pair.start.len();
 4434                        if buffer.contains_str_at(range.start, &region.pair.start)
 4435                            && buffer.contains_str_at(range.end, &region.pair.end)
 4436                        {
 4437                            range.end += region.pair.end.len();
 4438                            selection.start = range.start;
 4439                            selection.end = range.end;
 4440
 4441                            return selection;
 4442                        }
 4443                    }
 4444                }
 4445
 4446                let always_treat_brackets_as_autoclosed = buffer
 4447                    .language_settings_at(selection.start, cx)
 4448                    .always_treat_brackets_as_autoclosed;
 4449
 4450                if !always_treat_brackets_as_autoclosed {
 4451                    return selection;
 4452                }
 4453
 4454                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4455                    for (pair, enabled) in scope.brackets() {
 4456                        if !enabled || !pair.close {
 4457                            continue;
 4458                        }
 4459
 4460                        if buffer.contains_str_at(selection.start, &pair.end) {
 4461                            let pair_start_len = pair.start.len();
 4462                            if buffer.contains_str_at(
 4463                                selection.start.saturating_sub(pair_start_len),
 4464                                &pair.start,
 4465                            ) {
 4466                                selection.start -= pair_start_len;
 4467                                selection.end += pair.end.len();
 4468
 4469                                return selection;
 4470                            }
 4471                        }
 4472                    }
 4473                }
 4474
 4475                selection
 4476            })
 4477            .collect();
 4478
 4479        drop(buffer);
 4480        self.change_selections(None, window, cx, |selections| {
 4481            selections.select(new_selections)
 4482        });
 4483    }
 4484
 4485    /// Iterate the given selections, and for each one, find the smallest surrounding
 4486    /// autoclose region. This uses the ordering of the selections and the autoclose
 4487    /// regions to avoid repeated comparisons.
 4488    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4489        &'a self,
 4490        selections: impl IntoIterator<Item = Selection<D>>,
 4491        buffer: &'a MultiBufferSnapshot,
 4492    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4493        let mut i = 0;
 4494        let mut regions = self.autoclose_regions.as_slice();
 4495        selections.into_iter().map(move |selection| {
 4496            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4497
 4498            let mut enclosing = None;
 4499            while let Some(pair_state) = regions.get(i) {
 4500                if pair_state.range.end.to_offset(buffer) < range.start {
 4501                    regions = &regions[i + 1..];
 4502                    i = 0;
 4503                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4504                    break;
 4505                } else {
 4506                    if pair_state.selection_id == selection.id {
 4507                        enclosing = Some(pair_state);
 4508                    }
 4509                    i += 1;
 4510                }
 4511            }
 4512
 4513            (selection, enclosing)
 4514        })
 4515    }
 4516
 4517    /// Remove any autoclose regions that no longer contain their selection.
 4518    fn invalidate_autoclose_regions(
 4519        &mut self,
 4520        mut selections: &[Selection<Anchor>],
 4521        buffer: &MultiBufferSnapshot,
 4522    ) {
 4523        self.autoclose_regions.retain(|state| {
 4524            let mut i = 0;
 4525            while let Some(selection) = selections.get(i) {
 4526                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4527                    selections = &selections[1..];
 4528                    continue;
 4529                }
 4530                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4531                    break;
 4532                }
 4533                if selection.id == state.selection_id {
 4534                    return true;
 4535                } else {
 4536                    i += 1;
 4537                }
 4538            }
 4539            false
 4540        });
 4541    }
 4542
 4543    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4544        let offset = position.to_offset(buffer);
 4545        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4546        if offset > word_range.start && kind == Some(CharKind::Word) {
 4547            Some(
 4548                buffer
 4549                    .text_for_range(word_range.start..offset)
 4550                    .collect::<String>(),
 4551            )
 4552        } else {
 4553            None
 4554        }
 4555    }
 4556
 4557    pub fn toggle_inline_values(
 4558        &mut self,
 4559        _: &ToggleInlineValues,
 4560        _: &mut Window,
 4561        cx: &mut Context<Self>,
 4562    ) {
 4563        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4564
 4565        self.refresh_inline_values(cx);
 4566    }
 4567
 4568    pub fn toggle_inlay_hints(
 4569        &mut self,
 4570        _: &ToggleInlayHints,
 4571        _: &mut Window,
 4572        cx: &mut Context<Self>,
 4573    ) {
 4574        self.refresh_inlay_hints(
 4575            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4576            cx,
 4577        );
 4578    }
 4579
 4580    pub fn inlay_hints_enabled(&self) -> bool {
 4581        self.inlay_hint_cache.enabled
 4582    }
 4583
 4584    pub fn inline_values_enabled(&self) -> bool {
 4585        self.inline_value_cache.enabled
 4586    }
 4587
 4588    #[cfg(any(test, feature = "test-support"))]
 4589    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4590        self.display_map
 4591            .read(cx)
 4592            .current_inlays()
 4593            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4594            .cloned()
 4595            .collect()
 4596    }
 4597
 4598    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4599        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4600            return;
 4601        }
 4602
 4603        let reason_description = reason.description();
 4604        let ignore_debounce = matches!(
 4605            reason,
 4606            InlayHintRefreshReason::SettingsChange(_)
 4607                | InlayHintRefreshReason::Toggle(_)
 4608                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4609                | InlayHintRefreshReason::ModifiersChanged(_)
 4610        );
 4611        let (invalidate_cache, required_languages) = match reason {
 4612            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4613                match self.inlay_hint_cache.modifiers_override(enabled) {
 4614                    Some(enabled) => {
 4615                        if enabled {
 4616                            (InvalidationStrategy::RefreshRequested, None)
 4617                        } else {
 4618                            self.splice_inlays(
 4619                                &self
 4620                                    .visible_inlay_hints(cx)
 4621                                    .iter()
 4622                                    .map(|inlay| inlay.id)
 4623                                    .collect::<Vec<InlayId>>(),
 4624                                Vec::new(),
 4625                                cx,
 4626                            );
 4627                            return;
 4628                        }
 4629                    }
 4630                    None => return,
 4631                }
 4632            }
 4633            InlayHintRefreshReason::Toggle(enabled) => {
 4634                if self.inlay_hint_cache.toggle(enabled) {
 4635                    if enabled {
 4636                        (InvalidationStrategy::RefreshRequested, None)
 4637                    } else {
 4638                        self.splice_inlays(
 4639                            &self
 4640                                .visible_inlay_hints(cx)
 4641                                .iter()
 4642                                .map(|inlay| inlay.id)
 4643                                .collect::<Vec<InlayId>>(),
 4644                            Vec::new(),
 4645                            cx,
 4646                        );
 4647                        return;
 4648                    }
 4649                } else {
 4650                    return;
 4651                }
 4652            }
 4653            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4654                match self.inlay_hint_cache.update_settings(
 4655                    &self.buffer,
 4656                    new_settings,
 4657                    self.visible_inlay_hints(cx),
 4658                    cx,
 4659                ) {
 4660                    ControlFlow::Break(Some(InlaySplice {
 4661                        to_remove,
 4662                        to_insert,
 4663                    })) => {
 4664                        self.splice_inlays(&to_remove, to_insert, cx);
 4665                        return;
 4666                    }
 4667                    ControlFlow::Break(None) => return,
 4668                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4669                }
 4670            }
 4671            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4672                if let Some(InlaySplice {
 4673                    to_remove,
 4674                    to_insert,
 4675                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4676                {
 4677                    self.splice_inlays(&to_remove, to_insert, cx);
 4678                }
 4679                self.display_map.update(cx, |display_map, _| {
 4680                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4681                });
 4682                return;
 4683            }
 4684            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4685            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4686                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4687            }
 4688            InlayHintRefreshReason::RefreshRequested => {
 4689                (InvalidationStrategy::RefreshRequested, None)
 4690            }
 4691        };
 4692
 4693        if let Some(InlaySplice {
 4694            to_remove,
 4695            to_insert,
 4696        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4697            reason_description,
 4698            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4699            invalidate_cache,
 4700            ignore_debounce,
 4701            cx,
 4702        ) {
 4703            self.splice_inlays(&to_remove, to_insert, cx);
 4704        }
 4705    }
 4706
 4707    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4708        self.display_map
 4709            .read(cx)
 4710            .current_inlays()
 4711            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4712            .cloned()
 4713            .collect()
 4714    }
 4715
 4716    pub fn excerpts_for_inlay_hints_query(
 4717        &self,
 4718        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4719        cx: &mut Context<Editor>,
 4720    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4721        let Some(project) = self.project.as_ref() else {
 4722            return HashMap::default();
 4723        };
 4724        let project = project.read(cx);
 4725        let multi_buffer = self.buffer().read(cx);
 4726        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4727        let multi_buffer_visible_start = self
 4728            .scroll_manager
 4729            .anchor()
 4730            .anchor
 4731            .to_point(&multi_buffer_snapshot);
 4732        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4733            multi_buffer_visible_start
 4734                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4735            Bias::Left,
 4736        );
 4737        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4738        multi_buffer_snapshot
 4739            .range_to_buffer_ranges(multi_buffer_visible_range)
 4740            .into_iter()
 4741            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4742            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4743                let buffer_file = project::File::from_dyn(buffer.file())?;
 4744                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4745                let worktree_entry = buffer_worktree
 4746                    .read(cx)
 4747                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4748                if worktree_entry.is_ignored {
 4749                    return None;
 4750                }
 4751
 4752                let language = buffer.language()?;
 4753                if let Some(restrict_to_languages) = restrict_to_languages {
 4754                    if !restrict_to_languages.contains(language) {
 4755                        return None;
 4756                    }
 4757                }
 4758                Some((
 4759                    excerpt_id,
 4760                    (
 4761                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4762                        buffer.version().clone(),
 4763                        excerpt_visible_range,
 4764                    ),
 4765                ))
 4766            })
 4767            .collect()
 4768    }
 4769
 4770    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4771        TextLayoutDetails {
 4772            text_system: window.text_system().clone(),
 4773            editor_style: self.style.clone().unwrap(),
 4774            rem_size: window.rem_size(),
 4775            scroll_anchor: self.scroll_manager.anchor(),
 4776            visible_rows: self.visible_line_count(),
 4777            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4778        }
 4779    }
 4780
 4781    pub fn splice_inlays(
 4782        &self,
 4783        to_remove: &[InlayId],
 4784        to_insert: Vec<Inlay>,
 4785        cx: &mut Context<Self>,
 4786    ) {
 4787        self.display_map.update(cx, |display_map, cx| {
 4788            display_map.splice_inlays(to_remove, to_insert, cx)
 4789        });
 4790        cx.notify();
 4791    }
 4792
 4793    fn trigger_on_type_formatting(
 4794        &self,
 4795        input: String,
 4796        window: &mut Window,
 4797        cx: &mut Context<Self>,
 4798    ) -> Option<Task<Result<()>>> {
 4799        if input.len() != 1 {
 4800            return None;
 4801        }
 4802
 4803        let project = self.project.as_ref()?;
 4804        let position = self.selections.newest_anchor().head();
 4805        let (buffer, buffer_position) = self
 4806            .buffer
 4807            .read(cx)
 4808            .text_anchor_for_position(position, cx)?;
 4809
 4810        let settings = language_settings::language_settings(
 4811            buffer
 4812                .read(cx)
 4813                .language_at(buffer_position)
 4814                .map(|l| l.name()),
 4815            buffer.read(cx).file(),
 4816            cx,
 4817        );
 4818        if !settings.use_on_type_format {
 4819            return None;
 4820        }
 4821
 4822        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4823        // hence we do LSP request & edit on host side only — add formats to host's history.
 4824        let push_to_lsp_host_history = true;
 4825        // If this is not the host, append its history with new edits.
 4826        let push_to_client_history = project.read(cx).is_via_collab();
 4827
 4828        let on_type_formatting = project.update(cx, |project, cx| {
 4829            project.on_type_format(
 4830                buffer.clone(),
 4831                buffer_position,
 4832                input,
 4833                push_to_lsp_host_history,
 4834                cx,
 4835            )
 4836        });
 4837        Some(cx.spawn_in(window, async move |editor, cx| {
 4838            if let Some(transaction) = on_type_formatting.await? {
 4839                if push_to_client_history {
 4840                    buffer
 4841                        .update(cx, |buffer, _| {
 4842                            buffer.push_transaction(transaction, Instant::now());
 4843                            buffer.finalize_last_transaction();
 4844                        })
 4845                        .ok();
 4846                }
 4847                editor.update(cx, |editor, cx| {
 4848                    editor.refresh_document_highlights(cx);
 4849                })?;
 4850            }
 4851            Ok(())
 4852        }))
 4853    }
 4854
 4855    pub fn show_word_completions(
 4856        &mut self,
 4857        _: &ShowWordCompletions,
 4858        window: &mut Window,
 4859        cx: &mut Context<Self>,
 4860    ) {
 4861        self.open_completions_menu(true, None, window, cx);
 4862    }
 4863
 4864    pub fn show_completions(
 4865        &mut self,
 4866        options: &ShowCompletions,
 4867        window: &mut Window,
 4868        cx: &mut Context<Self>,
 4869    ) {
 4870        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4871    }
 4872
 4873    fn open_completions_menu(
 4874        &mut self,
 4875        ignore_completion_provider: bool,
 4876        trigger: Option<&str>,
 4877        window: &mut Window,
 4878        cx: &mut Context<Self>,
 4879    ) {
 4880        if self.pending_rename.is_some() {
 4881            return;
 4882        }
 4883        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4884            return;
 4885        }
 4886
 4887        let position = self.selections.newest_anchor().head();
 4888        if position.diff_base_anchor.is_some() {
 4889            return;
 4890        }
 4891        let (buffer, buffer_position) =
 4892            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4893                output
 4894            } else {
 4895                return;
 4896            };
 4897        let buffer_snapshot = buffer.read(cx).snapshot();
 4898        let show_completion_documentation = buffer_snapshot
 4899            .settings_at(buffer_position, cx)
 4900            .show_completion_documentation;
 4901
 4902        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4903
 4904        let trigger_kind = match trigger {
 4905            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4906                CompletionTriggerKind::TRIGGER_CHARACTER
 4907            }
 4908            _ => CompletionTriggerKind::INVOKED,
 4909        };
 4910        let completion_context = CompletionContext {
 4911            trigger_character: trigger.and_then(|trigger| {
 4912                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4913                    Some(String::from(trigger))
 4914                } else {
 4915                    None
 4916                }
 4917            }),
 4918            trigger_kind,
 4919        };
 4920
 4921        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4922        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4923            let word_to_exclude = buffer_snapshot
 4924                .text_for_range(old_range.clone())
 4925                .collect::<String>();
 4926            (
 4927                buffer_snapshot.anchor_before(old_range.start)
 4928                    ..buffer_snapshot.anchor_after(old_range.end),
 4929                Some(word_to_exclude),
 4930            )
 4931        } else {
 4932            (buffer_position..buffer_position, None)
 4933        };
 4934
 4935        let completion_settings = language_settings(
 4936            buffer_snapshot
 4937                .language_at(buffer_position)
 4938                .map(|language| language.name()),
 4939            buffer_snapshot.file(),
 4940            cx,
 4941        )
 4942        .completions;
 4943
 4944        // The document can be large, so stay in reasonable bounds when searching for words,
 4945        // otherwise completion pop-up might be slow to appear.
 4946        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4947        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4948        let min_word_search = buffer_snapshot.clip_point(
 4949            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4950            Bias::Left,
 4951        );
 4952        let max_word_search = buffer_snapshot.clip_point(
 4953            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4954            Bias::Right,
 4955        );
 4956        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4957            ..buffer_snapshot.point_to_offset(max_word_search);
 4958
 4959        let provider = self
 4960            .completion_provider
 4961            .as_ref()
 4962            .filter(|_| !ignore_completion_provider);
 4963        let skip_digits = query
 4964            .as_ref()
 4965            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4966
 4967        let (mut words, provided_completions) = match provider {
 4968            Some(provider) => {
 4969                let completions = provider.completions(
 4970                    position.excerpt_id,
 4971                    &buffer,
 4972                    buffer_position,
 4973                    completion_context,
 4974                    window,
 4975                    cx,
 4976                );
 4977
 4978                let words = match completion_settings.words {
 4979                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4980                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4981                        .background_spawn(async move {
 4982                            buffer_snapshot.words_in_range(WordsQuery {
 4983                                fuzzy_contents: None,
 4984                                range: word_search_range,
 4985                                skip_digits,
 4986                            })
 4987                        }),
 4988                };
 4989
 4990                (words, completions)
 4991            }
 4992            None => (
 4993                cx.background_spawn(async move {
 4994                    buffer_snapshot.words_in_range(WordsQuery {
 4995                        fuzzy_contents: None,
 4996                        range: word_search_range,
 4997                        skip_digits,
 4998                    })
 4999                }),
 5000                Task::ready(Ok(None)),
 5001            ),
 5002        };
 5003
 5004        let sort_completions = provider
 5005            .as_ref()
 5006            .map_or(false, |provider| provider.sort_completions());
 5007
 5008        let filter_completions = provider
 5009            .as_ref()
 5010            .map_or(true, |provider| provider.filter_completions());
 5011
 5012        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5013
 5014        let id = post_inc(&mut self.next_completion_id);
 5015        let task = cx.spawn_in(window, async move |editor, cx| {
 5016            async move {
 5017                editor.update(cx, |this, _| {
 5018                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5019                })?;
 5020
 5021                let mut completions = Vec::new();
 5022                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5023                    completions.extend(provided_completions);
 5024                    if completion_settings.words == WordsCompletionMode::Fallback {
 5025                        words = Task::ready(BTreeMap::default());
 5026                    }
 5027                }
 5028
 5029                let mut words = words.await;
 5030                if let Some(word_to_exclude) = &word_to_exclude {
 5031                    words.remove(word_to_exclude);
 5032                }
 5033                for lsp_completion in &completions {
 5034                    words.remove(&lsp_completion.new_text);
 5035                }
 5036                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5037                    replace_range: old_range.clone(),
 5038                    new_text: word.clone(),
 5039                    label: CodeLabel::plain(word, None),
 5040                    icon_path: None,
 5041                    documentation: None,
 5042                    source: CompletionSource::BufferWord {
 5043                        word_range,
 5044                        resolved: false,
 5045                    },
 5046                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5047                    confirm: None,
 5048                }));
 5049
 5050                let menu = if completions.is_empty() {
 5051                    None
 5052                } else {
 5053                    let mut menu = CompletionsMenu::new(
 5054                        id,
 5055                        sort_completions,
 5056                        show_completion_documentation,
 5057                        ignore_completion_provider,
 5058                        position,
 5059                        buffer.clone(),
 5060                        completions.into(),
 5061                        snippet_sort_order,
 5062                    );
 5063
 5064                    menu.filter(
 5065                        if filter_completions {
 5066                            query.as_deref()
 5067                        } else {
 5068                            None
 5069                        },
 5070                        cx.background_executor().clone(),
 5071                    )
 5072                    .await;
 5073
 5074                    menu.visible().then_some(menu)
 5075                };
 5076
 5077                editor.update_in(cx, |editor, window, cx| {
 5078                    match editor.context_menu.borrow().as_ref() {
 5079                        None => {}
 5080                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5081                            if prev_menu.id > id {
 5082                                return;
 5083                            }
 5084                        }
 5085                        _ => return,
 5086                    }
 5087
 5088                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5089                        let mut menu = menu.unwrap();
 5090                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5091                        crate::hover_popover::hide_hover(editor, cx);
 5092                        *editor.context_menu.borrow_mut() =
 5093                            Some(CodeContextMenu::Completions(menu));
 5094
 5095                        if editor.show_edit_predictions_in_menu() {
 5096                            editor.update_visible_inline_completion(window, cx);
 5097                        } else {
 5098                            editor.discard_inline_completion(false, cx);
 5099                        }
 5100
 5101                        cx.notify();
 5102                    } else if editor.completion_tasks.len() <= 1 {
 5103                        // If there are no more completion tasks and the last menu was
 5104                        // empty, we should hide it.
 5105                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5106                        // If it was already hidden and we don't show inline
 5107                        // completions in the menu, we should also show the
 5108                        // inline-completion when available.
 5109                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5110                            editor.update_visible_inline_completion(window, cx);
 5111                        }
 5112                    }
 5113                })?;
 5114
 5115                anyhow::Ok(())
 5116            }
 5117            .log_err()
 5118            .await
 5119        });
 5120
 5121        self.completion_tasks.push((id, task));
 5122    }
 5123
 5124    #[cfg(feature = "test-support")]
 5125    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5126        let menu = self.context_menu.borrow();
 5127        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5128            let completions = menu.completions.borrow();
 5129            Some(completions.to_vec())
 5130        } else {
 5131            None
 5132        }
 5133    }
 5134
 5135    pub fn confirm_completion(
 5136        &mut self,
 5137        action: &ConfirmCompletion,
 5138        window: &mut Window,
 5139        cx: &mut Context<Self>,
 5140    ) -> Option<Task<Result<()>>> {
 5141        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5142        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5143    }
 5144
 5145    pub fn confirm_completion_insert(
 5146        &mut self,
 5147        _: &ConfirmCompletionInsert,
 5148        window: &mut Window,
 5149        cx: &mut Context<Self>,
 5150    ) -> Option<Task<Result<()>>> {
 5151        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5152        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5153    }
 5154
 5155    pub fn confirm_completion_replace(
 5156        &mut self,
 5157        _: &ConfirmCompletionReplace,
 5158        window: &mut Window,
 5159        cx: &mut Context<Self>,
 5160    ) -> Option<Task<Result<()>>> {
 5161        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5162        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5163    }
 5164
 5165    pub fn compose_completion(
 5166        &mut self,
 5167        action: &ComposeCompletion,
 5168        window: &mut Window,
 5169        cx: &mut Context<Self>,
 5170    ) -> Option<Task<Result<()>>> {
 5171        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5172        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5173    }
 5174
 5175    fn do_completion(
 5176        &mut self,
 5177        item_ix: Option<usize>,
 5178        intent: CompletionIntent,
 5179        window: &mut Window,
 5180        cx: &mut Context<Editor>,
 5181    ) -> Option<Task<Result<()>>> {
 5182        use language::ToOffset as _;
 5183
 5184        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5185        else {
 5186            return None;
 5187        };
 5188
 5189        let candidate_id = {
 5190            let entries = completions_menu.entries.borrow();
 5191            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5192            if self.show_edit_predictions_in_menu() {
 5193                self.discard_inline_completion(true, cx);
 5194            }
 5195            mat.candidate_id
 5196        };
 5197
 5198        let buffer_handle = completions_menu.buffer;
 5199        let completion = completions_menu
 5200            .completions
 5201            .borrow()
 5202            .get(candidate_id)?
 5203            .clone();
 5204        cx.stop_propagation();
 5205
 5206        let snapshot = self.buffer.read(cx).snapshot(cx);
 5207        let newest_anchor = self.selections.newest_anchor();
 5208
 5209        let snippet;
 5210        let new_text;
 5211        if completion.is_snippet() {
 5212            let mut snippet_source = completion.new_text.clone();
 5213            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5214                if scope.prefers_label_for_snippet_in_completion() {
 5215                    if let Some(label) = completion.label() {
 5216                        if matches!(
 5217                            completion.kind(),
 5218                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5219                        ) {
 5220                            snippet_source = label;
 5221                        }
 5222                    }
 5223                }
 5224            }
 5225            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5226            new_text = snippet.as_ref().unwrap().text.clone();
 5227        } else {
 5228            snippet = None;
 5229            new_text = completion.new_text.clone();
 5230        };
 5231
 5232        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5233        let buffer = buffer_handle.read(cx);
 5234        let replace_range_multibuffer = {
 5235            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5236            let multibuffer_anchor = snapshot
 5237                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5238                .unwrap()
 5239                ..snapshot
 5240                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5241                    .unwrap();
 5242            multibuffer_anchor.start.to_offset(&snapshot)
 5243                ..multibuffer_anchor.end.to_offset(&snapshot)
 5244        };
 5245        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5246            return None;
 5247        }
 5248
 5249        let old_text = buffer
 5250            .text_for_range(replace_range.clone())
 5251            .collect::<String>();
 5252        let lookbehind = newest_anchor
 5253            .start
 5254            .text_anchor
 5255            .to_offset(buffer)
 5256            .saturating_sub(replace_range.start);
 5257        let lookahead = replace_range
 5258            .end
 5259            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5260        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5261        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5262
 5263        let selections = self.selections.all::<usize>(cx);
 5264        let mut ranges = Vec::new();
 5265        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5266
 5267        for selection in &selections {
 5268            let range = if selection.id == newest_anchor.id {
 5269                replace_range_multibuffer.clone()
 5270            } else {
 5271                let mut range = selection.range();
 5272
 5273                // if prefix is present, don't duplicate it
 5274                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5275                    range.start = range.start.saturating_sub(lookbehind);
 5276
 5277                    // if suffix is also present, mimic the newest cursor and replace it
 5278                    if selection.id != newest_anchor.id
 5279                        && snapshot.contains_str_at(range.end, suffix)
 5280                    {
 5281                        range.end += lookahead;
 5282                    }
 5283                }
 5284                range
 5285            };
 5286
 5287            ranges.push(range.clone());
 5288
 5289            if !self.linked_edit_ranges.is_empty() {
 5290                let start_anchor = snapshot.anchor_before(range.start);
 5291                let end_anchor = snapshot.anchor_after(range.end);
 5292                if let Some(ranges) = self
 5293                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5294                {
 5295                    for (buffer, edits) in ranges {
 5296                        linked_edits
 5297                            .entry(buffer.clone())
 5298                            .or_default()
 5299                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5300                    }
 5301                }
 5302            }
 5303        }
 5304
 5305        cx.emit(EditorEvent::InputHandled {
 5306            utf16_range_to_replace: None,
 5307            text: new_text.clone().into(),
 5308        });
 5309
 5310        self.transact(window, cx, |this, window, cx| {
 5311            if let Some(mut snippet) = snippet {
 5312                snippet.text = new_text.to_string();
 5313                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5314            } else {
 5315                this.buffer.update(cx, |buffer, cx| {
 5316                    let auto_indent = match completion.insert_text_mode {
 5317                        Some(InsertTextMode::AS_IS) => None,
 5318                        _ => this.autoindent_mode.clone(),
 5319                    };
 5320                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5321                    buffer.edit(edits, auto_indent, cx);
 5322                });
 5323            }
 5324            for (buffer, edits) in linked_edits {
 5325                buffer.update(cx, |buffer, cx| {
 5326                    let snapshot = buffer.snapshot();
 5327                    let edits = edits
 5328                        .into_iter()
 5329                        .map(|(range, text)| {
 5330                            use text::ToPoint as TP;
 5331                            let end_point = TP::to_point(&range.end, &snapshot);
 5332                            let start_point = TP::to_point(&range.start, &snapshot);
 5333                            (start_point..end_point, text)
 5334                        })
 5335                        .sorted_by_key(|(range, _)| range.start);
 5336                    buffer.edit(edits, None, cx);
 5337                })
 5338            }
 5339
 5340            this.refresh_inline_completion(true, false, window, cx);
 5341        });
 5342
 5343        let show_new_completions_on_confirm = completion
 5344            .confirm
 5345            .as_ref()
 5346            .map_or(false, |confirm| confirm(intent, window, cx));
 5347        if show_new_completions_on_confirm {
 5348            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5349        }
 5350
 5351        let provider = self.completion_provider.as_ref()?;
 5352        drop(completion);
 5353        let apply_edits = provider.apply_additional_edits_for_completion(
 5354            buffer_handle,
 5355            completions_menu.completions.clone(),
 5356            candidate_id,
 5357            true,
 5358            cx,
 5359        );
 5360
 5361        let editor_settings = EditorSettings::get_global(cx);
 5362        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5363            // After the code completion is finished, users often want to know what signatures are needed.
 5364            // so we should automatically call signature_help
 5365            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5366        }
 5367
 5368        Some(cx.foreground_executor().spawn(async move {
 5369            apply_edits.await?;
 5370            Ok(())
 5371        }))
 5372    }
 5373
 5374    pub fn toggle_code_actions(
 5375        &mut self,
 5376        action: &ToggleCodeActions,
 5377        window: &mut Window,
 5378        cx: &mut Context<Self>,
 5379    ) {
 5380        let quick_launch = action.quick_launch;
 5381        let mut context_menu = self.context_menu.borrow_mut();
 5382        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5383            if code_actions.deployed_from == action.deployed_from {
 5384                // Toggle if we're selecting the same one
 5385                *context_menu = None;
 5386                cx.notify();
 5387                return;
 5388            } else {
 5389                // Otherwise, clear it and start a new one
 5390                *context_menu = None;
 5391                cx.notify();
 5392            }
 5393        }
 5394        drop(context_menu);
 5395        let snapshot = self.snapshot(window, cx);
 5396        let deployed_from = action.deployed_from.clone();
 5397        let mut task = self.code_actions_task.take();
 5398        let action = action.clone();
 5399        cx.spawn_in(window, async move |editor, cx| {
 5400            while let Some(prev_task) = task {
 5401                prev_task.await.log_err();
 5402                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5403            }
 5404
 5405            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5406                if editor.focus_handle.is_focused(window) {
 5407                    let multibuffer_point = match &action.deployed_from {
 5408                        Some(CodeActionSource::Indicator(row)) => {
 5409                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5410                        }
 5411                        _ => editor.selections.newest::<Point>(cx).head(),
 5412                    };
 5413                    let (buffer, buffer_row) = snapshot
 5414                        .buffer_snapshot
 5415                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5416                        .and_then(|(buffer_snapshot, range)| {
 5417                            editor
 5418                                .buffer
 5419                                .read(cx)
 5420                                .buffer(buffer_snapshot.remote_id())
 5421                                .map(|buffer| (buffer, range.start.row))
 5422                        })?;
 5423                    let (_, code_actions) = editor
 5424                        .available_code_actions
 5425                        .clone()
 5426                        .and_then(|(location, code_actions)| {
 5427                            let snapshot = location.buffer.read(cx).snapshot();
 5428                            let point_range = location.range.to_point(&snapshot);
 5429                            let point_range = point_range.start.row..=point_range.end.row;
 5430                            if point_range.contains(&buffer_row) {
 5431                                Some((location, code_actions))
 5432                            } else {
 5433                                None
 5434                            }
 5435                        })
 5436                        .unzip();
 5437                    let buffer_id = buffer.read(cx).remote_id();
 5438                    let tasks = editor
 5439                        .tasks
 5440                        .get(&(buffer_id, buffer_row))
 5441                        .map(|t| Arc::new(t.to_owned()));
 5442                    if tasks.is_none() && code_actions.is_none() {
 5443                        return None;
 5444                    }
 5445
 5446                    editor.completion_tasks.clear();
 5447                    editor.discard_inline_completion(false, cx);
 5448                    let task_context =
 5449                        tasks
 5450                            .as_ref()
 5451                            .zip(editor.project.clone())
 5452                            .map(|(tasks, project)| {
 5453                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5454                            });
 5455
 5456                    Some(cx.spawn_in(window, async move |editor, cx| {
 5457                        let task_context = match task_context {
 5458                            Some(task_context) => task_context.await,
 5459                            None => None,
 5460                        };
 5461                        let resolved_tasks =
 5462                            tasks
 5463                                .zip(task_context.clone())
 5464                                .map(|(tasks, task_context)| ResolvedTasks {
 5465                                    templates: tasks.resolve(&task_context).collect(),
 5466                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5467                                        multibuffer_point.row,
 5468                                        tasks.column,
 5469                                    )),
 5470                                });
 5471                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5472                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5473                                maybe!({
 5474                                    let project = editor.project.as_ref()?;
 5475                                    let dap_store = project.read(cx).dap_store();
 5476                                    let mut scenarios = vec![];
 5477                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5478                                    let buffer = buffer.read(cx);
 5479                                    let language = buffer.language()?;
 5480                                    let file = buffer.file();
 5481                                    let debug_adapter =
 5482                                        language_settings(language.name().into(), file, cx)
 5483                                            .debuggers
 5484                                            .first()
 5485                                            .map(SharedString::from)
 5486                                            .or_else(|| {
 5487                                                language
 5488                                                    .config()
 5489                                                    .debuggers
 5490                                                    .first()
 5491                                                    .map(SharedString::from)
 5492                                            })?;
 5493
 5494                                    dap_store.update(cx, |dap_store, cx| {
 5495                                        for (_, task) in &resolved_tasks.templates {
 5496                                            if let Some(scenario) = dap_store
 5497                                                .debug_scenario_for_build_task(
 5498                                                    task.original_task().clone(),
 5499                                                    debug_adapter.clone().into(),
 5500                                                    task.display_label().to_owned().into(),
 5501                                                    cx,
 5502                                                )
 5503                                            {
 5504                                                scenarios.push(scenario);
 5505                                            }
 5506                                        }
 5507                                    });
 5508                                    Some(scenarios)
 5509                                })
 5510                                .unwrap_or_default()
 5511                            } else {
 5512                                vec![]
 5513                            }
 5514                        })?;
 5515                        let spawn_straight_away = quick_launch
 5516                            && resolved_tasks
 5517                                .as_ref()
 5518                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5519                            && code_actions
 5520                                .as_ref()
 5521                                .map_or(true, |actions| actions.is_empty())
 5522                            && debug_scenarios.is_empty();
 5523                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5524                            crate::hover_popover::hide_hover(editor, cx);
 5525                            *editor.context_menu.borrow_mut() =
 5526                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5527                                    buffer,
 5528                                    actions: CodeActionContents::new(
 5529                                        resolved_tasks,
 5530                                        code_actions,
 5531                                        debug_scenarios,
 5532                                        task_context.unwrap_or_default(),
 5533                                    ),
 5534                                    selected_item: Default::default(),
 5535                                    scroll_handle: UniformListScrollHandle::default(),
 5536                                    deployed_from,
 5537                                }));
 5538                            if spawn_straight_away {
 5539                                if let Some(task) = editor.confirm_code_action(
 5540                                    &ConfirmCodeAction { item_ix: Some(0) },
 5541                                    window,
 5542                                    cx,
 5543                                ) {
 5544                                    cx.notify();
 5545                                    return task;
 5546                                }
 5547                            }
 5548                            cx.notify();
 5549                            Task::ready(Ok(()))
 5550                        }) {
 5551                            task.await
 5552                        } else {
 5553                            Ok(())
 5554                        }
 5555                    }))
 5556                } else {
 5557                    Some(Task::ready(Ok(())))
 5558                }
 5559            })?;
 5560            if let Some(task) = spawned_test_task {
 5561                task.await?;
 5562            }
 5563
 5564            anyhow::Ok(())
 5565        })
 5566        .detach_and_log_err(cx);
 5567    }
 5568
 5569    pub fn confirm_code_action(
 5570        &mut self,
 5571        action: &ConfirmCodeAction,
 5572        window: &mut Window,
 5573        cx: &mut Context<Self>,
 5574    ) -> Option<Task<Result<()>>> {
 5575        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5576
 5577        let actions_menu =
 5578            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5579                menu
 5580            } else {
 5581                return None;
 5582            };
 5583
 5584        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5585        let action = actions_menu.actions.get(action_ix)?;
 5586        let title = action.label();
 5587        let buffer = actions_menu.buffer;
 5588        let workspace = self.workspace()?;
 5589
 5590        match action {
 5591            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5592                workspace.update(cx, |workspace, cx| {
 5593                    workspace.schedule_resolved_task(
 5594                        task_source_kind,
 5595                        resolved_task,
 5596                        false,
 5597                        window,
 5598                        cx,
 5599                    );
 5600
 5601                    Some(Task::ready(Ok(())))
 5602                })
 5603            }
 5604            CodeActionsItem::CodeAction {
 5605                excerpt_id,
 5606                action,
 5607                provider,
 5608            } => {
 5609                let apply_code_action =
 5610                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5611                let workspace = workspace.downgrade();
 5612                Some(cx.spawn_in(window, async move |editor, cx| {
 5613                    let project_transaction = apply_code_action.await?;
 5614                    Self::open_project_transaction(
 5615                        &editor,
 5616                        workspace,
 5617                        project_transaction,
 5618                        title,
 5619                        cx,
 5620                    )
 5621                    .await
 5622                }))
 5623            }
 5624            CodeActionsItem::DebugScenario(scenario) => {
 5625                let context = actions_menu.actions.context.clone();
 5626
 5627                workspace.update(cx, |workspace, cx| {
 5628                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5629                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5630                });
 5631                Some(Task::ready(Ok(())))
 5632            }
 5633        }
 5634    }
 5635
 5636    pub async fn open_project_transaction(
 5637        this: &WeakEntity<Editor>,
 5638        workspace: WeakEntity<Workspace>,
 5639        transaction: ProjectTransaction,
 5640        title: String,
 5641        cx: &mut AsyncWindowContext,
 5642    ) -> Result<()> {
 5643        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5644        cx.update(|_, cx| {
 5645            entries.sort_unstable_by_key(|(buffer, _)| {
 5646                buffer.read(cx).file().map(|f| f.path().clone())
 5647            });
 5648        })?;
 5649
 5650        // If the project transaction's edits are all contained within this editor, then
 5651        // avoid opening a new editor to display them.
 5652
 5653        if let Some((buffer, transaction)) = entries.first() {
 5654            if entries.len() == 1 {
 5655                let excerpt = this.update(cx, |editor, cx| {
 5656                    editor
 5657                        .buffer()
 5658                        .read(cx)
 5659                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5660                })?;
 5661                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5662                    if excerpted_buffer == *buffer {
 5663                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5664                            let excerpt_range = excerpt_range.to_offset(buffer);
 5665                            buffer
 5666                                .edited_ranges_for_transaction::<usize>(transaction)
 5667                                .all(|range| {
 5668                                    excerpt_range.start <= range.start
 5669                                        && excerpt_range.end >= range.end
 5670                                })
 5671                        })?;
 5672
 5673                        if all_edits_within_excerpt {
 5674                            return Ok(());
 5675                        }
 5676                    }
 5677                }
 5678            }
 5679        } else {
 5680            return Ok(());
 5681        }
 5682
 5683        let mut ranges_to_highlight = Vec::new();
 5684        let excerpt_buffer = cx.new(|cx| {
 5685            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5686            for (buffer_handle, transaction) in &entries {
 5687                let edited_ranges = buffer_handle
 5688                    .read(cx)
 5689                    .edited_ranges_for_transaction::<Point>(transaction)
 5690                    .collect::<Vec<_>>();
 5691                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5692                    PathKey::for_buffer(buffer_handle, cx),
 5693                    buffer_handle.clone(),
 5694                    edited_ranges,
 5695                    DEFAULT_MULTIBUFFER_CONTEXT,
 5696                    cx,
 5697                );
 5698
 5699                ranges_to_highlight.extend(ranges);
 5700            }
 5701            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5702            multibuffer
 5703        })?;
 5704
 5705        workspace.update_in(cx, |workspace, window, cx| {
 5706            let project = workspace.project().clone();
 5707            let editor =
 5708                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5709            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5710            editor.update(cx, |editor, cx| {
 5711                editor.highlight_background::<Self>(
 5712                    &ranges_to_highlight,
 5713                    |theme| theme.editor_highlighted_line_background,
 5714                    cx,
 5715                );
 5716            });
 5717        })?;
 5718
 5719        Ok(())
 5720    }
 5721
 5722    pub fn clear_code_action_providers(&mut self) {
 5723        self.code_action_providers.clear();
 5724        self.available_code_actions.take();
 5725    }
 5726
 5727    pub fn add_code_action_provider(
 5728        &mut self,
 5729        provider: Rc<dyn CodeActionProvider>,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) {
 5733        if self
 5734            .code_action_providers
 5735            .iter()
 5736            .any(|existing_provider| existing_provider.id() == provider.id())
 5737        {
 5738            return;
 5739        }
 5740
 5741        self.code_action_providers.push(provider);
 5742        self.refresh_code_actions(window, cx);
 5743    }
 5744
 5745    pub fn remove_code_action_provider(
 5746        &mut self,
 5747        id: Arc<str>,
 5748        window: &mut Window,
 5749        cx: &mut Context<Self>,
 5750    ) {
 5751        self.code_action_providers
 5752            .retain(|provider| provider.id() != id);
 5753        self.refresh_code_actions(window, cx);
 5754    }
 5755
 5756    pub fn code_actions_enabled(&self, cx: &App) -> bool {
 5757        !self.code_action_providers.is_empty()
 5758            && EditorSettings::get_global(cx).toolbar.code_actions
 5759    }
 5760
 5761    pub fn has_available_code_actions(&self) -> bool {
 5762        self.available_code_actions
 5763            .as_ref()
 5764            .is_some_and(|(_, actions)| !actions.is_empty())
 5765    }
 5766
 5767    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5768        &self.context_menu
 5769    }
 5770
 5771    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5772        let newest_selection = self.selections.newest_anchor().clone();
 5773        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5774        let buffer = self.buffer.read(cx);
 5775        if newest_selection.head().diff_base_anchor.is_some() {
 5776            return None;
 5777        }
 5778        let (start_buffer, start) =
 5779            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5780        let (end_buffer, end) =
 5781            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5782        if start_buffer != end_buffer {
 5783            return None;
 5784        }
 5785
 5786        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5787            cx.background_executor()
 5788                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5789                .await;
 5790
 5791            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5792                let providers = this.code_action_providers.clone();
 5793                let tasks = this
 5794                    .code_action_providers
 5795                    .iter()
 5796                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5797                    .collect::<Vec<_>>();
 5798                (providers, tasks)
 5799            })?;
 5800
 5801            let mut actions = Vec::new();
 5802            for (provider, provider_actions) in
 5803                providers.into_iter().zip(future::join_all(tasks).await)
 5804            {
 5805                if let Some(provider_actions) = provider_actions.log_err() {
 5806                    actions.extend(provider_actions.into_iter().map(|action| {
 5807                        AvailableCodeAction {
 5808                            excerpt_id: newest_selection.start.excerpt_id,
 5809                            action,
 5810                            provider: provider.clone(),
 5811                        }
 5812                    }));
 5813                }
 5814            }
 5815
 5816            this.update(cx, |this, cx| {
 5817                this.available_code_actions = if actions.is_empty() {
 5818                    None
 5819                } else {
 5820                    Some((
 5821                        Location {
 5822                            buffer: start_buffer,
 5823                            range: start..end,
 5824                        },
 5825                        actions.into(),
 5826                    ))
 5827                };
 5828                cx.notify();
 5829            })
 5830        }));
 5831        None
 5832    }
 5833
 5834    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5835        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5836            self.show_git_blame_inline = false;
 5837
 5838            self.show_git_blame_inline_delay_task =
 5839                Some(cx.spawn_in(window, async move |this, cx| {
 5840                    cx.background_executor().timer(delay).await;
 5841
 5842                    this.update(cx, |this, cx| {
 5843                        this.show_git_blame_inline = true;
 5844                        cx.notify();
 5845                    })
 5846                    .log_err();
 5847                }));
 5848        }
 5849    }
 5850
 5851    fn show_blame_popover(
 5852        &mut self,
 5853        blame_entry: &BlameEntry,
 5854        position: gpui::Point<Pixels>,
 5855        cx: &mut Context<Self>,
 5856    ) {
 5857        if let Some(state) = &mut self.inline_blame_popover {
 5858            state.hide_task.take();
 5859            cx.notify();
 5860        } else {
 5861            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5862            let show_task = cx.spawn(async move |editor, cx| {
 5863                cx.background_executor()
 5864                    .timer(std::time::Duration::from_millis(delay))
 5865                    .await;
 5866                editor
 5867                    .update(cx, |editor, cx| {
 5868                        if let Some(state) = &mut editor.inline_blame_popover {
 5869                            state.show_task = None;
 5870                            cx.notify();
 5871                        }
 5872                    })
 5873                    .ok();
 5874            });
 5875            let Some(blame) = self.blame.as_ref() else {
 5876                return;
 5877            };
 5878            let blame = blame.read(cx);
 5879            let details = blame.details_for_entry(&blame_entry);
 5880            let markdown = cx.new(|cx| {
 5881                Markdown::new(
 5882                    details
 5883                        .as_ref()
 5884                        .map(|message| message.message.clone())
 5885                        .unwrap_or_default(),
 5886                    None,
 5887                    None,
 5888                    cx,
 5889                )
 5890            });
 5891            self.inline_blame_popover = Some(InlineBlamePopover {
 5892                position,
 5893                show_task: Some(show_task),
 5894                hide_task: None,
 5895                popover_bounds: None,
 5896                popover_state: InlineBlamePopoverState {
 5897                    scroll_handle: ScrollHandle::new(),
 5898                    commit_message: details,
 5899                    markdown,
 5900                },
 5901            });
 5902        }
 5903    }
 5904
 5905    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5906        if let Some(state) = &mut self.inline_blame_popover {
 5907            if state.show_task.is_some() {
 5908                self.inline_blame_popover.take();
 5909                cx.notify();
 5910            } else {
 5911                let hide_task = cx.spawn(async move |editor, cx| {
 5912                    cx.background_executor()
 5913                        .timer(std::time::Duration::from_millis(100))
 5914                        .await;
 5915                    editor
 5916                        .update(cx, |editor, cx| {
 5917                            editor.inline_blame_popover.take();
 5918                            cx.notify();
 5919                        })
 5920                        .ok();
 5921                });
 5922                state.hide_task = Some(hide_task);
 5923            }
 5924        }
 5925    }
 5926
 5927    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5928        if self.pending_rename.is_some() {
 5929            return None;
 5930        }
 5931
 5932        let provider = self.semantics_provider.clone()?;
 5933        let buffer = self.buffer.read(cx);
 5934        let newest_selection = self.selections.newest_anchor().clone();
 5935        let cursor_position = newest_selection.head();
 5936        let (cursor_buffer, cursor_buffer_position) =
 5937            buffer.text_anchor_for_position(cursor_position, cx)?;
 5938        let (tail_buffer, tail_buffer_position) =
 5939            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5940        if cursor_buffer != tail_buffer {
 5941            return None;
 5942        }
 5943
 5944        let snapshot = cursor_buffer.read(cx).snapshot();
 5945        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5946        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5947        if start_word_range != end_word_range {
 5948            self.document_highlights_task.take();
 5949            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5950            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5951            return None;
 5952        }
 5953
 5954        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5955        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5956            cx.background_executor()
 5957                .timer(Duration::from_millis(debounce))
 5958                .await;
 5959
 5960            let highlights = if let Some(highlights) = cx
 5961                .update(|cx| {
 5962                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5963                })
 5964                .ok()
 5965                .flatten()
 5966            {
 5967                highlights.await.log_err()
 5968            } else {
 5969                None
 5970            };
 5971
 5972            if let Some(highlights) = highlights {
 5973                this.update(cx, |this, cx| {
 5974                    if this.pending_rename.is_some() {
 5975                        return;
 5976                    }
 5977
 5978                    let buffer_id = cursor_position.buffer_id;
 5979                    let buffer = this.buffer.read(cx);
 5980                    if !buffer
 5981                        .text_anchor_for_position(cursor_position, cx)
 5982                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5983                    {
 5984                        return;
 5985                    }
 5986
 5987                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5988                    let mut write_ranges = Vec::new();
 5989                    let mut read_ranges = Vec::new();
 5990                    for highlight in highlights {
 5991                        for (excerpt_id, excerpt_range) in
 5992                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5993                        {
 5994                            let start = highlight
 5995                                .range
 5996                                .start
 5997                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5998                            let end = highlight
 5999                                .range
 6000                                .end
 6001                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6002                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6003                                continue;
 6004                            }
 6005
 6006                            let range = Anchor {
 6007                                buffer_id,
 6008                                excerpt_id,
 6009                                text_anchor: start,
 6010                                diff_base_anchor: None,
 6011                            }..Anchor {
 6012                                buffer_id,
 6013                                excerpt_id,
 6014                                text_anchor: end,
 6015                                diff_base_anchor: None,
 6016                            };
 6017                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6018                                write_ranges.push(range);
 6019                            } else {
 6020                                read_ranges.push(range);
 6021                            }
 6022                        }
 6023                    }
 6024
 6025                    this.highlight_background::<DocumentHighlightRead>(
 6026                        &read_ranges,
 6027                        |theme| theme.editor_document_highlight_read_background,
 6028                        cx,
 6029                    );
 6030                    this.highlight_background::<DocumentHighlightWrite>(
 6031                        &write_ranges,
 6032                        |theme| theme.editor_document_highlight_write_background,
 6033                        cx,
 6034                    );
 6035                    cx.notify();
 6036                })
 6037                .log_err();
 6038            }
 6039        }));
 6040        None
 6041    }
 6042
 6043    fn prepare_highlight_query_from_selection(
 6044        &mut self,
 6045        cx: &mut Context<Editor>,
 6046    ) -> Option<(String, Range<Anchor>)> {
 6047        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6048            return None;
 6049        }
 6050        if !EditorSettings::get_global(cx).selection_highlight {
 6051            return None;
 6052        }
 6053        if self.selections.count() != 1 || self.selections.line_mode {
 6054            return None;
 6055        }
 6056        let selection = self.selections.newest::<Point>(cx);
 6057        if selection.is_empty() || selection.start.row != selection.end.row {
 6058            return None;
 6059        }
 6060        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6061        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6062        let query = multi_buffer_snapshot
 6063            .text_for_range(selection_anchor_range.clone())
 6064            .collect::<String>();
 6065        if query.trim().is_empty() {
 6066            return None;
 6067        }
 6068        Some((query, selection_anchor_range))
 6069    }
 6070
 6071    fn update_selection_occurrence_highlights(
 6072        &mut self,
 6073        query_text: String,
 6074        query_range: Range<Anchor>,
 6075        multi_buffer_range_to_query: Range<Point>,
 6076        use_debounce: bool,
 6077        window: &mut Window,
 6078        cx: &mut Context<Editor>,
 6079    ) -> Task<()> {
 6080        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6081        cx.spawn_in(window, async move |editor, cx| {
 6082            if use_debounce {
 6083                cx.background_executor()
 6084                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6085                    .await;
 6086            }
 6087            let match_task = cx.background_spawn(async move {
 6088                let buffer_ranges = multi_buffer_snapshot
 6089                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6090                    .into_iter()
 6091                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6092                let mut match_ranges = Vec::new();
 6093                let Ok(regex) = project::search::SearchQuery::text(
 6094                    query_text.clone(),
 6095                    false,
 6096                    false,
 6097                    false,
 6098                    Default::default(),
 6099                    Default::default(),
 6100                    false,
 6101                    None,
 6102                ) else {
 6103                    return Vec::default();
 6104                };
 6105                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6106                    match_ranges.extend(
 6107                        regex
 6108                            .search(&buffer_snapshot, Some(search_range.clone()))
 6109                            .await
 6110                            .into_iter()
 6111                            .filter_map(|match_range| {
 6112                                let match_start = buffer_snapshot
 6113                                    .anchor_after(search_range.start + match_range.start);
 6114                                let match_end = buffer_snapshot
 6115                                    .anchor_before(search_range.start + match_range.end);
 6116                                let match_anchor_range = Anchor::range_in_buffer(
 6117                                    excerpt_id,
 6118                                    buffer_snapshot.remote_id(),
 6119                                    match_start..match_end,
 6120                                );
 6121                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6122                            }),
 6123                    );
 6124                }
 6125                match_ranges
 6126            });
 6127            let match_ranges = match_task.await;
 6128            editor
 6129                .update_in(cx, |editor, _, cx| {
 6130                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6131                    if !match_ranges.is_empty() {
 6132                        editor.highlight_background::<SelectedTextHighlight>(
 6133                            &match_ranges,
 6134                            |theme| theme.editor_document_highlight_bracket_background,
 6135                            cx,
 6136                        )
 6137                    }
 6138                })
 6139                .log_err();
 6140        })
 6141    }
 6142
 6143    fn refresh_selected_text_highlights(
 6144        &mut self,
 6145        on_buffer_edit: bool,
 6146        window: &mut Window,
 6147        cx: &mut Context<Editor>,
 6148    ) {
 6149        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6150        else {
 6151            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6152            self.quick_selection_highlight_task.take();
 6153            self.debounced_selection_highlight_task.take();
 6154            return;
 6155        };
 6156        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6157        if on_buffer_edit
 6158            || self
 6159                .quick_selection_highlight_task
 6160                .as_ref()
 6161                .map_or(true, |(prev_anchor_range, _)| {
 6162                    prev_anchor_range != &query_range
 6163                })
 6164        {
 6165            let multi_buffer_visible_start = self
 6166                .scroll_manager
 6167                .anchor()
 6168                .anchor
 6169                .to_point(&multi_buffer_snapshot);
 6170            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6171                multi_buffer_visible_start
 6172                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6173                Bias::Left,
 6174            );
 6175            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6176            self.quick_selection_highlight_task = Some((
 6177                query_range.clone(),
 6178                self.update_selection_occurrence_highlights(
 6179                    query_text.clone(),
 6180                    query_range.clone(),
 6181                    multi_buffer_visible_range,
 6182                    false,
 6183                    window,
 6184                    cx,
 6185                ),
 6186            ));
 6187        }
 6188        if on_buffer_edit
 6189            || self
 6190                .debounced_selection_highlight_task
 6191                .as_ref()
 6192                .map_or(true, |(prev_anchor_range, _)| {
 6193                    prev_anchor_range != &query_range
 6194                })
 6195        {
 6196            let multi_buffer_start = multi_buffer_snapshot
 6197                .anchor_before(0)
 6198                .to_point(&multi_buffer_snapshot);
 6199            let multi_buffer_end = multi_buffer_snapshot
 6200                .anchor_after(multi_buffer_snapshot.len())
 6201                .to_point(&multi_buffer_snapshot);
 6202            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6203            self.debounced_selection_highlight_task = Some((
 6204                query_range.clone(),
 6205                self.update_selection_occurrence_highlights(
 6206                    query_text,
 6207                    query_range,
 6208                    multi_buffer_full_range,
 6209                    true,
 6210                    window,
 6211                    cx,
 6212                ),
 6213            ));
 6214        }
 6215    }
 6216
 6217    pub fn refresh_inline_completion(
 6218        &mut self,
 6219        debounce: bool,
 6220        user_requested: bool,
 6221        window: &mut Window,
 6222        cx: &mut Context<Self>,
 6223    ) -> Option<()> {
 6224        let provider = self.edit_prediction_provider()?;
 6225        let cursor = self.selections.newest_anchor().head();
 6226        let (buffer, cursor_buffer_position) =
 6227            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6228
 6229        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6230            self.discard_inline_completion(false, cx);
 6231            return None;
 6232        }
 6233
 6234        if !user_requested
 6235            && (!self.should_show_edit_predictions()
 6236                || !self.is_focused(window)
 6237                || buffer.read(cx).is_empty())
 6238        {
 6239            self.discard_inline_completion(false, cx);
 6240            return None;
 6241        }
 6242
 6243        self.update_visible_inline_completion(window, cx);
 6244        provider.refresh(
 6245            self.project.clone(),
 6246            buffer,
 6247            cursor_buffer_position,
 6248            debounce,
 6249            cx,
 6250        );
 6251        Some(())
 6252    }
 6253
 6254    fn show_edit_predictions_in_menu(&self) -> bool {
 6255        match self.edit_prediction_settings {
 6256            EditPredictionSettings::Disabled => false,
 6257            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6258        }
 6259    }
 6260
 6261    pub fn edit_predictions_enabled(&self) -> bool {
 6262        match self.edit_prediction_settings {
 6263            EditPredictionSettings::Disabled => false,
 6264            EditPredictionSettings::Enabled { .. } => true,
 6265        }
 6266    }
 6267
 6268    fn edit_prediction_requires_modifier(&self) -> bool {
 6269        match self.edit_prediction_settings {
 6270            EditPredictionSettings::Disabled => false,
 6271            EditPredictionSettings::Enabled {
 6272                preview_requires_modifier,
 6273                ..
 6274            } => preview_requires_modifier,
 6275        }
 6276    }
 6277
 6278    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6279        if self.edit_prediction_provider.is_none() {
 6280            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6281        } else {
 6282            let selection = self.selections.newest_anchor();
 6283            let cursor = selection.head();
 6284
 6285            if let Some((buffer, cursor_buffer_position)) =
 6286                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6287            {
 6288                self.edit_prediction_settings =
 6289                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6290            }
 6291        }
 6292    }
 6293
 6294    fn edit_prediction_settings_at_position(
 6295        &self,
 6296        buffer: &Entity<Buffer>,
 6297        buffer_position: language::Anchor,
 6298        cx: &App,
 6299    ) -> EditPredictionSettings {
 6300        if !self.mode.is_full()
 6301            || !self.show_inline_completions_override.unwrap_or(true)
 6302            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6303        {
 6304            return EditPredictionSettings::Disabled;
 6305        }
 6306
 6307        let buffer = buffer.read(cx);
 6308
 6309        let file = buffer.file();
 6310
 6311        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6312            return EditPredictionSettings::Disabled;
 6313        };
 6314
 6315        let by_provider = matches!(
 6316            self.menu_inline_completions_policy,
 6317            MenuInlineCompletionsPolicy::ByProvider
 6318        );
 6319
 6320        let show_in_menu = by_provider
 6321            && self
 6322                .edit_prediction_provider
 6323                .as_ref()
 6324                .map_or(false, |provider| {
 6325                    provider.provider.show_completions_in_menu()
 6326                });
 6327
 6328        let preview_requires_modifier =
 6329            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6330
 6331        EditPredictionSettings::Enabled {
 6332            show_in_menu,
 6333            preview_requires_modifier,
 6334        }
 6335    }
 6336
 6337    fn should_show_edit_predictions(&self) -> bool {
 6338        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6339    }
 6340
 6341    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6342        matches!(
 6343            self.edit_prediction_preview,
 6344            EditPredictionPreview::Active { .. }
 6345        )
 6346    }
 6347
 6348    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6349        let cursor = self.selections.newest_anchor().head();
 6350        if let Some((buffer, cursor_position)) =
 6351            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6352        {
 6353            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6354        } else {
 6355            false
 6356        }
 6357    }
 6358
 6359    pub fn supports_minimap(&self, cx: &App) -> bool {
 6360        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6361    }
 6362
 6363    fn edit_predictions_enabled_in_buffer(
 6364        &self,
 6365        buffer: &Entity<Buffer>,
 6366        buffer_position: language::Anchor,
 6367        cx: &App,
 6368    ) -> bool {
 6369        maybe!({
 6370            if self.read_only(cx) {
 6371                return Some(false);
 6372            }
 6373            let provider = self.edit_prediction_provider()?;
 6374            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6375                return Some(false);
 6376            }
 6377            let buffer = buffer.read(cx);
 6378            let Some(file) = buffer.file() else {
 6379                return Some(true);
 6380            };
 6381            let settings = all_language_settings(Some(file), cx);
 6382            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6383        })
 6384        .unwrap_or(false)
 6385    }
 6386
 6387    fn cycle_inline_completion(
 6388        &mut self,
 6389        direction: Direction,
 6390        window: &mut Window,
 6391        cx: &mut Context<Self>,
 6392    ) -> Option<()> {
 6393        let provider = self.edit_prediction_provider()?;
 6394        let cursor = self.selections.newest_anchor().head();
 6395        let (buffer, cursor_buffer_position) =
 6396            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6397        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6398            return None;
 6399        }
 6400
 6401        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6402        self.update_visible_inline_completion(window, cx);
 6403
 6404        Some(())
 6405    }
 6406
 6407    pub fn show_inline_completion(
 6408        &mut self,
 6409        _: &ShowEditPrediction,
 6410        window: &mut Window,
 6411        cx: &mut Context<Self>,
 6412    ) {
 6413        if !self.has_active_inline_completion() {
 6414            self.refresh_inline_completion(false, true, window, cx);
 6415            return;
 6416        }
 6417
 6418        self.update_visible_inline_completion(window, cx);
 6419    }
 6420
 6421    pub fn display_cursor_names(
 6422        &mut self,
 6423        _: &DisplayCursorNames,
 6424        window: &mut Window,
 6425        cx: &mut Context<Self>,
 6426    ) {
 6427        self.show_cursor_names(window, cx);
 6428    }
 6429
 6430    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6431        self.show_cursor_names = true;
 6432        cx.notify();
 6433        cx.spawn_in(window, async move |this, cx| {
 6434            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6435            this.update(cx, |this, cx| {
 6436                this.show_cursor_names = false;
 6437                cx.notify()
 6438            })
 6439            .ok()
 6440        })
 6441        .detach();
 6442    }
 6443
 6444    pub fn next_edit_prediction(
 6445        &mut self,
 6446        _: &NextEditPrediction,
 6447        window: &mut Window,
 6448        cx: &mut Context<Self>,
 6449    ) {
 6450        if self.has_active_inline_completion() {
 6451            self.cycle_inline_completion(Direction::Next, window, cx);
 6452        } else {
 6453            let is_copilot_disabled = self
 6454                .refresh_inline_completion(false, true, window, cx)
 6455                .is_none();
 6456            if is_copilot_disabled {
 6457                cx.propagate();
 6458            }
 6459        }
 6460    }
 6461
 6462    pub fn previous_edit_prediction(
 6463        &mut self,
 6464        _: &PreviousEditPrediction,
 6465        window: &mut Window,
 6466        cx: &mut Context<Self>,
 6467    ) {
 6468        if self.has_active_inline_completion() {
 6469            self.cycle_inline_completion(Direction::Prev, window, cx);
 6470        } else {
 6471            let is_copilot_disabled = self
 6472                .refresh_inline_completion(false, true, window, cx)
 6473                .is_none();
 6474            if is_copilot_disabled {
 6475                cx.propagate();
 6476            }
 6477        }
 6478    }
 6479
 6480    pub fn accept_edit_prediction(
 6481        &mut self,
 6482        _: &AcceptEditPrediction,
 6483        window: &mut Window,
 6484        cx: &mut Context<Self>,
 6485    ) {
 6486        if self.show_edit_predictions_in_menu() {
 6487            self.hide_context_menu(window, cx);
 6488        }
 6489
 6490        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6491            return;
 6492        };
 6493
 6494        self.report_inline_completion_event(
 6495            active_inline_completion.completion_id.clone(),
 6496            true,
 6497            cx,
 6498        );
 6499
 6500        match &active_inline_completion.completion {
 6501            InlineCompletion::Move { target, .. } => {
 6502                let target = *target;
 6503
 6504                if let Some(position_map) = &self.last_position_map {
 6505                    if position_map
 6506                        .visible_row_range
 6507                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6508                        || !self.edit_prediction_requires_modifier()
 6509                    {
 6510                        self.unfold_ranges(&[target..target], true, false, cx);
 6511                        // Note that this is also done in vim's handler of the Tab action.
 6512                        self.change_selections(
 6513                            Some(Autoscroll::newest()),
 6514                            window,
 6515                            cx,
 6516                            |selections| {
 6517                                selections.select_anchor_ranges([target..target]);
 6518                            },
 6519                        );
 6520                        self.clear_row_highlights::<EditPredictionPreview>();
 6521
 6522                        self.edit_prediction_preview
 6523                            .set_previous_scroll_position(None);
 6524                    } else {
 6525                        self.edit_prediction_preview
 6526                            .set_previous_scroll_position(Some(
 6527                                position_map.snapshot.scroll_anchor,
 6528                            ));
 6529
 6530                        self.highlight_rows::<EditPredictionPreview>(
 6531                            target..target,
 6532                            cx.theme().colors().editor_highlighted_line_background,
 6533                            RowHighlightOptions {
 6534                                autoscroll: true,
 6535                                ..Default::default()
 6536                            },
 6537                            cx,
 6538                        );
 6539                        self.request_autoscroll(Autoscroll::fit(), cx);
 6540                    }
 6541                }
 6542            }
 6543            InlineCompletion::Edit { edits, .. } => {
 6544                if let Some(provider) = self.edit_prediction_provider() {
 6545                    provider.accept(cx);
 6546                }
 6547
 6548                // Store the transaction ID and selections before applying the edit
 6549                let transaction_id_prev =
 6550                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6551
 6552                let snapshot = self.buffer.read(cx).snapshot(cx);
 6553                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6554
 6555                self.buffer.update(cx, |buffer, cx| {
 6556                    buffer.edit(edits.iter().cloned(), None, cx)
 6557                });
 6558
 6559                self.change_selections(None, window, cx, |s| {
 6560                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6561                });
 6562
 6563                let selections = self.selections.disjoint_anchors();
 6564                if let Some(transaction_id_now) =
 6565                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6566                {
 6567                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6568                    if has_new_transaction {
 6569                        self.selection_history
 6570                            .insert_transaction(transaction_id_now, selections);
 6571                    }
 6572                }
 6573
 6574                self.update_visible_inline_completion(window, cx);
 6575                if self.active_inline_completion.is_none() {
 6576                    self.refresh_inline_completion(true, true, window, cx);
 6577                }
 6578
 6579                cx.notify();
 6580            }
 6581        }
 6582
 6583        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6584    }
 6585
 6586    pub fn accept_partial_inline_completion(
 6587        &mut self,
 6588        _: &AcceptPartialEditPrediction,
 6589        window: &mut Window,
 6590        cx: &mut Context<Self>,
 6591    ) {
 6592        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6593            return;
 6594        };
 6595        if self.selections.count() != 1 {
 6596            return;
 6597        }
 6598
 6599        self.report_inline_completion_event(
 6600            active_inline_completion.completion_id.clone(),
 6601            true,
 6602            cx,
 6603        );
 6604
 6605        match &active_inline_completion.completion {
 6606            InlineCompletion::Move { target, .. } => {
 6607                let target = *target;
 6608                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6609                    selections.select_anchor_ranges([target..target]);
 6610                });
 6611            }
 6612            InlineCompletion::Edit { edits, .. } => {
 6613                // Find an insertion that starts at the cursor position.
 6614                let snapshot = self.buffer.read(cx).snapshot(cx);
 6615                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6616                let insertion = edits.iter().find_map(|(range, text)| {
 6617                    let range = range.to_offset(&snapshot);
 6618                    if range.is_empty() && range.start == cursor_offset {
 6619                        Some(text)
 6620                    } else {
 6621                        None
 6622                    }
 6623                });
 6624
 6625                if let Some(text) = insertion {
 6626                    let mut partial_completion = text
 6627                        .chars()
 6628                        .by_ref()
 6629                        .take_while(|c| c.is_alphabetic())
 6630                        .collect::<String>();
 6631                    if partial_completion.is_empty() {
 6632                        partial_completion = text
 6633                            .chars()
 6634                            .by_ref()
 6635                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6636                            .collect::<String>();
 6637                    }
 6638
 6639                    cx.emit(EditorEvent::InputHandled {
 6640                        utf16_range_to_replace: None,
 6641                        text: partial_completion.clone().into(),
 6642                    });
 6643
 6644                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6645
 6646                    self.refresh_inline_completion(true, true, window, cx);
 6647                    cx.notify();
 6648                } else {
 6649                    self.accept_edit_prediction(&Default::default(), window, cx);
 6650                }
 6651            }
 6652        }
 6653    }
 6654
 6655    fn discard_inline_completion(
 6656        &mut self,
 6657        should_report_inline_completion_event: bool,
 6658        cx: &mut Context<Self>,
 6659    ) -> bool {
 6660        if should_report_inline_completion_event {
 6661            let completion_id = self
 6662                .active_inline_completion
 6663                .as_ref()
 6664                .and_then(|active_completion| active_completion.completion_id.clone());
 6665
 6666            self.report_inline_completion_event(completion_id, false, cx);
 6667        }
 6668
 6669        if let Some(provider) = self.edit_prediction_provider() {
 6670            provider.discard(cx);
 6671        }
 6672
 6673        self.take_active_inline_completion(cx)
 6674    }
 6675
 6676    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6677        let Some(provider) = self.edit_prediction_provider() else {
 6678            return;
 6679        };
 6680
 6681        let Some((_, buffer, _)) = self
 6682            .buffer
 6683            .read(cx)
 6684            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6685        else {
 6686            return;
 6687        };
 6688
 6689        let extension = buffer
 6690            .read(cx)
 6691            .file()
 6692            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6693
 6694        let event_type = match accepted {
 6695            true => "Edit Prediction Accepted",
 6696            false => "Edit Prediction Discarded",
 6697        };
 6698        telemetry::event!(
 6699            event_type,
 6700            provider = provider.name(),
 6701            prediction_id = id,
 6702            suggestion_accepted = accepted,
 6703            file_extension = extension,
 6704        );
 6705    }
 6706
 6707    pub fn has_active_inline_completion(&self) -> bool {
 6708        self.active_inline_completion.is_some()
 6709    }
 6710
 6711    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6712        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6713            return false;
 6714        };
 6715
 6716        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6717        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6718        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6719        true
 6720    }
 6721
 6722    /// Returns true when we're displaying the edit prediction popover below the cursor
 6723    /// like we are not previewing and the LSP autocomplete menu is visible
 6724    /// or we are in `when_holding_modifier` mode.
 6725    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6726        if self.edit_prediction_preview_is_active()
 6727            || !self.show_edit_predictions_in_menu()
 6728            || !self.edit_predictions_enabled()
 6729        {
 6730            return false;
 6731        }
 6732
 6733        if self.has_visible_completions_menu() {
 6734            return true;
 6735        }
 6736
 6737        has_completion && self.edit_prediction_requires_modifier()
 6738    }
 6739
 6740    fn handle_modifiers_changed(
 6741        &mut self,
 6742        modifiers: Modifiers,
 6743        position_map: &PositionMap,
 6744        window: &mut Window,
 6745        cx: &mut Context<Self>,
 6746    ) {
 6747        if self.show_edit_predictions_in_menu() {
 6748            self.update_edit_prediction_preview(&modifiers, window, cx);
 6749        }
 6750
 6751        self.update_selection_mode(&modifiers, position_map, window, cx);
 6752
 6753        let mouse_position = window.mouse_position();
 6754        if !position_map.text_hitbox.is_hovered(window) {
 6755            return;
 6756        }
 6757
 6758        self.update_hovered_link(
 6759            position_map.point_for_position(mouse_position),
 6760            &position_map.snapshot,
 6761            modifiers,
 6762            window,
 6763            cx,
 6764        )
 6765    }
 6766
 6767    fn update_selection_mode(
 6768        &mut self,
 6769        modifiers: &Modifiers,
 6770        position_map: &PositionMap,
 6771        window: &mut Window,
 6772        cx: &mut Context<Self>,
 6773    ) {
 6774        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6775            return;
 6776        }
 6777
 6778        let mouse_position = window.mouse_position();
 6779        let point_for_position = position_map.point_for_position(mouse_position);
 6780        let position = point_for_position.previous_valid;
 6781
 6782        self.select(
 6783            SelectPhase::BeginColumnar {
 6784                position,
 6785                reset: false,
 6786                goal_column: point_for_position.exact_unclipped.column(),
 6787            },
 6788            window,
 6789            cx,
 6790        );
 6791    }
 6792
 6793    fn update_edit_prediction_preview(
 6794        &mut self,
 6795        modifiers: &Modifiers,
 6796        window: &mut Window,
 6797        cx: &mut Context<Self>,
 6798    ) {
 6799        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6800        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6801            return;
 6802        };
 6803
 6804        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6805            if matches!(
 6806                self.edit_prediction_preview,
 6807                EditPredictionPreview::Inactive { .. }
 6808            ) {
 6809                self.edit_prediction_preview = EditPredictionPreview::Active {
 6810                    previous_scroll_position: None,
 6811                    since: Instant::now(),
 6812                };
 6813
 6814                self.update_visible_inline_completion(window, cx);
 6815                cx.notify();
 6816            }
 6817        } else if let EditPredictionPreview::Active {
 6818            previous_scroll_position,
 6819            since,
 6820        } = self.edit_prediction_preview
 6821        {
 6822            if let (Some(previous_scroll_position), Some(position_map)) =
 6823                (previous_scroll_position, self.last_position_map.as_ref())
 6824            {
 6825                self.set_scroll_position(
 6826                    previous_scroll_position
 6827                        .scroll_position(&position_map.snapshot.display_snapshot),
 6828                    window,
 6829                    cx,
 6830                );
 6831            }
 6832
 6833            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6834                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6835            };
 6836            self.clear_row_highlights::<EditPredictionPreview>();
 6837            self.update_visible_inline_completion(window, cx);
 6838            cx.notify();
 6839        }
 6840    }
 6841
 6842    fn update_visible_inline_completion(
 6843        &mut self,
 6844        _window: &mut Window,
 6845        cx: &mut Context<Self>,
 6846    ) -> Option<()> {
 6847        let selection = self.selections.newest_anchor();
 6848        let cursor = selection.head();
 6849        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6850        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6851        let excerpt_id = cursor.excerpt_id;
 6852
 6853        let show_in_menu = self.show_edit_predictions_in_menu();
 6854        let completions_menu_has_precedence = !show_in_menu
 6855            && (self.context_menu.borrow().is_some()
 6856                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6857
 6858        if completions_menu_has_precedence
 6859            || !offset_selection.is_empty()
 6860            || self
 6861                .active_inline_completion
 6862                .as_ref()
 6863                .map_or(false, |completion| {
 6864                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6865                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6866                    !invalidation_range.contains(&offset_selection.head())
 6867                })
 6868        {
 6869            self.discard_inline_completion(false, cx);
 6870            return None;
 6871        }
 6872
 6873        self.take_active_inline_completion(cx);
 6874        let Some(provider) = self.edit_prediction_provider() else {
 6875            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6876            return None;
 6877        };
 6878
 6879        let (buffer, cursor_buffer_position) =
 6880            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6881
 6882        self.edit_prediction_settings =
 6883            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6884
 6885        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6886
 6887        if self.edit_prediction_indent_conflict {
 6888            let cursor_point = cursor.to_point(&multibuffer);
 6889
 6890            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6891
 6892            if let Some((_, indent)) = indents.iter().next() {
 6893                if indent.len == cursor_point.column {
 6894                    self.edit_prediction_indent_conflict = false;
 6895                }
 6896            }
 6897        }
 6898
 6899        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6900        let edits = inline_completion
 6901            .edits
 6902            .into_iter()
 6903            .flat_map(|(range, new_text)| {
 6904                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6905                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6906                Some((start..end, new_text))
 6907            })
 6908            .collect::<Vec<_>>();
 6909        if edits.is_empty() {
 6910            return None;
 6911        }
 6912
 6913        let first_edit_start = edits.first().unwrap().0.start;
 6914        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6915        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6916
 6917        let last_edit_end = edits.last().unwrap().0.end;
 6918        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6919        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6920
 6921        let cursor_row = cursor.to_point(&multibuffer).row;
 6922
 6923        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6924
 6925        let mut inlay_ids = Vec::new();
 6926        let invalidation_row_range;
 6927        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6928            Some(cursor_row..edit_end_row)
 6929        } else if cursor_row > edit_end_row {
 6930            Some(edit_start_row..cursor_row)
 6931        } else {
 6932            None
 6933        };
 6934        let is_move =
 6935            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6936        let completion = if is_move {
 6937            invalidation_row_range =
 6938                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6939            let target = first_edit_start;
 6940            InlineCompletion::Move { target, snapshot }
 6941        } else {
 6942            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6943                && !self.inline_completions_hidden_for_vim_mode;
 6944
 6945            if show_completions_in_buffer {
 6946                if edits
 6947                    .iter()
 6948                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6949                {
 6950                    let mut inlays = Vec::new();
 6951                    for (range, new_text) in &edits {
 6952                        let inlay = Inlay::inline_completion(
 6953                            post_inc(&mut self.next_inlay_id),
 6954                            range.start,
 6955                            new_text.as_str(),
 6956                        );
 6957                        inlay_ids.push(inlay.id);
 6958                        inlays.push(inlay);
 6959                    }
 6960
 6961                    self.splice_inlays(&[], inlays, cx);
 6962                } else {
 6963                    let background_color = cx.theme().status().deleted_background;
 6964                    self.highlight_text::<InlineCompletionHighlight>(
 6965                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6966                        HighlightStyle {
 6967                            background_color: Some(background_color),
 6968                            ..Default::default()
 6969                        },
 6970                        cx,
 6971                    );
 6972                }
 6973            }
 6974
 6975            invalidation_row_range = edit_start_row..edit_end_row;
 6976
 6977            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6978                if provider.show_tab_accept_marker() {
 6979                    EditDisplayMode::TabAccept
 6980                } else {
 6981                    EditDisplayMode::Inline
 6982                }
 6983            } else {
 6984                EditDisplayMode::DiffPopover
 6985            };
 6986
 6987            InlineCompletion::Edit {
 6988                edits,
 6989                edit_preview: inline_completion.edit_preview,
 6990                display_mode,
 6991                snapshot,
 6992            }
 6993        };
 6994
 6995        let invalidation_range = multibuffer
 6996            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6997            ..multibuffer.anchor_after(Point::new(
 6998                invalidation_row_range.end,
 6999                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7000            ));
 7001
 7002        self.stale_inline_completion_in_menu = None;
 7003        self.active_inline_completion = Some(InlineCompletionState {
 7004            inlay_ids,
 7005            completion,
 7006            completion_id: inline_completion.id,
 7007            invalidation_range,
 7008        });
 7009
 7010        cx.notify();
 7011
 7012        Some(())
 7013    }
 7014
 7015    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7016        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7017    }
 7018
 7019    fn clear_tasks(&mut self) {
 7020        self.tasks.clear()
 7021    }
 7022
 7023    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7024        if self.tasks.insert(key, value).is_some() {
 7025            // This case should hopefully be rare, but just in case...
 7026            log::error!(
 7027                "multiple different run targets found on a single line, only the last target will be rendered"
 7028            )
 7029        }
 7030    }
 7031
 7032    /// Get all display points of breakpoints that will be rendered within editor
 7033    ///
 7034    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7035    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7036    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7037    fn active_breakpoints(
 7038        &self,
 7039        range: Range<DisplayRow>,
 7040        window: &mut Window,
 7041        cx: &mut Context<Self>,
 7042    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7043        let mut breakpoint_display_points = HashMap::default();
 7044
 7045        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7046            return breakpoint_display_points;
 7047        };
 7048
 7049        let snapshot = self.snapshot(window, cx);
 7050
 7051        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7052        let Some(project) = self.project.as_ref() else {
 7053            return breakpoint_display_points;
 7054        };
 7055
 7056        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7057            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7058
 7059        for (buffer_snapshot, range, excerpt_id) in
 7060            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7061        {
 7062            let Some(buffer) = project.read_with(cx, |this, cx| {
 7063                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7064            }) else {
 7065                continue;
 7066            };
 7067            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7068                &buffer,
 7069                Some(
 7070                    buffer_snapshot.anchor_before(range.start)
 7071                        ..buffer_snapshot.anchor_after(range.end),
 7072                ),
 7073                buffer_snapshot,
 7074                cx,
 7075            );
 7076            for (breakpoint, state) in breakpoints {
 7077                let multi_buffer_anchor =
 7078                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7079                let position = multi_buffer_anchor
 7080                    .to_point(&multi_buffer_snapshot)
 7081                    .to_display_point(&snapshot);
 7082
 7083                breakpoint_display_points.insert(
 7084                    position.row(),
 7085                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7086                );
 7087            }
 7088        }
 7089
 7090        breakpoint_display_points
 7091    }
 7092
 7093    fn breakpoint_context_menu(
 7094        &self,
 7095        anchor: Anchor,
 7096        window: &mut Window,
 7097        cx: &mut Context<Self>,
 7098    ) -> Entity<ui::ContextMenu> {
 7099        let weak_editor = cx.weak_entity();
 7100        let focus_handle = self.focus_handle(cx);
 7101
 7102        let row = self
 7103            .buffer
 7104            .read(cx)
 7105            .snapshot(cx)
 7106            .summary_for_anchor::<Point>(&anchor)
 7107            .row;
 7108
 7109        let breakpoint = self
 7110            .breakpoint_at_row(row, window, cx)
 7111            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7112
 7113        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7114            "Edit Log Breakpoint"
 7115        } else {
 7116            "Set Log Breakpoint"
 7117        };
 7118
 7119        let condition_breakpoint_msg = if breakpoint
 7120            .as_ref()
 7121            .is_some_and(|bp| bp.1.condition.is_some())
 7122        {
 7123            "Edit Condition Breakpoint"
 7124        } else {
 7125            "Set Condition Breakpoint"
 7126        };
 7127
 7128        let hit_condition_breakpoint_msg = if breakpoint
 7129            .as_ref()
 7130            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7131        {
 7132            "Edit Hit Condition Breakpoint"
 7133        } else {
 7134            "Set Hit Condition Breakpoint"
 7135        };
 7136
 7137        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7138            "Unset Breakpoint"
 7139        } else {
 7140            "Set Breakpoint"
 7141        };
 7142
 7143        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7144            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7145
 7146        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7147            BreakpointState::Enabled => Some("Disable"),
 7148            BreakpointState::Disabled => Some("Enable"),
 7149        });
 7150
 7151        let (anchor, breakpoint) =
 7152            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7153
 7154        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7155            menu.on_blur_subscription(Subscription::new(|| {}))
 7156                .context(focus_handle)
 7157                .when(run_to_cursor, |this| {
 7158                    let weak_editor = weak_editor.clone();
 7159                    this.entry("Run to cursor", None, move |window, cx| {
 7160                        weak_editor
 7161                            .update(cx, |editor, cx| {
 7162                                editor.change_selections(None, window, cx, |s| {
 7163                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7164                                });
 7165                            })
 7166                            .ok();
 7167
 7168                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7169                    })
 7170                    .separator()
 7171                })
 7172                .when_some(toggle_state_msg, |this, msg| {
 7173                    this.entry(msg, None, {
 7174                        let weak_editor = weak_editor.clone();
 7175                        let breakpoint = breakpoint.clone();
 7176                        move |_window, cx| {
 7177                            weak_editor
 7178                                .update(cx, |this, cx| {
 7179                                    this.edit_breakpoint_at_anchor(
 7180                                        anchor,
 7181                                        breakpoint.as_ref().clone(),
 7182                                        BreakpointEditAction::InvertState,
 7183                                        cx,
 7184                                    );
 7185                                })
 7186                                .log_err();
 7187                        }
 7188                    })
 7189                })
 7190                .entry(set_breakpoint_msg, None, {
 7191                    let weak_editor = weak_editor.clone();
 7192                    let breakpoint = breakpoint.clone();
 7193                    move |_window, cx| {
 7194                        weak_editor
 7195                            .update(cx, |this, cx| {
 7196                                this.edit_breakpoint_at_anchor(
 7197                                    anchor,
 7198                                    breakpoint.as_ref().clone(),
 7199                                    BreakpointEditAction::Toggle,
 7200                                    cx,
 7201                                );
 7202                            })
 7203                            .log_err();
 7204                    }
 7205                })
 7206                .entry(log_breakpoint_msg, None, {
 7207                    let breakpoint = breakpoint.clone();
 7208                    let weak_editor = weak_editor.clone();
 7209                    move |window, cx| {
 7210                        weak_editor
 7211                            .update(cx, |this, cx| {
 7212                                this.add_edit_breakpoint_block(
 7213                                    anchor,
 7214                                    breakpoint.as_ref(),
 7215                                    BreakpointPromptEditAction::Log,
 7216                                    window,
 7217                                    cx,
 7218                                );
 7219                            })
 7220                            .log_err();
 7221                    }
 7222                })
 7223                .entry(condition_breakpoint_msg, None, {
 7224                    let breakpoint = breakpoint.clone();
 7225                    let weak_editor = weak_editor.clone();
 7226                    move |window, cx| {
 7227                        weak_editor
 7228                            .update(cx, |this, cx| {
 7229                                this.add_edit_breakpoint_block(
 7230                                    anchor,
 7231                                    breakpoint.as_ref(),
 7232                                    BreakpointPromptEditAction::Condition,
 7233                                    window,
 7234                                    cx,
 7235                                );
 7236                            })
 7237                            .log_err();
 7238                    }
 7239                })
 7240                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7241                    weak_editor
 7242                        .update(cx, |this, cx| {
 7243                            this.add_edit_breakpoint_block(
 7244                                anchor,
 7245                                breakpoint.as_ref(),
 7246                                BreakpointPromptEditAction::HitCondition,
 7247                                window,
 7248                                cx,
 7249                            );
 7250                        })
 7251                        .log_err();
 7252                })
 7253        })
 7254    }
 7255
 7256    fn render_breakpoint(
 7257        &self,
 7258        position: Anchor,
 7259        row: DisplayRow,
 7260        breakpoint: &Breakpoint,
 7261        state: Option<BreakpointSessionState>,
 7262        cx: &mut Context<Self>,
 7263    ) -> IconButton {
 7264        let is_rejected = state.is_some_and(|s| !s.verified);
 7265        // Is it a breakpoint that shows up when hovering over gutter?
 7266        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7267            (false, false),
 7268            |PhantomBreakpointIndicator {
 7269                 is_active,
 7270                 display_row,
 7271                 collides_with_existing_breakpoint,
 7272             }| {
 7273                (
 7274                    is_active && display_row == row,
 7275                    collides_with_existing_breakpoint,
 7276                )
 7277            },
 7278        );
 7279
 7280        let (color, icon) = {
 7281            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7282                (false, false) => ui::IconName::DebugBreakpoint,
 7283                (true, false) => ui::IconName::DebugLogBreakpoint,
 7284                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7285                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7286            };
 7287
 7288            let color = if is_phantom {
 7289                Color::Hint
 7290            } else if is_rejected {
 7291                Color::Disabled
 7292            } else {
 7293                Color::Debugger
 7294            };
 7295
 7296            (color, icon)
 7297        };
 7298
 7299        let breakpoint = Arc::from(breakpoint.clone());
 7300
 7301        let alt_as_text = gpui::Keystroke {
 7302            modifiers: Modifiers::secondary_key(),
 7303            ..Default::default()
 7304        };
 7305        let primary_action_text = if breakpoint.is_disabled() {
 7306            "Enable breakpoint"
 7307        } else if is_phantom && !collides_with_existing {
 7308            "Set breakpoint"
 7309        } else {
 7310            "Unset breakpoint"
 7311        };
 7312        let focus_handle = self.focus_handle.clone();
 7313
 7314        let meta = if is_rejected {
 7315            SharedString::from("No executable code is associated with this line.")
 7316        } else if collides_with_existing && !breakpoint.is_disabled() {
 7317            SharedString::from(format!(
 7318                "{alt_as_text}-click to disable,\nright-click for more options."
 7319            ))
 7320        } else {
 7321            SharedString::from("Right-click for more options.")
 7322        };
 7323        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7324            .icon_size(IconSize::XSmall)
 7325            .size(ui::ButtonSize::None)
 7326            .when(is_rejected, |this| {
 7327                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7328            })
 7329            .icon_color(color)
 7330            .style(ButtonStyle::Transparent)
 7331            .on_click(cx.listener({
 7332                let breakpoint = breakpoint.clone();
 7333
 7334                move |editor, event: &ClickEvent, window, cx| {
 7335                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7336                        BreakpointEditAction::InvertState
 7337                    } else {
 7338                        BreakpointEditAction::Toggle
 7339                    };
 7340
 7341                    window.focus(&editor.focus_handle(cx));
 7342                    editor.edit_breakpoint_at_anchor(
 7343                        position,
 7344                        breakpoint.as_ref().clone(),
 7345                        edit_action,
 7346                        cx,
 7347                    );
 7348                }
 7349            }))
 7350            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7351                editor.set_breakpoint_context_menu(
 7352                    row,
 7353                    Some(position),
 7354                    event.down.position,
 7355                    window,
 7356                    cx,
 7357                );
 7358            }))
 7359            .tooltip(move |window, cx| {
 7360                Tooltip::with_meta_in(
 7361                    primary_action_text,
 7362                    Some(&ToggleBreakpoint),
 7363                    meta.clone(),
 7364                    &focus_handle,
 7365                    window,
 7366                    cx,
 7367                )
 7368            })
 7369    }
 7370
 7371    fn build_tasks_context(
 7372        project: &Entity<Project>,
 7373        buffer: &Entity<Buffer>,
 7374        buffer_row: u32,
 7375        tasks: &Arc<RunnableTasks>,
 7376        cx: &mut Context<Self>,
 7377    ) -> Task<Option<task::TaskContext>> {
 7378        let position = Point::new(buffer_row, tasks.column);
 7379        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7380        let location = Location {
 7381            buffer: buffer.clone(),
 7382            range: range_start..range_start,
 7383        };
 7384        // Fill in the environmental variables from the tree-sitter captures
 7385        let mut captured_task_variables = TaskVariables::default();
 7386        for (capture_name, value) in tasks.extra_variables.clone() {
 7387            captured_task_variables.insert(
 7388                task::VariableName::Custom(capture_name.into()),
 7389                value.clone(),
 7390            );
 7391        }
 7392        project.update(cx, |project, cx| {
 7393            project.task_store().update(cx, |task_store, cx| {
 7394                task_store.task_context_for_location(captured_task_variables, location, cx)
 7395            })
 7396        })
 7397    }
 7398
 7399    pub fn spawn_nearest_task(
 7400        &mut self,
 7401        action: &SpawnNearestTask,
 7402        window: &mut Window,
 7403        cx: &mut Context<Self>,
 7404    ) {
 7405        let Some((workspace, _)) = self.workspace.clone() else {
 7406            return;
 7407        };
 7408        let Some(project) = self.project.clone() else {
 7409            return;
 7410        };
 7411
 7412        // Try to find a closest, enclosing node using tree-sitter that has a
 7413        // task
 7414        let Some((buffer, buffer_row, tasks)) = self
 7415            .find_enclosing_node_task(cx)
 7416            // Or find the task that's closest in row-distance.
 7417            .or_else(|| self.find_closest_task(cx))
 7418        else {
 7419            return;
 7420        };
 7421
 7422        let reveal_strategy = action.reveal;
 7423        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7424        cx.spawn_in(window, async move |_, cx| {
 7425            let context = task_context.await?;
 7426            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7427
 7428            let resolved = &mut resolved_task.resolved;
 7429            resolved.reveal = reveal_strategy;
 7430
 7431            workspace
 7432                .update_in(cx, |workspace, window, cx| {
 7433                    workspace.schedule_resolved_task(
 7434                        task_source_kind,
 7435                        resolved_task,
 7436                        false,
 7437                        window,
 7438                        cx,
 7439                    );
 7440                })
 7441                .ok()
 7442        })
 7443        .detach();
 7444    }
 7445
 7446    fn find_closest_task(
 7447        &mut self,
 7448        cx: &mut Context<Self>,
 7449    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7450        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7451
 7452        let ((buffer_id, row), tasks) = self
 7453            .tasks
 7454            .iter()
 7455            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7456
 7457        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7458        let tasks = Arc::new(tasks.to_owned());
 7459        Some((buffer, *row, tasks))
 7460    }
 7461
 7462    fn find_enclosing_node_task(
 7463        &mut self,
 7464        cx: &mut Context<Self>,
 7465    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7466        let snapshot = self.buffer.read(cx).snapshot(cx);
 7467        let offset = self.selections.newest::<usize>(cx).head();
 7468        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7469        let buffer_id = excerpt.buffer().remote_id();
 7470
 7471        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7472        let mut cursor = layer.node().walk();
 7473
 7474        while cursor.goto_first_child_for_byte(offset).is_some() {
 7475            if cursor.node().end_byte() == offset {
 7476                cursor.goto_next_sibling();
 7477            }
 7478        }
 7479
 7480        // Ascend to the smallest ancestor that contains the range and has a task.
 7481        loop {
 7482            let node = cursor.node();
 7483            let node_range = node.byte_range();
 7484            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7485
 7486            // Check if this node contains our offset
 7487            if node_range.start <= offset && node_range.end >= offset {
 7488                // If it contains offset, check for task
 7489                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7490                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7491                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7492                }
 7493            }
 7494
 7495            if !cursor.goto_parent() {
 7496                break;
 7497            }
 7498        }
 7499        None
 7500    }
 7501
 7502    fn render_run_indicator(
 7503        &self,
 7504        _style: &EditorStyle,
 7505        is_active: bool,
 7506        row: DisplayRow,
 7507        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7508        cx: &mut Context<Self>,
 7509    ) -> IconButton {
 7510        let color = Color::Muted;
 7511        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7512
 7513        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7514            .shape(ui::IconButtonShape::Square)
 7515            .icon_size(IconSize::XSmall)
 7516            .icon_color(color)
 7517            .toggle_state(is_active)
 7518            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7519                let quick_launch = e.down.button == MouseButton::Left;
 7520                window.focus(&editor.focus_handle(cx));
 7521                editor.toggle_code_actions(
 7522                    &ToggleCodeActions {
 7523                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7524                        quick_launch,
 7525                    },
 7526                    window,
 7527                    cx,
 7528                );
 7529            }))
 7530            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7531                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7532            }))
 7533    }
 7534
 7535    pub fn context_menu_visible(&self) -> bool {
 7536        !self.edit_prediction_preview_is_active()
 7537            && self
 7538                .context_menu
 7539                .borrow()
 7540                .as_ref()
 7541                .map_or(false, |menu| menu.visible())
 7542    }
 7543
 7544    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7545        self.context_menu
 7546            .borrow()
 7547            .as_ref()
 7548            .map(|menu| menu.origin())
 7549    }
 7550
 7551    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7552        self.context_menu_options = Some(options);
 7553    }
 7554
 7555    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7556    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7557
 7558    fn render_edit_prediction_popover(
 7559        &mut self,
 7560        text_bounds: &Bounds<Pixels>,
 7561        content_origin: gpui::Point<Pixels>,
 7562        right_margin: Pixels,
 7563        editor_snapshot: &EditorSnapshot,
 7564        visible_row_range: Range<DisplayRow>,
 7565        scroll_top: f32,
 7566        scroll_bottom: f32,
 7567        line_layouts: &[LineWithInvisibles],
 7568        line_height: Pixels,
 7569        scroll_pixel_position: gpui::Point<Pixels>,
 7570        newest_selection_head: Option<DisplayPoint>,
 7571        editor_width: Pixels,
 7572        style: &EditorStyle,
 7573        window: &mut Window,
 7574        cx: &mut App,
 7575    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7576        if self.mode().is_minimap() {
 7577            return None;
 7578        }
 7579        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7580
 7581        if self.edit_prediction_visible_in_cursor_popover(true) {
 7582            return None;
 7583        }
 7584
 7585        match &active_inline_completion.completion {
 7586            InlineCompletion::Move { target, .. } => {
 7587                let target_display_point = target.to_display_point(editor_snapshot);
 7588
 7589                if self.edit_prediction_requires_modifier() {
 7590                    if !self.edit_prediction_preview_is_active() {
 7591                        return None;
 7592                    }
 7593
 7594                    self.render_edit_prediction_modifier_jump_popover(
 7595                        text_bounds,
 7596                        content_origin,
 7597                        visible_row_range,
 7598                        line_layouts,
 7599                        line_height,
 7600                        scroll_pixel_position,
 7601                        newest_selection_head,
 7602                        target_display_point,
 7603                        window,
 7604                        cx,
 7605                    )
 7606                } else {
 7607                    self.render_edit_prediction_eager_jump_popover(
 7608                        text_bounds,
 7609                        content_origin,
 7610                        editor_snapshot,
 7611                        visible_row_range,
 7612                        scroll_top,
 7613                        scroll_bottom,
 7614                        line_height,
 7615                        scroll_pixel_position,
 7616                        target_display_point,
 7617                        editor_width,
 7618                        window,
 7619                        cx,
 7620                    )
 7621                }
 7622            }
 7623            InlineCompletion::Edit {
 7624                display_mode: EditDisplayMode::Inline,
 7625                ..
 7626            } => None,
 7627            InlineCompletion::Edit {
 7628                display_mode: EditDisplayMode::TabAccept,
 7629                edits,
 7630                ..
 7631            } => {
 7632                let range = &edits.first()?.0;
 7633                let target_display_point = range.end.to_display_point(editor_snapshot);
 7634
 7635                self.render_edit_prediction_end_of_line_popover(
 7636                    "Accept",
 7637                    editor_snapshot,
 7638                    visible_row_range,
 7639                    target_display_point,
 7640                    line_height,
 7641                    scroll_pixel_position,
 7642                    content_origin,
 7643                    editor_width,
 7644                    window,
 7645                    cx,
 7646                )
 7647            }
 7648            InlineCompletion::Edit {
 7649                edits,
 7650                edit_preview,
 7651                display_mode: EditDisplayMode::DiffPopover,
 7652                snapshot,
 7653            } => self.render_edit_prediction_diff_popover(
 7654                text_bounds,
 7655                content_origin,
 7656                right_margin,
 7657                editor_snapshot,
 7658                visible_row_range,
 7659                line_layouts,
 7660                line_height,
 7661                scroll_pixel_position,
 7662                newest_selection_head,
 7663                editor_width,
 7664                style,
 7665                edits,
 7666                edit_preview,
 7667                snapshot,
 7668                window,
 7669                cx,
 7670            ),
 7671        }
 7672    }
 7673
 7674    fn render_edit_prediction_modifier_jump_popover(
 7675        &mut self,
 7676        text_bounds: &Bounds<Pixels>,
 7677        content_origin: gpui::Point<Pixels>,
 7678        visible_row_range: Range<DisplayRow>,
 7679        line_layouts: &[LineWithInvisibles],
 7680        line_height: Pixels,
 7681        scroll_pixel_position: gpui::Point<Pixels>,
 7682        newest_selection_head: Option<DisplayPoint>,
 7683        target_display_point: DisplayPoint,
 7684        window: &mut Window,
 7685        cx: &mut App,
 7686    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7687        let scrolled_content_origin =
 7688            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7689
 7690        const SCROLL_PADDING_Y: Pixels = px(12.);
 7691
 7692        if target_display_point.row() < visible_row_range.start {
 7693            return self.render_edit_prediction_scroll_popover(
 7694                |_| SCROLL_PADDING_Y,
 7695                IconName::ArrowUp,
 7696                visible_row_range,
 7697                line_layouts,
 7698                newest_selection_head,
 7699                scrolled_content_origin,
 7700                window,
 7701                cx,
 7702            );
 7703        } else if target_display_point.row() >= visible_row_range.end {
 7704            return self.render_edit_prediction_scroll_popover(
 7705                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7706                IconName::ArrowDown,
 7707                visible_row_range,
 7708                line_layouts,
 7709                newest_selection_head,
 7710                scrolled_content_origin,
 7711                window,
 7712                cx,
 7713            );
 7714        }
 7715
 7716        const POLE_WIDTH: Pixels = px(2.);
 7717
 7718        let line_layout =
 7719            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7720        let target_column = target_display_point.column() as usize;
 7721
 7722        let target_x = line_layout.x_for_index(target_column);
 7723        let target_y =
 7724            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7725
 7726        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7727
 7728        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7729        border_color.l += 0.001;
 7730
 7731        let mut element = v_flex()
 7732            .items_end()
 7733            .when(flag_on_right, |el| el.items_start())
 7734            .child(if flag_on_right {
 7735                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7736                    .rounded_bl(px(0.))
 7737                    .rounded_tl(px(0.))
 7738                    .border_l_2()
 7739                    .border_color(border_color)
 7740            } else {
 7741                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7742                    .rounded_br(px(0.))
 7743                    .rounded_tr(px(0.))
 7744                    .border_r_2()
 7745                    .border_color(border_color)
 7746            })
 7747            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7748            .into_any();
 7749
 7750        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7751
 7752        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7753            - point(
 7754                if flag_on_right {
 7755                    POLE_WIDTH
 7756                } else {
 7757                    size.width - POLE_WIDTH
 7758                },
 7759                size.height - line_height,
 7760            );
 7761
 7762        origin.x = origin.x.max(content_origin.x);
 7763
 7764        element.prepaint_at(origin, window, cx);
 7765
 7766        Some((element, origin))
 7767    }
 7768
 7769    fn render_edit_prediction_scroll_popover(
 7770        &mut self,
 7771        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7772        scroll_icon: IconName,
 7773        visible_row_range: Range<DisplayRow>,
 7774        line_layouts: &[LineWithInvisibles],
 7775        newest_selection_head: Option<DisplayPoint>,
 7776        scrolled_content_origin: gpui::Point<Pixels>,
 7777        window: &mut Window,
 7778        cx: &mut App,
 7779    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7780        let mut element = self
 7781            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7782            .into_any();
 7783
 7784        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7785
 7786        let cursor = newest_selection_head?;
 7787        let cursor_row_layout =
 7788            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7789        let cursor_column = cursor.column() as usize;
 7790
 7791        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7792
 7793        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7794
 7795        element.prepaint_at(origin, window, cx);
 7796        Some((element, origin))
 7797    }
 7798
 7799    fn render_edit_prediction_eager_jump_popover(
 7800        &mut self,
 7801        text_bounds: &Bounds<Pixels>,
 7802        content_origin: gpui::Point<Pixels>,
 7803        editor_snapshot: &EditorSnapshot,
 7804        visible_row_range: Range<DisplayRow>,
 7805        scroll_top: f32,
 7806        scroll_bottom: f32,
 7807        line_height: Pixels,
 7808        scroll_pixel_position: gpui::Point<Pixels>,
 7809        target_display_point: DisplayPoint,
 7810        editor_width: Pixels,
 7811        window: &mut Window,
 7812        cx: &mut App,
 7813    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7814        if target_display_point.row().as_f32() < scroll_top {
 7815            let mut element = self
 7816                .render_edit_prediction_line_popover(
 7817                    "Jump to Edit",
 7818                    Some(IconName::ArrowUp),
 7819                    window,
 7820                    cx,
 7821                )?
 7822                .into_any();
 7823
 7824            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7825            let offset = point(
 7826                (text_bounds.size.width - size.width) / 2.,
 7827                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7828            );
 7829
 7830            let origin = text_bounds.origin + offset;
 7831            element.prepaint_at(origin, window, cx);
 7832            Some((element, origin))
 7833        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7834            let mut element = self
 7835                .render_edit_prediction_line_popover(
 7836                    "Jump to Edit",
 7837                    Some(IconName::ArrowDown),
 7838                    window,
 7839                    cx,
 7840                )?
 7841                .into_any();
 7842
 7843            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7844            let offset = point(
 7845                (text_bounds.size.width - size.width) / 2.,
 7846                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7847            );
 7848
 7849            let origin = text_bounds.origin + offset;
 7850            element.prepaint_at(origin, window, cx);
 7851            Some((element, origin))
 7852        } else {
 7853            self.render_edit_prediction_end_of_line_popover(
 7854                "Jump to Edit",
 7855                editor_snapshot,
 7856                visible_row_range,
 7857                target_display_point,
 7858                line_height,
 7859                scroll_pixel_position,
 7860                content_origin,
 7861                editor_width,
 7862                window,
 7863                cx,
 7864            )
 7865        }
 7866    }
 7867
 7868    fn render_edit_prediction_end_of_line_popover(
 7869        self: &mut Editor,
 7870        label: &'static str,
 7871        editor_snapshot: &EditorSnapshot,
 7872        visible_row_range: Range<DisplayRow>,
 7873        target_display_point: DisplayPoint,
 7874        line_height: Pixels,
 7875        scroll_pixel_position: gpui::Point<Pixels>,
 7876        content_origin: gpui::Point<Pixels>,
 7877        editor_width: Pixels,
 7878        window: &mut Window,
 7879        cx: &mut App,
 7880    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7881        let target_line_end = DisplayPoint::new(
 7882            target_display_point.row(),
 7883            editor_snapshot.line_len(target_display_point.row()),
 7884        );
 7885
 7886        let mut element = self
 7887            .render_edit_prediction_line_popover(label, None, window, cx)?
 7888            .into_any();
 7889
 7890        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7891
 7892        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7893
 7894        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7895        let mut origin = start_point
 7896            + line_origin
 7897            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7898        origin.x = origin.x.max(content_origin.x);
 7899
 7900        let max_x = content_origin.x + editor_width - size.width;
 7901
 7902        if origin.x > max_x {
 7903            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7904
 7905            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7906                origin.y += offset;
 7907                IconName::ArrowUp
 7908            } else {
 7909                origin.y -= offset;
 7910                IconName::ArrowDown
 7911            };
 7912
 7913            element = self
 7914                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7915                .into_any();
 7916
 7917            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7918
 7919            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7920        }
 7921
 7922        element.prepaint_at(origin, window, cx);
 7923        Some((element, origin))
 7924    }
 7925
 7926    fn render_edit_prediction_diff_popover(
 7927        self: &Editor,
 7928        text_bounds: &Bounds<Pixels>,
 7929        content_origin: gpui::Point<Pixels>,
 7930        right_margin: Pixels,
 7931        editor_snapshot: &EditorSnapshot,
 7932        visible_row_range: Range<DisplayRow>,
 7933        line_layouts: &[LineWithInvisibles],
 7934        line_height: Pixels,
 7935        scroll_pixel_position: gpui::Point<Pixels>,
 7936        newest_selection_head: Option<DisplayPoint>,
 7937        editor_width: Pixels,
 7938        style: &EditorStyle,
 7939        edits: &Vec<(Range<Anchor>, String)>,
 7940        edit_preview: &Option<language::EditPreview>,
 7941        snapshot: &language::BufferSnapshot,
 7942        window: &mut Window,
 7943        cx: &mut App,
 7944    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7945        let edit_start = edits
 7946            .first()
 7947            .unwrap()
 7948            .0
 7949            .start
 7950            .to_display_point(editor_snapshot);
 7951        let edit_end = edits
 7952            .last()
 7953            .unwrap()
 7954            .0
 7955            .end
 7956            .to_display_point(editor_snapshot);
 7957
 7958        let is_visible = visible_row_range.contains(&edit_start.row())
 7959            || visible_row_range.contains(&edit_end.row());
 7960        if !is_visible {
 7961            return None;
 7962        }
 7963
 7964        let highlighted_edits =
 7965            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7966
 7967        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7968        let line_count = highlighted_edits.text.lines().count();
 7969
 7970        const BORDER_WIDTH: Pixels = px(1.);
 7971
 7972        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7973        let has_keybind = keybind.is_some();
 7974
 7975        let mut element = h_flex()
 7976            .items_start()
 7977            .child(
 7978                h_flex()
 7979                    .bg(cx.theme().colors().editor_background)
 7980                    .border(BORDER_WIDTH)
 7981                    .shadow_sm()
 7982                    .border_color(cx.theme().colors().border)
 7983                    .rounded_l_lg()
 7984                    .when(line_count > 1, |el| el.rounded_br_lg())
 7985                    .pr_1()
 7986                    .child(styled_text),
 7987            )
 7988            .child(
 7989                h_flex()
 7990                    .h(line_height + BORDER_WIDTH * 2.)
 7991                    .px_1p5()
 7992                    .gap_1()
 7993                    // Workaround: For some reason, there's a gap if we don't do this
 7994                    .ml(-BORDER_WIDTH)
 7995                    .shadow(vec![gpui::BoxShadow {
 7996                        color: gpui::black().opacity(0.05),
 7997                        offset: point(px(1.), px(1.)),
 7998                        blur_radius: px(2.),
 7999                        spread_radius: px(0.),
 8000                    }])
 8001                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8002                    .border(BORDER_WIDTH)
 8003                    .border_color(cx.theme().colors().border)
 8004                    .rounded_r_lg()
 8005                    .id("edit_prediction_diff_popover_keybind")
 8006                    .when(!has_keybind, |el| {
 8007                        let status_colors = cx.theme().status();
 8008
 8009                        el.bg(status_colors.error_background)
 8010                            .border_color(status_colors.error.opacity(0.6))
 8011                            .child(Icon::new(IconName::Info).color(Color::Error))
 8012                            .cursor_default()
 8013                            .hoverable_tooltip(move |_window, cx| {
 8014                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8015                            })
 8016                    })
 8017                    .children(keybind),
 8018            )
 8019            .into_any();
 8020
 8021        let longest_row =
 8022            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8023        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8024            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8025        } else {
 8026            layout_line(
 8027                longest_row,
 8028                editor_snapshot,
 8029                style,
 8030                editor_width,
 8031                |_| false,
 8032                window,
 8033                cx,
 8034            )
 8035            .width
 8036        };
 8037
 8038        let viewport_bounds =
 8039            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8040                right: -right_margin,
 8041                ..Default::default()
 8042            });
 8043
 8044        let x_after_longest =
 8045            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8046                - scroll_pixel_position.x;
 8047
 8048        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8049
 8050        // Fully visible if it can be displayed within the window (allow overlapping other
 8051        // panes). However, this is only allowed if the popover starts within text_bounds.
 8052        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8053            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8054
 8055        let mut origin = if can_position_to_the_right {
 8056            point(
 8057                x_after_longest,
 8058                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8059                    - scroll_pixel_position.y,
 8060            )
 8061        } else {
 8062            let cursor_row = newest_selection_head.map(|head| head.row());
 8063            let above_edit = edit_start
 8064                .row()
 8065                .0
 8066                .checked_sub(line_count as u32)
 8067                .map(DisplayRow);
 8068            let below_edit = Some(edit_end.row() + 1);
 8069            let above_cursor =
 8070                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8071            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8072
 8073            // Place the edit popover adjacent to the edit if there is a location
 8074            // available that is onscreen and does not obscure the cursor. Otherwise,
 8075            // place it adjacent to the cursor.
 8076            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8077                .into_iter()
 8078                .flatten()
 8079                .find(|&start_row| {
 8080                    let end_row = start_row + line_count as u32;
 8081                    visible_row_range.contains(&start_row)
 8082                        && visible_row_range.contains(&end_row)
 8083                        && cursor_row.map_or(true, |cursor_row| {
 8084                            !((start_row..end_row).contains(&cursor_row))
 8085                        })
 8086                })?;
 8087
 8088            content_origin
 8089                + point(
 8090                    -scroll_pixel_position.x,
 8091                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8092                )
 8093        };
 8094
 8095        origin.x -= BORDER_WIDTH;
 8096
 8097        window.defer_draw(element, origin, 1);
 8098
 8099        // Do not return an element, since it will already be drawn due to defer_draw.
 8100        None
 8101    }
 8102
 8103    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8104        px(30.)
 8105    }
 8106
 8107    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8108        if self.read_only(cx) {
 8109            cx.theme().players().read_only()
 8110        } else {
 8111            self.style.as_ref().unwrap().local_player
 8112        }
 8113    }
 8114
 8115    fn render_edit_prediction_accept_keybind(
 8116        &self,
 8117        window: &mut Window,
 8118        cx: &App,
 8119    ) -> Option<AnyElement> {
 8120        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8121        let accept_keystroke = accept_binding.keystroke()?;
 8122
 8123        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8124
 8125        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8126            Color::Accent
 8127        } else {
 8128            Color::Muted
 8129        };
 8130
 8131        h_flex()
 8132            .px_0p5()
 8133            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8134            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8135            .text_size(TextSize::XSmall.rems(cx))
 8136            .child(h_flex().children(ui::render_modifiers(
 8137                &accept_keystroke.modifiers,
 8138                PlatformStyle::platform(),
 8139                Some(modifiers_color),
 8140                Some(IconSize::XSmall.rems().into()),
 8141                true,
 8142            )))
 8143            .when(is_platform_style_mac, |parent| {
 8144                parent.child(accept_keystroke.key.clone())
 8145            })
 8146            .when(!is_platform_style_mac, |parent| {
 8147                parent.child(
 8148                    Key::new(
 8149                        util::capitalize(&accept_keystroke.key),
 8150                        Some(Color::Default),
 8151                    )
 8152                    .size(Some(IconSize::XSmall.rems().into())),
 8153                )
 8154            })
 8155            .into_any()
 8156            .into()
 8157    }
 8158
 8159    fn render_edit_prediction_line_popover(
 8160        &self,
 8161        label: impl Into<SharedString>,
 8162        icon: Option<IconName>,
 8163        window: &mut Window,
 8164        cx: &App,
 8165    ) -> Option<Stateful<Div>> {
 8166        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8167
 8168        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8169        let has_keybind = keybind.is_some();
 8170
 8171        let result = h_flex()
 8172            .id("ep-line-popover")
 8173            .py_0p5()
 8174            .pl_1()
 8175            .pr(padding_right)
 8176            .gap_1()
 8177            .rounded_md()
 8178            .border_1()
 8179            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8180            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8181            .shadow_sm()
 8182            .when(!has_keybind, |el| {
 8183                let status_colors = cx.theme().status();
 8184
 8185                el.bg(status_colors.error_background)
 8186                    .border_color(status_colors.error.opacity(0.6))
 8187                    .pl_2()
 8188                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8189                    .cursor_default()
 8190                    .hoverable_tooltip(move |_window, cx| {
 8191                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8192                    })
 8193            })
 8194            .children(keybind)
 8195            .child(
 8196                Label::new(label)
 8197                    .size(LabelSize::Small)
 8198                    .when(!has_keybind, |el| {
 8199                        el.color(cx.theme().status().error.into()).strikethrough()
 8200                    }),
 8201            )
 8202            .when(!has_keybind, |el| {
 8203                el.child(
 8204                    h_flex().ml_1().child(
 8205                        Icon::new(IconName::Info)
 8206                            .size(IconSize::Small)
 8207                            .color(cx.theme().status().error.into()),
 8208                    ),
 8209                )
 8210            })
 8211            .when_some(icon, |element, icon| {
 8212                element.child(
 8213                    div()
 8214                        .mt(px(1.5))
 8215                        .child(Icon::new(icon).size(IconSize::Small)),
 8216                )
 8217            });
 8218
 8219        Some(result)
 8220    }
 8221
 8222    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8223        let accent_color = cx.theme().colors().text_accent;
 8224        let editor_bg_color = cx.theme().colors().editor_background;
 8225        editor_bg_color.blend(accent_color.opacity(0.1))
 8226    }
 8227
 8228    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8229        let accent_color = cx.theme().colors().text_accent;
 8230        let editor_bg_color = cx.theme().colors().editor_background;
 8231        editor_bg_color.blend(accent_color.opacity(0.6))
 8232    }
 8233
 8234    fn render_edit_prediction_cursor_popover(
 8235        &self,
 8236        min_width: Pixels,
 8237        max_width: Pixels,
 8238        cursor_point: Point,
 8239        style: &EditorStyle,
 8240        accept_keystroke: Option<&gpui::Keystroke>,
 8241        _window: &Window,
 8242        cx: &mut Context<Editor>,
 8243    ) -> Option<AnyElement> {
 8244        let provider = self.edit_prediction_provider.as_ref()?;
 8245
 8246        if provider.provider.needs_terms_acceptance(cx) {
 8247            return Some(
 8248                h_flex()
 8249                    .min_w(min_width)
 8250                    .flex_1()
 8251                    .px_2()
 8252                    .py_1()
 8253                    .gap_3()
 8254                    .elevation_2(cx)
 8255                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8256                    .id("accept-terms")
 8257                    .cursor_pointer()
 8258                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8259                    .on_click(cx.listener(|this, _event, window, cx| {
 8260                        cx.stop_propagation();
 8261                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8262                        window.dispatch_action(
 8263                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8264                            cx,
 8265                        );
 8266                    }))
 8267                    .child(
 8268                        h_flex()
 8269                            .flex_1()
 8270                            .gap_2()
 8271                            .child(Icon::new(IconName::ZedPredict))
 8272                            .child(Label::new("Accept Terms of Service"))
 8273                            .child(div().w_full())
 8274                            .child(
 8275                                Icon::new(IconName::ArrowUpRight)
 8276                                    .color(Color::Muted)
 8277                                    .size(IconSize::Small),
 8278                            )
 8279                            .into_any_element(),
 8280                    )
 8281                    .into_any(),
 8282            );
 8283        }
 8284
 8285        let is_refreshing = provider.provider.is_refreshing(cx);
 8286
 8287        fn pending_completion_container() -> Div {
 8288            h_flex()
 8289                .h_full()
 8290                .flex_1()
 8291                .gap_2()
 8292                .child(Icon::new(IconName::ZedPredict))
 8293        }
 8294
 8295        let completion = match &self.active_inline_completion {
 8296            Some(prediction) => {
 8297                if !self.has_visible_completions_menu() {
 8298                    const RADIUS: Pixels = px(6.);
 8299                    const BORDER_WIDTH: Pixels = px(1.);
 8300
 8301                    return Some(
 8302                        h_flex()
 8303                            .elevation_2(cx)
 8304                            .border(BORDER_WIDTH)
 8305                            .border_color(cx.theme().colors().border)
 8306                            .when(accept_keystroke.is_none(), |el| {
 8307                                el.border_color(cx.theme().status().error)
 8308                            })
 8309                            .rounded(RADIUS)
 8310                            .rounded_tl(px(0.))
 8311                            .overflow_hidden()
 8312                            .child(div().px_1p5().child(match &prediction.completion {
 8313                                InlineCompletion::Move { target, snapshot } => {
 8314                                    use text::ToPoint as _;
 8315                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8316                                    {
 8317                                        Icon::new(IconName::ZedPredictDown)
 8318                                    } else {
 8319                                        Icon::new(IconName::ZedPredictUp)
 8320                                    }
 8321                                }
 8322                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8323                            }))
 8324                            .child(
 8325                                h_flex()
 8326                                    .gap_1()
 8327                                    .py_1()
 8328                                    .px_2()
 8329                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8330                                    .border_l_1()
 8331                                    .border_color(cx.theme().colors().border)
 8332                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8333                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8334                                        el.child(
 8335                                            Label::new("Hold")
 8336                                                .size(LabelSize::Small)
 8337                                                .when(accept_keystroke.is_none(), |el| {
 8338                                                    el.strikethrough()
 8339                                                })
 8340                                                .line_height_style(LineHeightStyle::UiLabel),
 8341                                        )
 8342                                    })
 8343                                    .id("edit_prediction_cursor_popover_keybind")
 8344                                    .when(accept_keystroke.is_none(), |el| {
 8345                                        let status_colors = cx.theme().status();
 8346
 8347                                        el.bg(status_colors.error_background)
 8348                                            .border_color(status_colors.error.opacity(0.6))
 8349                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8350                                            .cursor_default()
 8351                                            .hoverable_tooltip(move |_window, cx| {
 8352                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8353                                                    .into()
 8354                                            })
 8355                                    })
 8356                                    .when_some(
 8357                                        accept_keystroke.as_ref(),
 8358                                        |el, accept_keystroke| {
 8359                                            el.child(h_flex().children(ui::render_modifiers(
 8360                                                &accept_keystroke.modifiers,
 8361                                                PlatformStyle::platform(),
 8362                                                Some(Color::Default),
 8363                                                Some(IconSize::XSmall.rems().into()),
 8364                                                false,
 8365                                            )))
 8366                                        },
 8367                                    ),
 8368                            )
 8369                            .into_any(),
 8370                    );
 8371                }
 8372
 8373                self.render_edit_prediction_cursor_popover_preview(
 8374                    prediction,
 8375                    cursor_point,
 8376                    style,
 8377                    cx,
 8378                )?
 8379            }
 8380
 8381            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8382                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8383                    stale_completion,
 8384                    cursor_point,
 8385                    style,
 8386                    cx,
 8387                )?,
 8388
 8389                None => {
 8390                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8391                }
 8392            },
 8393
 8394            None => pending_completion_container().child(Label::new("No Prediction")),
 8395        };
 8396
 8397        let completion = if is_refreshing {
 8398            completion
 8399                .with_animation(
 8400                    "loading-completion",
 8401                    Animation::new(Duration::from_secs(2))
 8402                        .repeat()
 8403                        .with_easing(pulsating_between(0.4, 0.8)),
 8404                    |label, delta| label.opacity(delta),
 8405                )
 8406                .into_any_element()
 8407        } else {
 8408            completion.into_any_element()
 8409        };
 8410
 8411        let has_completion = self.active_inline_completion.is_some();
 8412
 8413        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8414        Some(
 8415            h_flex()
 8416                .min_w(min_width)
 8417                .max_w(max_width)
 8418                .flex_1()
 8419                .elevation_2(cx)
 8420                .border_color(cx.theme().colors().border)
 8421                .child(
 8422                    div()
 8423                        .flex_1()
 8424                        .py_1()
 8425                        .px_2()
 8426                        .overflow_hidden()
 8427                        .child(completion),
 8428                )
 8429                .when_some(accept_keystroke, |el, accept_keystroke| {
 8430                    if !accept_keystroke.modifiers.modified() {
 8431                        return el;
 8432                    }
 8433
 8434                    el.child(
 8435                        h_flex()
 8436                            .h_full()
 8437                            .border_l_1()
 8438                            .rounded_r_lg()
 8439                            .border_color(cx.theme().colors().border)
 8440                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8441                            .gap_1()
 8442                            .py_1()
 8443                            .px_2()
 8444                            .child(
 8445                                h_flex()
 8446                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8447                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8448                                    .child(h_flex().children(ui::render_modifiers(
 8449                                        &accept_keystroke.modifiers,
 8450                                        PlatformStyle::platform(),
 8451                                        Some(if !has_completion {
 8452                                            Color::Muted
 8453                                        } else {
 8454                                            Color::Default
 8455                                        }),
 8456                                        None,
 8457                                        false,
 8458                                    ))),
 8459                            )
 8460                            .child(Label::new("Preview").into_any_element())
 8461                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8462                    )
 8463                })
 8464                .into_any(),
 8465        )
 8466    }
 8467
 8468    fn render_edit_prediction_cursor_popover_preview(
 8469        &self,
 8470        completion: &InlineCompletionState,
 8471        cursor_point: Point,
 8472        style: &EditorStyle,
 8473        cx: &mut Context<Editor>,
 8474    ) -> Option<Div> {
 8475        use text::ToPoint as _;
 8476
 8477        fn render_relative_row_jump(
 8478            prefix: impl Into<String>,
 8479            current_row: u32,
 8480            target_row: u32,
 8481        ) -> Div {
 8482            let (row_diff, arrow) = if target_row < current_row {
 8483                (current_row - target_row, IconName::ArrowUp)
 8484            } else {
 8485                (target_row - current_row, IconName::ArrowDown)
 8486            };
 8487
 8488            h_flex()
 8489                .child(
 8490                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8491                        .color(Color::Muted)
 8492                        .size(LabelSize::Small),
 8493                )
 8494                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8495        }
 8496
 8497        match &completion.completion {
 8498            InlineCompletion::Move {
 8499                target, snapshot, ..
 8500            } => Some(
 8501                h_flex()
 8502                    .px_2()
 8503                    .gap_2()
 8504                    .flex_1()
 8505                    .child(
 8506                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8507                            Icon::new(IconName::ZedPredictDown)
 8508                        } else {
 8509                            Icon::new(IconName::ZedPredictUp)
 8510                        },
 8511                    )
 8512                    .child(Label::new("Jump to Edit")),
 8513            ),
 8514
 8515            InlineCompletion::Edit {
 8516                edits,
 8517                edit_preview,
 8518                snapshot,
 8519                display_mode: _,
 8520            } => {
 8521                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8522
 8523                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8524                    &snapshot,
 8525                    &edits,
 8526                    edit_preview.as_ref()?,
 8527                    true,
 8528                    cx,
 8529                )
 8530                .first_line_preview();
 8531
 8532                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8533                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8534
 8535                let preview = h_flex()
 8536                    .gap_1()
 8537                    .min_w_16()
 8538                    .child(styled_text)
 8539                    .when(has_more_lines, |parent| parent.child(""));
 8540
 8541                let left = if first_edit_row != cursor_point.row {
 8542                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8543                        .into_any_element()
 8544                } else {
 8545                    Icon::new(IconName::ZedPredict).into_any_element()
 8546                };
 8547
 8548                Some(
 8549                    h_flex()
 8550                        .h_full()
 8551                        .flex_1()
 8552                        .gap_2()
 8553                        .pr_1()
 8554                        .overflow_x_hidden()
 8555                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8556                        .child(left)
 8557                        .child(preview),
 8558                )
 8559            }
 8560        }
 8561    }
 8562
 8563    pub fn render_context_menu(
 8564        &self,
 8565        style: &EditorStyle,
 8566        max_height_in_lines: u32,
 8567        window: &mut Window,
 8568        cx: &mut Context<Editor>,
 8569    ) -> Option<AnyElement> {
 8570        let menu = self.context_menu.borrow();
 8571        let menu = menu.as_ref()?;
 8572        if !menu.visible() {
 8573            return None;
 8574        };
 8575        Some(menu.render(style, max_height_in_lines, window, cx))
 8576    }
 8577
 8578    fn render_context_menu_aside(
 8579        &mut self,
 8580        max_size: Size<Pixels>,
 8581        window: &mut Window,
 8582        cx: &mut Context<Editor>,
 8583    ) -> Option<AnyElement> {
 8584        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8585            if menu.visible() {
 8586                menu.render_aside(self, max_size, window, cx)
 8587            } else {
 8588                None
 8589            }
 8590        })
 8591    }
 8592
 8593    fn hide_context_menu(
 8594        &mut self,
 8595        window: &mut Window,
 8596        cx: &mut Context<Self>,
 8597    ) -> Option<CodeContextMenu> {
 8598        cx.notify();
 8599        self.completion_tasks.clear();
 8600        let context_menu = self.context_menu.borrow_mut().take();
 8601        self.stale_inline_completion_in_menu.take();
 8602        self.update_visible_inline_completion(window, cx);
 8603        context_menu
 8604    }
 8605
 8606    fn show_snippet_choices(
 8607        &mut self,
 8608        choices: &Vec<String>,
 8609        selection: Range<Anchor>,
 8610        cx: &mut Context<Self>,
 8611    ) {
 8612        if selection.start.buffer_id.is_none() {
 8613            return;
 8614        }
 8615        let buffer_id = selection.start.buffer_id.unwrap();
 8616        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8617        let id = post_inc(&mut self.next_completion_id);
 8618        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8619
 8620        if let Some(buffer) = buffer {
 8621            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8622                CompletionsMenu::new_snippet_choices(
 8623                    id,
 8624                    true,
 8625                    choices,
 8626                    selection,
 8627                    buffer,
 8628                    snippet_sort_order,
 8629                ),
 8630            ));
 8631        }
 8632    }
 8633
 8634    pub fn insert_snippet(
 8635        &mut self,
 8636        insertion_ranges: &[Range<usize>],
 8637        snippet: Snippet,
 8638        window: &mut Window,
 8639        cx: &mut Context<Self>,
 8640    ) -> Result<()> {
 8641        struct Tabstop<T> {
 8642            is_end_tabstop: bool,
 8643            ranges: Vec<Range<T>>,
 8644            choices: Option<Vec<String>>,
 8645        }
 8646
 8647        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8648            let snippet_text: Arc<str> = snippet.text.clone().into();
 8649            let edits = insertion_ranges
 8650                .iter()
 8651                .cloned()
 8652                .map(|range| (range, snippet_text.clone()));
 8653            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8654
 8655            let snapshot = &*buffer.read(cx);
 8656            let snippet = &snippet;
 8657            snippet
 8658                .tabstops
 8659                .iter()
 8660                .map(|tabstop| {
 8661                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8662                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8663                    });
 8664                    let mut tabstop_ranges = tabstop
 8665                        .ranges
 8666                        .iter()
 8667                        .flat_map(|tabstop_range| {
 8668                            let mut delta = 0_isize;
 8669                            insertion_ranges.iter().map(move |insertion_range| {
 8670                                let insertion_start = insertion_range.start as isize + delta;
 8671                                delta +=
 8672                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8673
 8674                                let start = ((insertion_start + tabstop_range.start) as usize)
 8675                                    .min(snapshot.len());
 8676                                let end = ((insertion_start + tabstop_range.end) as usize)
 8677                                    .min(snapshot.len());
 8678                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8679                            })
 8680                        })
 8681                        .collect::<Vec<_>>();
 8682                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8683
 8684                    Tabstop {
 8685                        is_end_tabstop,
 8686                        ranges: tabstop_ranges,
 8687                        choices: tabstop.choices.clone(),
 8688                    }
 8689                })
 8690                .collect::<Vec<_>>()
 8691        });
 8692        if let Some(tabstop) = tabstops.first() {
 8693            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8694                s.select_ranges(tabstop.ranges.iter().cloned());
 8695            });
 8696
 8697            if let Some(choices) = &tabstop.choices {
 8698                if let Some(selection) = tabstop.ranges.first() {
 8699                    self.show_snippet_choices(choices, selection.clone(), cx)
 8700                }
 8701            }
 8702
 8703            // If we're already at the last tabstop and it's at the end of the snippet,
 8704            // we're done, we don't need to keep the state around.
 8705            if !tabstop.is_end_tabstop {
 8706                let choices = tabstops
 8707                    .iter()
 8708                    .map(|tabstop| tabstop.choices.clone())
 8709                    .collect();
 8710
 8711                let ranges = tabstops
 8712                    .into_iter()
 8713                    .map(|tabstop| tabstop.ranges)
 8714                    .collect::<Vec<_>>();
 8715
 8716                self.snippet_stack.push(SnippetState {
 8717                    active_index: 0,
 8718                    ranges,
 8719                    choices,
 8720                });
 8721            }
 8722
 8723            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8724            if self.autoclose_regions.is_empty() {
 8725                let snapshot = self.buffer.read(cx).snapshot(cx);
 8726                for selection in &mut self.selections.all::<Point>(cx) {
 8727                    let selection_head = selection.head();
 8728                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8729                        continue;
 8730                    };
 8731
 8732                    let mut bracket_pair = None;
 8733                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8734                    let prev_chars = snapshot
 8735                        .reversed_chars_at(selection_head)
 8736                        .collect::<String>();
 8737                    for (pair, enabled) in scope.brackets() {
 8738                        if enabled
 8739                            && pair.close
 8740                            && prev_chars.starts_with(pair.start.as_str())
 8741                            && next_chars.starts_with(pair.end.as_str())
 8742                        {
 8743                            bracket_pair = Some(pair.clone());
 8744                            break;
 8745                        }
 8746                    }
 8747                    if let Some(pair) = bracket_pair {
 8748                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8749                        let autoclose_enabled =
 8750                            self.use_autoclose && snapshot_settings.use_autoclose;
 8751                        if autoclose_enabled {
 8752                            let start = snapshot.anchor_after(selection_head);
 8753                            let end = snapshot.anchor_after(selection_head);
 8754                            self.autoclose_regions.push(AutocloseRegion {
 8755                                selection_id: selection.id,
 8756                                range: start..end,
 8757                                pair,
 8758                            });
 8759                        }
 8760                    }
 8761                }
 8762            }
 8763        }
 8764        Ok(())
 8765    }
 8766
 8767    pub fn move_to_next_snippet_tabstop(
 8768        &mut self,
 8769        window: &mut Window,
 8770        cx: &mut Context<Self>,
 8771    ) -> bool {
 8772        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8773    }
 8774
 8775    pub fn move_to_prev_snippet_tabstop(
 8776        &mut self,
 8777        window: &mut Window,
 8778        cx: &mut Context<Self>,
 8779    ) -> bool {
 8780        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8781    }
 8782
 8783    pub fn move_to_snippet_tabstop(
 8784        &mut self,
 8785        bias: Bias,
 8786        window: &mut Window,
 8787        cx: &mut Context<Self>,
 8788    ) -> bool {
 8789        if let Some(mut snippet) = self.snippet_stack.pop() {
 8790            match bias {
 8791                Bias::Left => {
 8792                    if snippet.active_index > 0 {
 8793                        snippet.active_index -= 1;
 8794                    } else {
 8795                        self.snippet_stack.push(snippet);
 8796                        return false;
 8797                    }
 8798                }
 8799                Bias::Right => {
 8800                    if snippet.active_index + 1 < snippet.ranges.len() {
 8801                        snippet.active_index += 1;
 8802                    } else {
 8803                        self.snippet_stack.push(snippet);
 8804                        return false;
 8805                    }
 8806                }
 8807            }
 8808            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8809                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8810                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8811                });
 8812
 8813                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8814                    if let Some(selection) = current_ranges.first() {
 8815                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8816                    }
 8817                }
 8818
 8819                // If snippet state is not at the last tabstop, push it back on the stack
 8820                if snippet.active_index + 1 < snippet.ranges.len() {
 8821                    self.snippet_stack.push(snippet);
 8822                }
 8823                return true;
 8824            }
 8825        }
 8826
 8827        false
 8828    }
 8829
 8830    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8831        self.transact(window, cx, |this, window, cx| {
 8832            this.select_all(&SelectAll, window, cx);
 8833            this.insert("", window, cx);
 8834        });
 8835    }
 8836
 8837    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8838        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8839        self.transact(window, cx, |this, window, cx| {
 8840            this.select_autoclose_pair(window, cx);
 8841            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8842            if !this.linked_edit_ranges.is_empty() {
 8843                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8844                let snapshot = this.buffer.read(cx).snapshot(cx);
 8845
 8846                for selection in selections.iter() {
 8847                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8848                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8849                    if selection_start.buffer_id != selection_end.buffer_id {
 8850                        continue;
 8851                    }
 8852                    if let Some(ranges) =
 8853                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8854                    {
 8855                        for (buffer, entries) in ranges {
 8856                            linked_ranges.entry(buffer).or_default().extend(entries);
 8857                        }
 8858                    }
 8859                }
 8860            }
 8861
 8862            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8863            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8864            for selection in &mut selections {
 8865                if selection.is_empty() {
 8866                    let old_head = selection.head();
 8867                    let mut new_head =
 8868                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8869                            .to_point(&display_map);
 8870                    if let Some((buffer, line_buffer_range)) = display_map
 8871                        .buffer_snapshot
 8872                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8873                    {
 8874                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8875                        let indent_len = match indent_size.kind {
 8876                            IndentKind::Space => {
 8877                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8878                            }
 8879                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8880                        };
 8881                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8882                            let indent_len = indent_len.get();
 8883                            new_head = cmp::min(
 8884                                new_head,
 8885                                MultiBufferPoint::new(
 8886                                    old_head.row,
 8887                                    ((old_head.column - 1) / indent_len) * indent_len,
 8888                                ),
 8889                            );
 8890                        }
 8891                    }
 8892
 8893                    selection.set_head(new_head, SelectionGoal::None);
 8894                }
 8895            }
 8896
 8897            this.signature_help_state.set_backspace_pressed(true);
 8898            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8899                s.select(selections)
 8900            });
 8901            this.insert("", window, cx);
 8902            let empty_str: Arc<str> = Arc::from("");
 8903            for (buffer, edits) in linked_ranges {
 8904                let snapshot = buffer.read(cx).snapshot();
 8905                use text::ToPoint as TP;
 8906
 8907                let edits = edits
 8908                    .into_iter()
 8909                    .map(|range| {
 8910                        let end_point = TP::to_point(&range.end, &snapshot);
 8911                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8912
 8913                        if end_point == start_point {
 8914                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8915                                .saturating_sub(1);
 8916                            start_point =
 8917                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8918                        };
 8919
 8920                        (start_point..end_point, empty_str.clone())
 8921                    })
 8922                    .sorted_by_key(|(range, _)| range.start)
 8923                    .collect::<Vec<_>>();
 8924                buffer.update(cx, |this, cx| {
 8925                    this.edit(edits, None, cx);
 8926                })
 8927            }
 8928            this.refresh_inline_completion(true, false, window, cx);
 8929            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8930        });
 8931    }
 8932
 8933    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8934        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8935        self.transact(window, cx, |this, window, cx| {
 8936            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8937                s.move_with(|map, selection| {
 8938                    if selection.is_empty() {
 8939                        let cursor = movement::right(map, selection.head());
 8940                        selection.end = cursor;
 8941                        selection.reversed = true;
 8942                        selection.goal = SelectionGoal::None;
 8943                    }
 8944                })
 8945            });
 8946            this.insert("", window, cx);
 8947            this.refresh_inline_completion(true, false, window, cx);
 8948        });
 8949    }
 8950
 8951    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8952        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8953        if self.move_to_prev_snippet_tabstop(window, cx) {
 8954            return;
 8955        }
 8956        self.outdent(&Outdent, window, cx);
 8957    }
 8958
 8959    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8960        if self.move_to_next_snippet_tabstop(window, cx) {
 8961            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8962            return;
 8963        }
 8964        if self.read_only(cx) {
 8965            return;
 8966        }
 8967        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8968        let mut selections = self.selections.all_adjusted(cx);
 8969        let buffer = self.buffer.read(cx);
 8970        let snapshot = buffer.snapshot(cx);
 8971        let rows_iter = selections.iter().map(|s| s.head().row);
 8972        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8973
 8974        let has_some_cursor_in_whitespace = selections
 8975            .iter()
 8976            .filter(|selection| selection.is_empty())
 8977            .any(|selection| {
 8978                let cursor = selection.head();
 8979                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8980                cursor.column < current_indent.len
 8981            });
 8982
 8983        let mut edits = Vec::new();
 8984        let mut prev_edited_row = 0;
 8985        let mut row_delta = 0;
 8986        for selection in &mut selections {
 8987            if selection.start.row != prev_edited_row {
 8988                row_delta = 0;
 8989            }
 8990            prev_edited_row = selection.end.row;
 8991
 8992            // If the selection is non-empty, then increase the indentation of the selected lines.
 8993            if !selection.is_empty() {
 8994                row_delta =
 8995                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8996                continue;
 8997            }
 8998
 8999            let cursor = selection.head();
 9000            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9001            if let Some(suggested_indent) =
 9002                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9003            {
 9004                // Don't do anything if already at suggested indent
 9005                // and there is any other cursor which is not
 9006                if has_some_cursor_in_whitespace
 9007                    && cursor.column == current_indent.len
 9008                    && current_indent.len == suggested_indent.len
 9009                {
 9010                    continue;
 9011                }
 9012
 9013                // Adjust line and move cursor to suggested indent
 9014                // if cursor is not at suggested indent
 9015                if cursor.column < suggested_indent.len
 9016                    && cursor.column <= current_indent.len
 9017                    && current_indent.len <= suggested_indent.len
 9018                {
 9019                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9020                    selection.end = selection.start;
 9021                    if row_delta == 0 {
 9022                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9023                            cursor.row,
 9024                            current_indent,
 9025                            suggested_indent,
 9026                        ));
 9027                        row_delta = suggested_indent.len - current_indent.len;
 9028                    }
 9029                    continue;
 9030                }
 9031
 9032                // If current indent is more than suggested indent
 9033                // only move cursor to current indent and skip indent
 9034                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9035                    selection.start = Point::new(cursor.row, current_indent.len);
 9036                    selection.end = selection.start;
 9037                    continue;
 9038                }
 9039            }
 9040
 9041            // Otherwise, insert a hard or soft tab.
 9042            let settings = buffer.language_settings_at(cursor, cx);
 9043            let tab_size = if settings.hard_tabs {
 9044                IndentSize::tab()
 9045            } else {
 9046                let tab_size = settings.tab_size.get();
 9047                let indent_remainder = snapshot
 9048                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9049                    .flat_map(str::chars)
 9050                    .fold(row_delta % tab_size, |counter: u32, c| {
 9051                        if c == '\t' {
 9052                            0
 9053                        } else {
 9054                            (counter + 1) % tab_size
 9055                        }
 9056                    });
 9057
 9058                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9059                IndentSize::spaces(chars_to_next_tab_stop)
 9060            };
 9061            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9062            selection.end = selection.start;
 9063            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9064            row_delta += tab_size.len;
 9065        }
 9066
 9067        self.transact(window, cx, |this, window, cx| {
 9068            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9069            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9070                s.select(selections)
 9071            });
 9072            this.refresh_inline_completion(true, false, window, cx);
 9073        });
 9074    }
 9075
 9076    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9077        if self.read_only(cx) {
 9078            return;
 9079        }
 9080        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9081        let mut selections = self.selections.all::<Point>(cx);
 9082        let mut prev_edited_row = 0;
 9083        let mut row_delta = 0;
 9084        let mut edits = Vec::new();
 9085        let buffer = self.buffer.read(cx);
 9086        let snapshot = buffer.snapshot(cx);
 9087        for selection in &mut selections {
 9088            if selection.start.row != prev_edited_row {
 9089                row_delta = 0;
 9090            }
 9091            prev_edited_row = selection.end.row;
 9092
 9093            row_delta =
 9094                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9095        }
 9096
 9097        self.transact(window, cx, |this, window, cx| {
 9098            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9099            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9100                s.select(selections)
 9101            });
 9102        });
 9103    }
 9104
 9105    fn indent_selection(
 9106        buffer: &MultiBuffer,
 9107        snapshot: &MultiBufferSnapshot,
 9108        selection: &mut Selection<Point>,
 9109        edits: &mut Vec<(Range<Point>, String)>,
 9110        delta_for_start_row: u32,
 9111        cx: &App,
 9112    ) -> u32 {
 9113        let settings = buffer.language_settings_at(selection.start, cx);
 9114        let tab_size = settings.tab_size.get();
 9115        let indent_kind = if settings.hard_tabs {
 9116            IndentKind::Tab
 9117        } else {
 9118            IndentKind::Space
 9119        };
 9120        let mut start_row = selection.start.row;
 9121        let mut end_row = selection.end.row + 1;
 9122
 9123        // If a selection ends at the beginning of a line, don't indent
 9124        // that last line.
 9125        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9126            end_row -= 1;
 9127        }
 9128
 9129        // Avoid re-indenting a row that has already been indented by a
 9130        // previous selection, but still update this selection's column
 9131        // to reflect that indentation.
 9132        if delta_for_start_row > 0 {
 9133            start_row += 1;
 9134            selection.start.column += delta_for_start_row;
 9135            if selection.end.row == selection.start.row {
 9136                selection.end.column += delta_for_start_row;
 9137            }
 9138        }
 9139
 9140        let mut delta_for_end_row = 0;
 9141        let has_multiple_rows = start_row + 1 != end_row;
 9142        for row in start_row..end_row {
 9143            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9144            let indent_delta = match (current_indent.kind, indent_kind) {
 9145                (IndentKind::Space, IndentKind::Space) => {
 9146                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9147                    IndentSize::spaces(columns_to_next_tab_stop)
 9148                }
 9149                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9150                (_, IndentKind::Tab) => IndentSize::tab(),
 9151            };
 9152
 9153            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9154                0
 9155            } else {
 9156                selection.start.column
 9157            };
 9158            let row_start = Point::new(row, start);
 9159            edits.push((
 9160                row_start..row_start,
 9161                indent_delta.chars().collect::<String>(),
 9162            ));
 9163
 9164            // Update this selection's endpoints to reflect the indentation.
 9165            if row == selection.start.row {
 9166                selection.start.column += indent_delta.len;
 9167            }
 9168            if row == selection.end.row {
 9169                selection.end.column += indent_delta.len;
 9170                delta_for_end_row = indent_delta.len;
 9171            }
 9172        }
 9173
 9174        if selection.start.row == selection.end.row {
 9175            delta_for_start_row + delta_for_end_row
 9176        } else {
 9177            delta_for_end_row
 9178        }
 9179    }
 9180
 9181    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9182        if self.read_only(cx) {
 9183            return;
 9184        }
 9185        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9187        let selections = self.selections.all::<Point>(cx);
 9188        let mut deletion_ranges = Vec::new();
 9189        let mut last_outdent = None;
 9190        {
 9191            let buffer = self.buffer.read(cx);
 9192            let snapshot = buffer.snapshot(cx);
 9193            for selection in &selections {
 9194                let settings = buffer.language_settings_at(selection.start, cx);
 9195                let tab_size = settings.tab_size.get();
 9196                let mut rows = selection.spanned_rows(false, &display_map);
 9197
 9198                // Avoid re-outdenting a row that has already been outdented by a
 9199                // previous selection.
 9200                if let Some(last_row) = last_outdent {
 9201                    if last_row == rows.start {
 9202                        rows.start = rows.start.next_row();
 9203                    }
 9204                }
 9205                let has_multiple_rows = rows.len() > 1;
 9206                for row in rows.iter_rows() {
 9207                    let indent_size = snapshot.indent_size_for_line(row);
 9208                    if indent_size.len > 0 {
 9209                        let deletion_len = match indent_size.kind {
 9210                            IndentKind::Space => {
 9211                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9212                                if columns_to_prev_tab_stop == 0 {
 9213                                    tab_size
 9214                                } else {
 9215                                    columns_to_prev_tab_stop
 9216                                }
 9217                            }
 9218                            IndentKind::Tab => 1,
 9219                        };
 9220                        let start = if has_multiple_rows
 9221                            || deletion_len > selection.start.column
 9222                            || indent_size.len < selection.start.column
 9223                        {
 9224                            0
 9225                        } else {
 9226                            selection.start.column - deletion_len
 9227                        };
 9228                        deletion_ranges.push(
 9229                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9230                        );
 9231                        last_outdent = Some(row);
 9232                    }
 9233                }
 9234            }
 9235        }
 9236
 9237        self.transact(window, cx, |this, window, cx| {
 9238            this.buffer.update(cx, |buffer, cx| {
 9239                let empty_str: Arc<str> = Arc::default();
 9240                buffer.edit(
 9241                    deletion_ranges
 9242                        .into_iter()
 9243                        .map(|range| (range, empty_str.clone())),
 9244                    None,
 9245                    cx,
 9246                );
 9247            });
 9248            let selections = this.selections.all::<usize>(cx);
 9249            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9250                s.select(selections)
 9251            });
 9252        });
 9253    }
 9254
 9255    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9256        if self.read_only(cx) {
 9257            return;
 9258        }
 9259        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9260        let selections = self
 9261            .selections
 9262            .all::<usize>(cx)
 9263            .into_iter()
 9264            .map(|s| s.range());
 9265
 9266        self.transact(window, cx, |this, window, cx| {
 9267            this.buffer.update(cx, |buffer, cx| {
 9268                buffer.autoindent_ranges(selections, cx);
 9269            });
 9270            let selections = this.selections.all::<usize>(cx);
 9271            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9272                s.select(selections)
 9273            });
 9274        });
 9275    }
 9276
 9277    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9278        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9279        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9280        let selections = self.selections.all::<Point>(cx);
 9281
 9282        let mut new_cursors = Vec::new();
 9283        let mut edit_ranges = Vec::new();
 9284        let mut selections = selections.iter().peekable();
 9285        while let Some(selection) = selections.next() {
 9286            let mut rows = selection.spanned_rows(false, &display_map);
 9287            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9288
 9289            // Accumulate contiguous regions of rows that we want to delete.
 9290            while let Some(next_selection) = selections.peek() {
 9291                let next_rows = next_selection.spanned_rows(false, &display_map);
 9292                if next_rows.start <= rows.end {
 9293                    rows.end = next_rows.end;
 9294                    selections.next().unwrap();
 9295                } else {
 9296                    break;
 9297                }
 9298            }
 9299
 9300            let buffer = &display_map.buffer_snapshot;
 9301            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9302            let edit_end;
 9303            let cursor_buffer_row;
 9304            if buffer.max_point().row >= rows.end.0 {
 9305                // If there's a line after the range, delete the \n from the end of the row range
 9306                // and position the cursor on the next line.
 9307                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9308                cursor_buffer_row = rows.end;
 9309            } else {
 9310                // If there isn't a line after the range, delete the \n from the line before the
 9311                // start of the row range and position the cursor there.
 9312                edit_start = edit_start.saturating_sub(1);
 9313                edit_end = buffer.len();
 9314                cursor_buffer_row = rows.start.previous_row();
 9315            }
 9316
 9317            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9318            *cursor.column_mut() =
 9319                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9320
 9321            new_cursors.push((
 9322                selection.id,
 9323                buffer.anchor_after(cursor.to_point(&display_map)),
 9324            ));
 9325            edit_ranges.push(edit_start..edit_end);
 9326        }
 9327
 9328        self.transact(window, cx, |this, window, cx| {
 9329            let buffer = this.buffer.update(cx, |buffer, cx| {
 9330                let empty_str: Arc<str> = Arc::default();
 9331                buffer.edit(
 9332                    edit_ranges
 9333                        .into_iter()
 9334                        .map(|range| (range, empty_str.clone())),
 9335                    None,
 9336                    cx,
 9337                );
 9338                buffer.snapshot(cx)
 9339            });
 9340            let new_selections = new_cursors
 9341                .into_iter()
 9342                .map(|(id, cursor)| {
 9343                    let cursor = cursor.to_point(&buffer);
 9344                    Selection {
 9345                        id,
 9346                        start: cursor,
 9347                        end: cursor,
 9348                        reversed: false,
 9349                        goal: SelectionGoal::None,
 9350                    }
 9351                })
 9352                .collect();
 9353
 9354            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9355                s.select(new_selections);
 9356            });
 9357        });
 9358    }
 9359
 9360    pub fn join_lines_impl(
 9361        &mut self,
 9362        insert_whitespace: bool,
 9363        window: &mut Window,
 9364        cx: &mut Context<Self>,
 9365    ) {
 9366        if self.read_only(cx) {
 9367            return;
 9368        }
 9369        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9370        for selection in self.selections.all::<Point>(cx) {
 9371            let start = MultiBufferRow(selection.start.row);
 9372            // Treat single line selections as if they include the next line. Otherwise this action
 9373            // would do nothing for single line selections individual cursors.
 9374            let end = if selection.start.row == selection.end.row {
 9375                MultiBufferRow(selection.start.row + 1)
 9376            } else {
 9377                MultiBufferRow(selection.end.row)
 9378            };
 9379
 9380            if let Some(last_row_range) = row_ranges.last_mut() {
 9381                if start <= last_row_range.end {
 9382                    last_row_range.end = end;
 9383                    continue;
 9384                }
 9385            }
 9386            row_ranges.push(start..end);
 9387        }
 9388
 9389        let snapshot = self.buffer.read(cx).snapshot(cx);
 9390        let mut cursor_positions = Vec::new();
 9391        for row_range in &row_ranges {
 9392            let anchor = snapshot.anchor_before(Point::new(
 9393                row_range.end.previous_row().0,
 9394                snapshot.line_len(row_range.end.previous_row()),
 9395            ));
 9396            cursor_positions.push(anchor..anchor);
 9397        }
 9398
 9399        self.transact(window, cx, |this, window, cx| {
 9400            for row_range in row_ranges.into_iter().rev() {
 9401                for row in row_range.iter_rows().rev() {
 9402                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9403                    let next_line_row = row.next_row();
 9404                    let indent = snapshot.indent_size_for_line(next_line_row);
 9405                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9406
 9407                    let replace =
 9408                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9409                            " "
 9410                        } else {
 9411                            ""
 9412                        };
 9413
 9414                    this.buffer.update(cx, |buffer, cx| {
 9415                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9416                    });
 9417                }
 9418            }
 9419
 9420            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9421                s.select_anchor_ranges(cursor_positions)
 9422            });
 9423        });
 9424    }
 9425
 9426    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9427        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9428        self.join_lines_impl(true, window, cx);
 9429    }
 9430
 9431    pub fn sort_lines_case_sensitive(
 9432        &mut self,
 9433        _: &SortLinesCaseSensitive,
 9434        window: &mut Window,
 9435        cx: &mut Context<Self>,
 9436    ) {
 9437        self.manipulate_lines(window, cx, |lines| lines.sort())
 9438    }
 9439
 9440    pub fn sort_lines_case_insensitive(
 9441        &mut self,
 9442        _: &SortLinesCaseInsensitive,
 9443        window: &mut Window,
 9444        cx: &mut Context<Self>,
 9445    ) {
 9446        self.manipulate_lines(window, cx, |lines| {
 9447            lines.sort_by_key(|line| line.to_lowercase())
 9448        })
 9449    }
 9450
 9451    pub fn unique_lines_case_insensitive(
 9452        &mut self,
 9453        _: &UniqueLinesCaseInsensitive,
 9454        window: &mut Window,
 9455        cx: &mut Context<Self>,
 9456    ) {
 9457        self.manipulate_lines(window, cx, |lines| {
 9458            let mut seen = HashSet::default();
 9459            lines.retain(|line| seen.insert(line.to_lowercase()));
 9460        })
 9461    }
 9462
 9463    pub fn unique_lines_case_sensitive(
 9464        &mut self,
 9465        _: &UniqueLinesCaseSensitive,
 9466        window: &mut Window,
 9467        cx: &mut Context<Self>,
 9468    ) {
 9469        self.manipulate_lines(window, cx, |lines| {
 9470            let mut seen = HashSet::default();
 9471            lines.retain(|line| seen.insert(*line));
 9472        })
 9473    }
 9474
 9475    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9476        let Some(project) = self.project.clone() else {
 9477            return;
 9478        };
 9479        self.reload(project, window, cx)
 9480            .detach_and_notify_err(window, cx);
 9481    }
 9482
 9483    pub fn restore_file(
 9484        &mut self,
 9485        _: &::git::RestoreFile,
 9486        window: &mut Window,
 9487        cx: &mut Context<Self>,
 9488    ) {
 9489        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9490        let mut buffer_ids = HashSet::default();
 9491        let snapshot = self.buffer().read(cx).snapshot(cx);
 9492        for selection in self.selections.all::<usize>(cx) {
 9493            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9494        }
 9495
 9496        let buffer = self.buffer().read(cx);
 9497        let ranges = buffer_ids
 9498            .into_iter()
 9499            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9500            .collect::<Vec<_>>();
 9501
 9502        self.restore_hunks_in_ranges(ranges, window, cx);
 9503    }
 9504
 9505    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9506        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9507        let selections = self
 9508            .selections
 9509            .all(cx)
 9510            .into_iter()
 9511            .map(|s| s.range())
 9512            .collect();
 9513        self.restore_hunks_in_ranges(selections, window, cx);
 9514    }
 9515
 9516    pub fn restore_hunks_in_ranges(
 9517        &mut self,
 9518        ranges: Vec<Range<Point>>,
 9519        window: &mut Window,
 9520        cx: &mut Context<Editor>,
 9521    ) {
 9522        let mut revert_changes = HashMap::default();
 9523        let chunk_by = self
 9524            .snapshot(window, cx)
 9525            .hunks_for_ranges(ranges)
 9526            .into_iter()
 9527            .chunk_by(|hunk| hunk.buffer_id);
 9528        for (buffer_id, hunks) in &chunk_by {
 9529            let hunks = hunks.collect::<Vec<_>>();
 9530            for hunk in &hunks {
 9531                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9532            }
 9533            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9534        }
 9535        drop(chunk_by);
 9536        if !revert_changes.is_empty() {
 9537            self.transact(window, cx, |editor, window, cx| {
 9538                editor.restore(revert_changes, window, cx);
 9539            });
 9540        }
 9541    }
 9542
 9543    pub fn open_active_item_in_terminal(
 9544        &mut self,
 9545        _: &OpenInTerminal,
 9546        window: &mut Window,
 9547        cx: &mut Context<Self>,
 9548    ) {
 9549        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9550            let project_path = buffer.read(cx).project_path(cx)?;
 9551            let project = self.project.as_ref()?.read(cx);
 9552            let entry = project.entry_for_path(&project_path, cx)?;
 9553            let parent = match &entry.canonical_path {
 9554                Some(canonical_path) => canonical_path.to_path_buf(),
 9555                None => project.absolute_path(&project_path, cx)?,
 9556            }
 9557            .parent()?
 9558            .to_path_buf();
 9559            Some(parent)
 9560        }) {
 9561            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9562        }
 9563    }
 9564
 9565    fn set_breakpoint_context_menu(
 9566        &mut self,
 9567        display_row: DisplayRow,
 9568        position: Option<Anchor>,
 9569        clicked_point: gpui::Point<Pixels>,
 9570        window: &mut Window,
 9571        cx: &mut Context<Self>,
 9572    ) {
 9573        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9574            return;
 9575        }
 9576        let source = self
 9577            .buffer
 9578            .read(cx)
 9579            .snapshot(cx)
 9580            .anchor_before(Point::new(display_row.0, 0u32));
 9581
 9582        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9583
 9584        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9585            self,
 9586            source,
 9587            clicked_point,
 9588            context_menu,
 9589            window,
 9590            cx,
 9591        );
 9592    }
 9593
 9594    fn add_edit_breakpoint_block(
 9595        &mut self,
 9596        anchor: Anchor,
 9597        breakpoint: &Breakpoint,
 9598        edit_action: BreakpointPromptEditAction,
 9599        window: &mut Window,
 9600        cx: &mut Context<Self>,
 9601    ) {
 9602        let weak_editor = cx.weak_entity();
 9603        let bp_prompt = cx.new(|cx| {
 9604            BreakpointPromptEditor::new(
 9605                weak_editor,
 9606                anchor,
 9607                breakpoint.clone(),
 9608                edit_action,
 9609                window,
 9610                cx,
 9611            )
 9612        });
 9613
 9614        let height = bp_prompt.update(cx, |this, cx| {
 9615            this.prompt
 9616                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9617        });
 9618        let cloned_prompt = bp_prompt.clone();
 9619        let blocks = vec![BlockProperties {
 9620            style: BlockStyle::Sticky,
 9621            placement: BlockPlacement::Above(anchor),
 9622            height: Some(height),
 9623            render: Arc::new(move |cx| {
 9624                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9625                cloned_prompt.clone().into_any_element()
 9626            }),
 9627            priority: 0,
 9628            render_in_minimap: true,
 9629        }];
 9630
 9631        let focus_handle = bp_prompt.focus_handle(cx);
 9632        window.focus(&focus_handle);
 9633
 9634        let block_ids = self.insert_blocks(blocks, None, cx);
 9635        bp_prompt.update(cx, |prompt, _| {
 9636            prompt.add_block_ids(block_ids);
 9637        });
 9638    }
 9639
 9640    pub(crate) fn breakpoint_at_row(
 9641        &self,
 9642        row: u32,
 9643        window: &mut Window,
 9644        cx: &mut Context<Self>,
 9645    ) -> Option<(Anchor, Breakpoint)> {
 9646        let snapshot = self.snapshot(window, cx);
 9647        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9648
 9649        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9650    }
 9651
 9652    pub(crate) fn breakpoint_at_anchor(
 9653        &self,
 9654        breakpoint_position: Anchor,
 9655        snapshot: &EditorSnapshot,
 9656        cx: &mut Context<Self>,
 9657    ) -> Option<(Anchor, Breakpoint)> {
 9658        let project = self.project.clone()?;
 9659
 9660        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9661            snapshot
 9662                .buffer_snapshot
 9663                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9664        })?;
 9665
 9666        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9667        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9668        let buffer_snapshot = buffer.read(cx).snapshot();
 9669
 9670        let row = buffer_snapshot
 9671            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9672            .row;
 9673
 9674        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9675        let anchor_end = snapshot
 9676            .buffer_snapshot
 9677            .anchor_after(Point::new(row, line_len));
 9678
 9679        let bp = self
 9680            .breakpoint_store
 9681            .as_ref()?
 9682            .read_with(cx, |breakpoint_store, cx| {
 9683                breakpoint_store
 9684                    .breakpoints(
 9685                        &buffer,
 9686                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9687                        &buffer_snapshot,
 9688                        cx,
 9689                    )
 9690                    .next()
 9691                    .and_then(|(bp, _)| {
 9692                        let breakpoint_row = buffer_snapshot
 9693                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9694                            .row;
 9695
 9696                        if breakpoint_row == row {
 9697                            snapshot
 9698                                .buffer_snapshot
 9699                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9700                                .map(|position| (position, bp.bp.clone()))
 9701                        } else {
 9702                            None
 9703                        }
 9704                    })
 9705            });
 9706        bp
 9707    }
 9708
 9709    pub fn edit_log_breakpoint(
 9710        &mut self,
 9711        _: &EditLogBreakpoint,
 9712        window: &mut Window,
 9713        cx: &mut Context<Self>,
 9714    ) {
 9715        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9716            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9717                message: None,
 9718                state: BreakpointState::Enabled,
 9719                condition: None,
 9720                hit_condition: None,
 9721            });
 9722
 9723            self.add_edit_breakpoint_block(
 9724                anchor,
 9725                &breakpoint,
 9726                BreakpointPromptEditAction::Log,
 9727                window,
 9728                cx,
 9729            );
 9730        }
 9731    }
 9732
 9733    fn breakpoints_at_cursors(
 9734        &self,
 9735        window: &mut Window,
 9736        cx: &mut Context<Self>,
 9737    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9738        let snapshot = self.snapshot(window, cx);
 9739        let cursors = self
 9740            .selections
 9741            .disjoint_anchors()
 9742            .into_iter()
 9743            .map(|selection| {
 9744                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9745
 9746                let breakpoint_position = self
 9747                    .breakpoint_at_row(cursor_position.row, window, cx)
 9748                    .map(|bp| bp.0)
 9749                    .unwrap_or_else(|| {
 9750                        snapshot
 9751                            .display_snapshot
 9752                            .buffer_snapshot
 9753                            .anchor_after(Point::new(cursor_position.row, 0))
 9754                    });
 9755
 9756                let breakpoint = self
 9757                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9758                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9759
 9760                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9761            })
 9762            // 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.
 9763            .collect::<HashMap<Anchor, _>>();
 9764
 9765        cursors.into_iter().collect()
 9766    }
 9767
 9768    pub fn enable_breakpoint(
 9769        &mut self,
 9770        _: &crate::actions::EnableBreakpoint,
 9771        window: &mut Window,
 9772        cx: &mut Context<Self>,
 9773    ) {
 9774        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9775            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9776                continue;
 9777            };
 9778            self.edit_breakpoint_at_anchor(
 9779                anchor,
 9780                breakpoint,
 9781                BreakpointEditAction::InvertState,
 9782                cx,
 9783            );
 9784        }
 9785    }
 9786
 9787    pub fn disable_breakpoint(
 9788        &mut self,
 9789        _: &crate::actions::DisableBreakpoint,
 9790        window: &mut Window,
 9791        cx: &mut Context<Self>,
 9792    ) {
 9793        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9794            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9795                continue;
 9796            };
 9797            self.edit_breakpoint_at_anchor(
 9798                anchor,
 9799                breakpoint,
 9800                BreakpointEditAction::InvertState,
 9801                cx,
 9802            );
 9803        }
 9804    }
 9805
 9806    pub fn toggle_breakpoint(
 9807        &mut self,
 9808        _: &crate::actions::ToggleBreakpoint,
 9809        window: &mut Window,
 9810        cx: &mut Context<Self>,
 9811    ) {
 9812        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9813            if let Some(breakpoint) = breakpoint {
 9814                self.edit_breakpoint_at_anchor(
 9815                    anchor,
 9816                    breakpoint,
 9817                    BreakpointEditAction::Toggle,
 9818                    cx,
 9819                );
 9820            } else {
 9821                self.edit_breakpoint_at_anchor(
 9822                    anchor,
 9823                    Breakpoint::new_standard(),
 9824                    BreakpointEditAction::Toggle,
 9825                    cx,
 9826                );
 9827            }
 9828        }
 9829    }
 9830
 9831    pub fn edit_breakpoint_at_anchor(
 9832        &mut self,
 9833        breakpoint_position: Anchor,
 9834        breakpoint: Breakpoint,
 9835        edit_action: BreakpointEditAction,
 9836        cx: &mut Context<Self>,
 9837    ) {
 9838        let Some(breakpoint_store) = &self.breakpoint_store else {
 9839            return;
 9840        };
 9841
 9842        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9843            if breakpoint_position == Anchor::min() {
 9844                self.buffer()
 9845                    .read(cx)
 9846                    .excerpt_buffer_ids()
 9847                    .into_iter()
 9848                    .next()
 9849            } else {
 9850                None
 9851            }
 9852        }) else {
 9853            return;
 9854        };
 9855
 9856        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9857            return;
 9858        };
 9859
 9860        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9861            breakpoint_store.toggle_breakpoint(
 9862                buffer,
 9863                BreakpointWithPosition {
 9864                    position: breakpoint_position.text_anchor,
 9865                    bp: breakpoint,
 9866                },
 9867                edit_action,
 9868                cx,
 9869            );
 9870        });
 9871
 9872        cx.notify();
 9873    }
 9874
 9875    #[cfg(any(test, feature = "test-support"))]
 9876    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9877        self.breakpoint_store.clone()
 9878    }
 9879
 9880    pub fn prepare_restore_change(
 9881        &self,
 9882        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9883        hunk: &MultiBufferDiffHunk,
 9884        cx: &mut App,
 9885    ) -> Option<()> {
 9886        if hunk.is_created_file() {
 9887            return None;
 9888        }
 9889        let buffer = self.buffer.read(cx);
 9890        let diff = buffer.diff_for(hunk.buffer_id)?;
 9891        let buffer = buffer.buffer(hunk.buffer_id)?;
 9892        let buffer = buffer.read(cx);
 9893        let original_text = diff
 9894            .read(cx)
 9895            .base_text()
 9896            .as_rope()
 9897            .slice(hunk.diff_base_byte_range.clone());
 9898        let buffer_snapshot = buffer.snapshot();
 9899        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9900        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9901            probe
 9902                .0
 9903                .start
 9904                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9905                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9906        }) {
 9907            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9908            Some(())
 9909        } else {
 9910            None
 9911        }
 9912    }
 9913
 9914    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9915        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9916    }
 9917
 9918    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9919        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9920    }
 9921
 9922    fn manipulate_lines<Fn>(
 9923        &mut self,
 9924        window: &mut Window,
 9925        cx: &mut Context<Self>,
 9926        mut callback: Fn,
 9927    ) where
 9928        Fn: FnMut(&mut Vec<&str>),
 9929    {
 9930        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9931
 9932        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9933        let buffer = self.buffer.read(cx).snapshot(cx);
 9934
 9935        let mut edits = Vec::new();
 9936
 9937        let selections = self.selections.all::<Point>(cx);
 9938        let mut selections = selections.iter().peekable();
 9939        let mut contiguous_row_selections = Vec::new();
 9940        let mut new_selections = Vec::new();
 9941        let mut added_lines = 0;
 9942        let mut removed_lines = 0;
 9943
 9944        while let Some(selection) = selections.next() {
 9945            let (start_row, end_row) = consume_contiguous_rows(
 9946                &mut contiguous_row_selections,
 9947                selection,
 9948                &display_map,
 9949                &mut selections,
 9950            );
 9951
 9952            let start_point = Point::new(start_row.0, 0);
 9953            let end_point = Point::new(
 9954                end_row.previous_row().0,
 9955                buffer.line_len(end_row.previous_row()),
 9956            );
 9957            let text = buffer
 9958                .text_for_range(start_point..end_point)
 9959                .collect::<String>();
 9960
 9961            let mut lines = text.split('\n').collect_vec();
 9962
 9963            let lines_before = lines.len();
 9964            callback(&mut lines);
 9965            let lines_after = lines.len();
 9966
 9967            edits.push((start_point..end_point, lines.join("\n")));
 9968
 9969            // Selections must change based on added and removed line count
 9970            let start_row =
 9971                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9972            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9973            new_selections.push(Selection {
 9974                id: selection.id,
 9975                start: start_row,
 9976                end: end_row,
 9977                goal: SelectionGoal::None,
 9978                reversed: selection.reversed,
 9979            });
 9980
 9981            if lines_after > lines_before {
 9982                added_lines += lines_after - lines_before;
 9983            } else if lines_before > lines_after {
 9984                removed_lines += lines_before - lines_after;
 9985            }
 9986        }
 9987
 9988        self.transact(window, cx, |this, window, cx| {
 9989            let buffer = this.buffer.update(cx, |buffer, cx| {
 9990                buffer.edit(edits, None, cx);
 9991                buffer.snapshot(cx)
 9992            });
 9993
 9994            // Recalculate offsets on newly edited buffer
 9995            let new_selections = new_selections
 9996                .iter()
 9997                .map(|s| {
 9998                    let start_point = Point::new(s.start.0, 0);
 9999                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10000                    Selection {
10001                        id: s.id,
10002                        start: buffer.point_to_offset(start_point),
10003                        end: buffer.point_to_offset(end_point),
10004                        goal: s.goal,
10005                        reversed: s.reversed,
10006                    }
10007                })
10008                .collect();
10009
10010            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10011                s.select(new_selections);
10012            });
10013
10014            this.request_autoscroll(Autoscroll::fit(), cx);
10015        });
10016    }
10017
10018    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10019        self.manipulate_text(window, cx, |text| {
10020            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10021            if has_upper_case_characters {
10022                text.to_lowercase()
10023            } else {
10024                text.to_uppercase()
10025            }
10026        })
10027    }
10028
10029    pub fn convert_to_upper_case(
10030        &mut self,
10031        _: &ConvertToUpperCase,
10032        window: &mut Window,
10033        cx: &mut Context<Self>,
10034    ) {
10035        self.manipulate_text(window, cx, |text| text.to_uppercase())
10036    }
10037
10038    pub fn convert_to_lower_case(
10039        &mut self,
10040        _: &ConvertToLowerCase,
10041        window: &mut Window,
10042        cx: &mut Context<Self>,
10043    ) {
10044        self.manipulate_text(window, cx, |text| text.to_lowercase())
10045    }
10046
10047    pub fn convert_to_title_case(
10048        &mut self,
10049        _: &ConvertToTitleCase,
10050        window: &mut Window,
10051        cx: &mut Context<Self>,
10052    ) {
10053        self.manipulate_text(window, cx, |text| {
10054            text.split('\n')
10055                .map(|line| line.to_case(Case::Title))
10056                .join("\n")
10057        })
10058    }
10059
10060    pub fn convert_to_snake_case(
10061        &mut self,
10062        _: &ConvertToSnakeCase,
10063        window: &mut Window,
10064        cx: &mut Context<Self>,
10065    ) {
10066        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10067    }
10068
10069    pub fn convert_to_kebab_case(
10070        &mut self,
10071        _: &ConvertToKebabCase,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10076    }
10077
10078    pub fn convert_to_upper_camel_case(
10079        &mut self,
10080        _: &ConvertToUpperCamelCase,
10081        window: &mut Window,
10082        cx: &mut Context<Self>,
10083    ) {
10084        self.manipulate_text(window, cx, |text| {
10085            text.split('\n')
10086                .map(|line| line.to_case(Case::UpperCamel))
10087                .join("\n")
10088        })
10089    }
10090
10091    pub fn convert_to_lower_camel_case(
10092        &mut self,
10093        _: &ConvertToLowerCamelCase,
10094        window: &mut Window,
10095        cx: &mut Context<Self>,
10096    ) {
10097        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10098    }
10099
10100    pub fn convert_to_opposite_case(
10101        &mut self,
10102        _: &ConvertToOppositeCase,
10103        window: &mut Window,
10104        cx: &mut Context<Self>,
10105    ) {
10106        self.manipulate_text(window, cx, |text| {
10107            text.chars()
10108                .fold(String::with_capacity(text.len()), |mut t, c| {
10109                    if c.is_uppercase() {
10110                        t.extend(c.to_lowercase());
10111                    } else {
10112                        t.extend(c.to_uppercase());
10113                    }
10114                    t
10115                })
10116        })
10117    }
10118
10119    pub fn convert_to_rot13(
10120        &mut self,
10121        _: &ConvertToRot13,
10122        window: &mut Window,
10123        cx: &mut Context<Self>,
10124    ) {
10125        self.manipulate_text(window, cx, |text| {
10126            text.chars()
10127                .map(|c| match c {
10128                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10129                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10130                    _ => c,
10131                })
10132                .collect()
10133        })
10134    }
10135
10136    pub fn convert_to_rot47(
10137        &mut self,
10138        _: &ConvertToRot47,
10139        window: &mut Window,
10140        cx: &mut Context<Self>,
10141    ) {
10142        self.manipulate_text(window, cx, |text| {
10143            text.chars()
10144                .map(|c| {
10145                    let code_point = c as u32;
10146                    if code_point >= 33 && code_point <= 126 {
10147                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10148                    }
10149                    c
10150                })
10151                .collect()
10152        })
10153    }
10154
10155    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10156    where
10157        Fn: FnMut(&str) -> String,
10158    {
10159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10160        let buffer = self.buffer.read(cx).snapshot(cx);
10161
10162        let mut new_selections = Vec::new();
10163        let mut edits = Vec::new();
10164        let mut selection_adjustment = 0i32;
10165
10166        for selection in self.selections.all::<usize>(cx) {
10167            let selection_is_empty = selection.is_empty();
10168
10169            let (start, end) = if selection_is_empty {
10170                let word_range = movement::surrounding_word(
10171                    &display_map,
10172                    selection.start.to_display_point(&display_map),
10173                );
10174                let start = word_range.start.to_offset(&display_map, Bias::Left);
10175                let end = word_range.end.to_offset(&display_map, Bias::Left);
10176                (start, end)
10177            } else {
10178                (selection.start, selection.end)
10179            };
10180
10181            let text = buffer.text_for_range(start..end).collect::<String>();
10182            let old_length = text.len() as i32;
10183            let text = callback(&text);
10184
10185            new_selections.push(Selection {
10186                start: (start as i32 - selection_adjustment) as usize,
10187                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10188                goal: SelectionGoal::None,
10189                ..selection
10190            });
10191
10192            selection_adjustment += old_length - text.len() as i32;
10193
10194            edits.push((start..end, text));
10195        }
10196
10197        self.transact(window, cx, |this, window, cx| {
10198            this.buffer.update(cx, |buffer, cx| {
10199                buffer.edit(edits, None, cx);
10200            });
10201
10202            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10203                s.select(new_selections);
10204            });
10205
10206            this.request_autoscroll(Autoscroll::fit(), cx);
10207        });
10208    }
10209
10210    pub fn duplicate(
10211        &mut self,
10212        upwards: bool,
10213        whole_lines: bool,
10214        window: &mut Window,
10215        cx: &mut Context<Self>,
10216    ) {
10217        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10218
10219        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10220        let buffer = &display_map.buffer_snapshot;
10221        let selections = self.selections.all::<Point>(cx);
10222
10223        let mut edits = Vec::new();
10224        let mut selections_iter = selections.iter().peekable();
10225        while let Some(selection) = selections_iter.next() {
10226            let mut rows = selection.spanned_rows(false, &display_map);
10227            // duplicate line-wise
10228            if whole_lines || selection.start == selection.end {
10229                // Avoid duplicating the same lines twice.
10230                while let Some(next_selection) = selections_iter.peek() {
10231                    let next_rows = next_selection.spanned_rows(false, &display_map);
10232                    if next_rows.start < rows.end {
10233                        rows.end = next_rows.end;
10234                        selections_iter.next().unwrap();
10235                    } else {
10236                        break;
10237                    }
10238                }
10239
10240                // Copy the text from the selected row region and splice it either at the start
10241                // or end of the region.
10242                let start = Point::new(rows.start.0, 0);
10243                let end = Point::new(
10244                    rows.end.previous_row().0,
10245                    buffer.line_len(rows.end.previous_row()),
10246                );
10247                let text = buffer
10248                    .text_for_range(start..end)
10249                    .chain(Some("\n"))
10250                    .collect::<String>();
10251                let insert_location = if upwards {
10252                    Point::new(rows.end.0, 0)
10253                } else {
10254                    start
10255                };
10256                edits.push((insert_location..insert_location, text));
10257            } else {
10258                // duplicate character-wise
10259                let start = selection.start;
10260                let end = selection.end;
10261                let text = buffer.text_for_range(start..end).collect::<String>();
10262                edits.push((selection.end..selection.end, text));
10263            }
10264        }
10265
10266        self.transact(window, cx, |this, _, cx| {
10267            this.buffer.update(cx, |buffer, cx| {
10268                buffer.edit(edits, None, cx);
10269            });
10270
10271            this.request_autoscroll(Autoscroll::fit(), cx);
10272        });
10273    }
10274
10275    pub fn duplicate_line_up(
10276        &mut self,
10277        _: &DuplicateLineUp,
10278        window: &mut Window,
10279        cx: &mut Context<Self>,
10280    ) {
10281        self.duplicate(true, true, window, cx);
10282    }
10283
10284    pub fn duplicate_line_down(
10285        &mut self,
10286        _: &DuplicateLineDown,
10287        window: &mut Window,
10288        cx: &mut Context<Self>,
10289    ) {
10290        self.duplicate(false, true, window, cx);
10291    }
10292
10293    pub fn duplicate_selection(
10294        &mut self,
10295        _: &DuplicateSelection,
10296        window: &mut Window,
10297        cx: &mut Context<Self>,
10298    ) {
10299        self.duplicate(false, false, window, cx);
10300    }
10301
10302    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10303        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10304
10305        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10306        let buffer = self.buffer.read(cx).snapshot(cx);
10307
10308        let mut edits = Vec::new();
10309        let mut unfold_ranges = Vec::new();
10310        let mut refold_creases = Vec::new();
10311
10312        let selections = self.selections.all::<Point>(cx);
10313        let mut selections = selections.iter().peekable();
10314        let mut contiguous_row_selections = Vec::new();
10315        let mut new_selections = Vec::new();
10316
10317        while let Some(selection) = selections.next() {
10318            // Find all the selections that span a contiguous row range
10319            let (start_row, end_row) = consume_contiguous_rows(
10320                &mut contiguous_row_selections,
10321                selection,
10322                &display_map,
10323                &mut selections,
10324            );
10325
10326            // Move the text spanned by the row range to be before the line preceding the row range
10327            if start_row.0 > 0 {
10328                let range_to_move = Point::new(
10329                    start_row.previous_row().0,
10330                    buffer.line_len(start_row.previous_row()),
10331                )
10332                    ..Point::new(
10333                        end_row.previous_row().0,
10334                        buffer.line_len(end_row.previous_row()),
10335                    );
10336                let insertion_point = display_map
10337                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10338                    .0;
10339
10340                // Don't move lines across excerpts
10341                if buffer
10342                    .excerpt_containing(insertion_point..range_to_move.end)
10343                    .is_some()
10344                {
10345                    let text = buffer
10346                        .text_for_range(range_to_move.clone())
10347                        .flat_map(|s| s.chars())
10348                        .skip(1)
10349                        .chain(['\n'])
10350                        .collect::<String>();
10351
10352                    edits.push((
10353                        buffer.anchor_after(range_to_move.start)
10354                            ..buffer.anchor_before(range_to_move.end),
10355                        String::new(),
10356                    ));
10357                    let insertion_anchor = buffer.anchor_after(insertion_point);
10358                    edits.push((insertion_anchor..insertion_anchor, text));
10359
10360                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10361
10362                    // Move selections up
10363                    new_selections.extend(contiguous_row_selections.drain(..).map(
10364                        |mut selection| {
10365                            selection.start.row -= row_delta;
10366                            selection.end.row -= row_delta;
10367                            selection
10368                        },
10369                    ));
10370
10371                    // Move folds up
10372                    unfold_ranges.push(range_to_move.clone());
10373                    for fold in display_map.folds_in_range(
10374                        buffer.anchor_before(range_to_move.start)
10375                            ..buffer.anchor_after(range_to_move.end),
10376                    ) {
10377                        let mut start = fold.range.start.to_point(&buffer);
10378                        let mut end = fold.range.end.to_point(&buffer);
10379                        start.row -= row_delta;
10380                        end.row -= row_delta;
10381                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10382                    }
10383                }
10384            }
10385
10386            // If we didn't move line(s), preserve the existing selections
10387            new_selections.append(&mut contiguous_row_selections);
10388        }
10389
10390        self.transact(window, cx, |this, window, cx| {
10391            this.unfold_ranges(&unfold_ranges, true, true, cx);
10392            this.buffer.update(cx, |buffer, cx| {
10393                for (range, text) in edits {
10394                    buffer.edit([(range, text)], None, cx);
10395                }
10396            });
10397            this.fold_creases(refold_creases, true, window, cx);
10398            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10399                s.select(new_selections);
10400            })
10401        });
10402    }
10403
10404    pub fn move_line_down(
10405        &mut self,
10406        _: &MoveLineDown,
10407        window: &mut Window,
10408        cx: &mut Context<Self>,
10409    ) {
10410        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10411
10412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10413        let buffer = self.buffer.read(cx).snapshot(cx);
10414
10415        let mut edits = Vec::new();
10416        let mut unfold_ranges = Vec::new();
10417        let mut refold_creases = Vec::new();
10418
10419        let selections = self.selections.all::<Point>(cx);
10420        let mut selections = selections.iter().peekable();
10421        let mut contiguous_row_selections = Vec::new();
10422        let mut new_selections = Vec::new();
10423
10424        while let Some(selection) = selections.next() {
10425            // Find all the selections that span a contiguous row range
10426            let (start_row, end_row) = consume_contiguous_rows(
10427                &mut contiguous_row_selections,
10428                selection,
10429                &display_map,
10430                &mut selections,
10431            );
10432
10433            // Move the text spanned by the row range to be after the last line of the row range
10434            if end_row.0 <= buffer.max_point().row {
10435                let range_to_move =
10436                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10437                let insertion_point = display_map
10438                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10439                    .0;
10440
10441                // Don't move lines across excerpt boundaries
10442                if buffer
10443                    .excerpt_containing(range_to_move.start..insertion_point)
10444                    .is_some()
10445                {
10446                    let mut text = String::from("\n");
10447                    text.extend(buffer.text_for_range(range_to_move.clone()));
10448                    text.pop(); // Drop trailing newline
10449                    edits.push((
10450                        buffer.anchor_after(range_to_move.start)
10451                            ..buffer.anchor_before(range_to_move.end),
10452                        String::new(),
10453                    ));
10454                    let insertion_anchor = buffer.anchor_after(insertion_point);
10455                    edits.push((insertion_anchor..insertion_anchor, text));
10456
10457                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10458
10459                    // Move selections down
10460                    new_selections.extend(contiguous_row_selections.drain(..).map(
10461                        |mut selection| {
10462                            selection.start.row += row_delta;
10463                            selection.end.row += row_delta;
10464                            selection
10465                        },
10466                    ));
10467
10468                    // Move folds down
10469                    unfold_ranges.push(range_to_move.clone());
10470                    for fold in display_map.folds_in_range(
10471                        buffer.anchor_before(range_to_move.start)
10472                            ..buffer.anchor_after(range_to_move.end),
10473                    ) {
10474                        let mut start = fold.range.start.to_point(&buffer);
10475                        let mut end = fold.range.end.to_point(&buffer);
10476                        start.row += row_delta;
10477                        end.row += row_delta;
10478                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10479                    }
10480                }
10481            }
10482
10483            // If we didn't move line(s), preserve the existing selections
10484            new_selections.append(&mut contiguous_row_selections);
10485        }
10486
10487        self.transact(window, cx, |this, window, cx| {
10488            this.unfold_ranges(&unfold_ranges, true, true, cx);
10489            this.buffer.update(cx, |buffer, cx| {
10490                for (range, text) in edits {
10491                    buffer.edit([(range, text)], None, cx);
10492                }
10493            });
10494            this.fold_creases(refold_creases, true, window, cx);
10495            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10496                s.select(new_selections)
10497            });
10498        });
10499    }
10500
10501    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10502        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10503        let text_layout_details = &self.text_layout_details(window);
10504        self.transact(window, cx, |this, window, cx| {
10505            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10506                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10507                s.move_with(|display_map, selection| {
10508                    if !selection.is_empty() {
10509                        return;
10510                    }
10511
10512                    let mut head = selection.head();
10513                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10514                    if head.column() == display_map.line_len(head.row()) {
10515                        transpose_offset = display_map
10516                            .buffer_snapshot
10517                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10518                    }
10519
10520                    if transpose_offset == 0 {
10521                        return;
10522                    }
10523
10524                    *head.column_mut() += 1;
10525                    head = display_map.clip_point(head, Bias::Right);
10526                    let goal = SelectionGoal::HorizontalPosition(
10527                        display_map
10528                            .x_for_display_point(head, text_layout_details)
10529                            .into(),
10530                    );
10531                    selection.collapse_to(head, goal);
10532
10533                    let transpose_start = display_map
10534                        .buffer_snapshot
10535                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10536                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10537                        let transpose_end = display_map
10538                            .buffer_snapshot
10539                            .clip_offset(transpose_offset + 1, Bias::Right);
10540                        if let Some(ch) =
10541                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10542                        {
10543                            edits.push((transpose_start..transpose_offset, String::new()));
10544                            edits.push((transpose_end..transpose_end, ch.to_string()));
10545                        }
10546                    }
10547                });
10548                edits
10549            });
10550            this.buffer
10551                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10552            let selections = this.selections.all::<usize>(cx);
10553            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10554                s.select(selections);
10555            });
10556        });
10557    }
10558
10559    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10560        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10561        self.rewrap_impl(RewrapOptions::default(), cx)
10562    }
10563
10564    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10565        let buffer = self.buffer.read(cx).snapshot(cx);
10566        let selections = self.selections.all::<Point>(cx);
10567        let mut selections = selections.iter().peekable();
10568
10569        let mut edits = Vec::new();
10570        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10571
10572        while let Some(selection) = selections.next() {
10573            let mut start_row = selection.start.row;
10574            let mut end_row = selection.end.row;
10575
10576            // Skip selections that overlap with a range that has already been rewrapped.
10577            let selection_range = start_row..end_row;
10578            if rewrapped_row_ranges
10579                .iter()
10580                .any(|range| range.overlaps(&selection_range))
10581            {
10582                continue;
10583            }
10584
10585            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10586
10587            // Since not all lines in the selection may be at the same indent
10588            // level, choose the indent size that is the most common between all
10589            // of the lines.
10590            //
10591            // If there is a tie, we use the deepest indent.
10592            let (indent_size, indent_end) = {
10593                let mut indent_size_occurrences = HashMap::default();
10594                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10595
10596                for row in start_row..=end_row {
10597                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10598                    rows_by_indent_size.entry(indent).or_default().push(row);
10599                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10600                }
10601
10602                let indent_size = indent_size_occurrences
10603                    .into_iter()
10604                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10605                    .map(|(indent, _)| indent)
10606                    .unwrap_or_default();
10607                let row = rows_by_indent_size[&indent_size][0];
10608                let indent_end = Point::new(row, indent_size.len);
10609
10610                (indent_size, indent_end)
10611            };
10612
10613            let mut line_prefix = indent_size.chars().collect::<String>();
10614
10615            let mut inside_comment = false;
10616            if let Some(comment_prefix) =
10617                buffer
10618                    .language_scope_at(selection.head())
10619                    .and_then(|language| {
10620                        language
10621                            .line_comment_prefixes()
10622                            .iter()
10623                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10624                            .cloned()
10625                    })
10626            {
10627                line_prefix.push_str(&comment_prefix);
10628                inside_comment = true;
10629            }
10630
10631            let language_settings = buffer.language_settings_at(selection.head(), cx);
10632            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10633                RewrapBehavior::InComments => inside_comment,
10634                RewrapBehavior::InSelections => !selection.is_empty(),
10635                RewrapBehavior::Anywhere => true,
10636            };
10637
10638            let should_rewrap = options.override_language_settings
10639                || allow_rewrap_based_on_language
10640                || self.hard_wrap.is_some();
10641            if !should_rewrap {
10642                continue;
10643            }
10644
10645            if selection.is_empty() {
10646                'expand_upwards: while start_row > 0 {
10647                    let prev_row = start_row - 1;
10648                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10649                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10650                    {
10651                        start_row = prev_row;
10652                    } else {
10653                        break 'expand_upwards;
10654                    }
10655                }
10656
10657                'expand_downwards: while end_row < buffer.max_point().row {
10658                    let next_row = end_row + 1;
10659                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10660                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10661                    {
10662                        end_row = next_row;
10663                    } else {
10664                        break 'expand_downwards;
10665                    }
10666                }
10667            }
10668
10669            let start = Point::new(start_row, 0);
10670            let start_offset = start.to_offset(&buffer);
10671            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10672            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10673            let Some(lines_without_prefixes) = selection_text
10674                .lines()
10675                .map(|line| {
10676                    line.strip_prefix(&line_prefix)
10677                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10678                        .with_context(|| {
10679                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10680                        })
10681                })
10682                .collect::<Result<Vec<_>, _>>()
10683                .log_err()
10684            else {
10685                continue;
10686            };
10687
10688            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10689                buffer
10690                    .language_settings_at(Point::new(start_row, 0), cx)
10691                    .preferred_line_length as usize
10692            });
10693            let wrapped_text = wrap_with_prefix(
10694                line_prefix,
10695                lines_without_prefixes.join("\n"),
10696                wrap_column,
10697                tab_size,
10698                options.preserve_existing_whitespace,
10699            );
10700
10701            // TODO: should always use char-based diff while still supporting cursor behavior that
10702            // matches vim.
10703            let mut diff_options = DiffOptions::default();
10704            if options.override_language_settings {
10705                diff_options.max_word_diff_len = 0;
10706                diff_options.max_word_diff_line_count = 0;
10707            } else {
10708                diff_options.max_word_diff_len = usize::MAX;
10709                diff_options.max_word_diff_line_count = usize::MAX;
10710            }
10711
10712            for (old_range, new_text) in
10713                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10714            {
10715                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10716                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10717                edits.push((edit_start..edit_end, new_text));
10718            }
10719
10720            rewrapped_row_ranges.push(start_row..=end_row);
10721        }
10722
10723        self.buffer
10724            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10725    }
10726
10727    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10728        let mut text = String::new();
10729        let buffer = self.buffer.read(cx).snapshot(cx);
10730        let mut selections = self.selections.all::<Point>(cx);
10731        let mut clipboard_selections = Vec::with_capacity(selections.len());
10732        {
10733            let max_point = buffer.max_point();
10734            let mut is_first = true;
10735            for selection in &mut selections {
10736                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10737                if is_entire_line {
10738                    selection.start = Point::new(selection.start.row, 0);
10739                    if !selection.is_empty() && selection.end.column == 0 {
10740                        selection.end = cmp::min(max_point, selection.end);
10741                    } else {
10742                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10743                    }
10744                    selection.goal = SelectionGoal::None;
10745                }
10746                if is_first {
10747                    is_first = false;
10748                } else {
10749                    text += "\n";
10750                }
10751                let mut len = 0;
10752                for chunk in buffer.text_for_range(selection.start..selection.end) {
10753                    text.push_str(chunk);
10754                    len += chunk.len();
10755                }
10756                clipboard_selections.push(ClipboardSelection {
10757                    len,
10758                    is_entire_line,
10759                    first_line_indent: buffer
10760                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10761                        .len,
10762                });
10763            }
10764        }
10765
10766        self.transact(window, cx, |this, window, cx| {
10767            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10768                s.select(selections);
10769            });
10770            this.insert("", window, cx);
10771        });
10772        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10773    }
10774
10775    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10776        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10777        let item = self.cut_common(window, cx);
10778        cx.write_to_clipboard(item);
10779    }
10780
10781    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10782        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10783        self.change_selections(None, window, cx, |s| {
10784            s.move_with(|snapshot, sel| {
10785                if sel.is_empty() {
10786                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10787                }
10788            });
10789        });
10790        let item = self.cut_common(window, cx);
10791        cx.set_global(KillRing(item))
10792    }
10793
10794    pub fn kill_ring_yank(
10795        &mut self,
10796        _: &KillRingYank,
10797        window: &mut Window,
10798        cx: &mut Context<Self>,
10799    ) {
10800        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10801        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10802            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10803                (kill_ring.text().to_string(), kill_ring.metadata_json())
10804            } else {
10805                return;
10806            }
10807        } else {
10808            return;
10809        };
10810        self.do_paste(&text, metadata, false, window, cx);
10811    }
10812
10813    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10814        self.do_copy(true, cx);
10815    }
10816
10817    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10818        self.do_copy(false, cx);
10819    }
10820
10821    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10822        let selections = self.selections.all::<Point>(cx);
10823        let buffer = self.buffer.read(cx).read(cx);
10824        let mut text = String::new();
10825
10826        let mut clipboard_selections = Vec::with_capacity(selections.len());
10827        {
10828            let max_point = buffer.max_point();
10829            let mut is_first = true;
10830            for selection in &selections {
10831                let mut start = selection.start;
10832                let mut end = selection.end;
10833                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10834                if is_entire_line {
10835                    start = Point::new(start.row, 0);
10836                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10837                }
10838
10839                let mut trimmed_selections = Vec::new();
10840                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10841                    let row = MultiBufferRow(start.row);
10842                    let first_indent = buffer.indent_size_for_line(row);
10843                    if first_indent.len == 0 || start.column > first_indent.len {
10844                        trimmed_selections.push(start..end);
10845                    } else {
10846                        trimmed_selections.push(
10847                            Point::new(row.0, first_indent.len)
10848                                ..Point::new(row.0, buffer.line_len(row)),
10849                        );
10850                        for row in start.row + 1..=end.row {
10851                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10852                            if row == end.row {
10853                                line_len = end.column;
10854                            }
10855                            if line_len == 0 {
10856                                trimmed_selections
10857                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10858                                continue;
10859                            }
10860                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10861                            if row_indent_size.len >= first_indent.len {
10862                                trimmed_selections.push(
10863                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10864                                );
10865                            } else {
10866                                trimmed_selections.clear();
10867                                trimmed_selections.push(start..end);
10868                                break;
10869                            }
10870                        }
10871                    }
10872                } else {
10873                    trimmed_selections.push(start..end);
10874                }
10875
10876                for trimmed_range in trimmed_selections {
10877                    if is_first {
10878                        is_first = false;
10879                    } else {
10880                        text += "\n";
10881                    }
10882                    let mut len = 0;
10883                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10884                        text.push_str(chunk);
10885                        len += chunk.len();
10886                    }
10887                    clipboard_selections.push(ClipboardSelection {
10888                        len,
10889                        is_entire_line,
10890                        first_line_indent: buffer
10891                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10892                            .len,
10893                    });
10894                }
10895            }
10896        }
10897
10898        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10899            text,
10900            clipboard_selections,
10901        ));
10902    }
10903
10904    pub fn do_paste(
10905        &mut self,
10906        text: &String,
10907        clipboard_selections: Option<Vec<ClipboardSelection>>,
10908        handle_entire_lines: bool,
10909        window: &mut Window,
10910        cx: &mut Context<Self>,
10911    ) {
10912        if self.read_only(cx) {
10913            return;
10914        }
10915
10916        let clipboard_text = Cow::Borrowed(text);
10917
10918        self.transact(window, cx, |this, window, cx| {
10919            if let Some(mut clipboard_selections) = clipboard_selections {
10920                let old_selections = this.selections.all::<usize>(cx);
10921                let all_selections_were_entire_line =
10922                    clipboard_selections.iter().all(|s| s.is_entire_line);
10923                let first_selection_indent_column =
10924                    clipboard_selections.first().map(|s| s.first_line_indent);
10925                if clipboard_selections.len() != old_selections.len() {
10926                    clipboard_selections.drain(..);
10927                }
10928                let cursor_offset = this.selections.last::<usize>(cx).head();
10929                let mut auto_indent_on_paste = true;
10930
10931                this.buffer.update(cx, |buffer, cx| {
10932                    let snapshot = buffer.read(cx);
10933                    auto_indent_on_paste = snapshot
10934                        .language_settings_at(cursor_offset, cx)
10935                        .auto_indent_on_paste;
10936
10937                    let mut start_offset = 0;
10938                    let mut edits = Vec::new();
10939                    let mut original_indent_columns = Vec::new();
10940                    for (ix, selection) in old_selections.iter().enumerate() {
10941                        let to_insert;
10942                        let entire_line;
10943                        let original_indent_column;
10944                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10945                            let end_offset = start_offset + clipboard_selection.len;
10946                            to_insert = &clipboard_text[start_offset..end_offset];
10947                            entire_line = clipboard_selection.is_entire_line;
10948                            start_offset = end_offset + 1;
10949                            original_indent_column = Some(clipboard_selection.first_line_indent);
10950                        } else {
10951                            to_insert = clipboard_text.as_str();
10952                            entire_line = all_selections_were_entire_line;
10953                            original_indent_column = first_selection_indent_column
10954                        }
10955
10956                        // If the corresponding selection was empty when this slice of the
10957                        // clipboard text was written, then the entire line containing the
10958                        // selection was copied. If this selection is also currently empty,
10959                        // then paste the line before the current line of the buffer.
10960                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10961                            let column = selection.start.to_point(&snapshot).column as usize;
10962                            let line_start = selection.start - column;
10963                            line_start..line_start
10964                        } else {
10965                            selection.range()
10966                        };
10967
10968                        edits.push((range, to_insert));
10969                        original_indent_columns.push(original_indent_column);
10970                    }
10971                    drop(snapshot);
10972
10973                    buffer.edit(
10974                        edits,
10975                        if auto_indent_on_paste {
10976                            Some(AutoindentMode::Block {
10977                                original_indent_columns,
10978                            })
10979                        } else {
10980                            None
10981                        },
10982                        cx,
10983                    );
10984                });
10985
10986                let selections = this.selections.all::<usize>(cx);
10987                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10988                    s.select(selections)
10989                });
10990            } else {
10991                this.insert(&clipboard_text, window, cx);
10992            }
10993        });
10994    }
10995
10996    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10997        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10998        if let Some(item) = cx.read_from_clipboard() {
10999            let entries = item.entries();
11000
11001            match entries.first() {
11002                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11003                // of all the pasted entries.
11004                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11005                    .do_paste(
11006                        clipboard_string.text(),
11007                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11008                        true,
11009                        window,
11010                        cx,
11011                    ),
11012                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11013            }
11014        }
11015    }
11016
11017    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11018        if self.read_only(cx) {
11019            return;
11020        }
11021
11022        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11023
11024        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11025            if let Some((selections, _)) =
11026                self.selection_history.transaction(transaction_id).cloned()
11027            {
11028                self.change_selections(None, window, cx, |s| {
11029                    s.select_anchors(selections.to_vec());
11030                });
11031            } else {
11032                log::error!(
11033                    "No entry in selection_history found for undo. \
11034                     This may correspond to a bug where undo does not update the selection. \
11035                     If this is occurring, please add details to \
11036                     https://github.com/zed-industries/zed/issues/22692"
11037                );
11038            }
11039            self.request_autoscroll(Autoscroll::fit(), cx);
11040            self.unmark_text(window, cx);
11041            self.refresh_inline_completion(true, false, window, cx);
11042            cx.emit(EditorEvent::Edited { transaction_id });
11043            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11044        }
11045    }
11046
11047    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11048        if self.read_only(cx) {
11049            return;
11050        }
11051
11052        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11053
11054        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11055            if let Some((_, Some(selections))) =
11056                self.selection_history.transaction(transaction_id).cloned()
11057            {
11058                self.change_selections(None, window, cx, |s| {
11059                    s.select_anchors(selections.to_vec());
11060                });
11061            } else {
11062                log::error!(
11063                    "No entry in selection_history found for redo. \
11064                     This may correspond to a bug where undo does not update the selection. \
11065                     If this is occurring, please add details to \
11066                     https://github.com/zed-industries/zed/issues/22692"
11067                );
11068            }
11069            self.request_autoscroll(Autoscroll::fit(), cx);
11070            self.unmark_text(window, cx);
11071            self.refresh_inline_completion(true, false, window, cx);
11072            cx.emit(EditorEvent::Edited { transaction_id });
11073        }
11074    }
11075
11076    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11077        self.buffer
11078            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11079    }
11080
11081    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11082        self.buffer
11083            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11084    }
11085
11086    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11087        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11088        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11089            s.move_with(|map, selection| {
11090                let cursor = if selection.is_empty() {
11091                    movement::left(map, selection.start)
11092                } else {
11093                    selection.start
11094                };
11095                selection.collapse_to(cursor, SelectionGoal::None);
11096            });
11097        })
11098    }
11099
11100    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11101        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11102        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11103            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11104        })
11105    }
11106
11107    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11108        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11109        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11110            s.move_with(|map, selection| {
11111                let cursor = if selection.is_empty() {
11112                    movement::right(map, selection.end)
11113                } else {
11114                    selection.end
11115                };
11116                selection.collapse_to(cursor, SelectionGoal::None)
11117            });
11118        })
11119    }
11120
11121    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11122        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11123        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11124            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11125        })
11126    }
11127
11128    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11129        if self.take_rename(true, window, cx).is_some() {
11130            return;
11131        }
11132
11133        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11134            cx.propagate();
11135            return;
11136        }
11137
11138        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11139
11140        let text_layout_details = &self.text_layout_details(window);
11141        let selection_count = self.selections.count();
11142        let first_selection = self.selections.first_anchor();
11143
11144        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11145            s.move_with(|map, selection| {
11146                if !selection.is_empty() {
11147                    selection.goal = SelectionGoal::None;
11148                }
11149                let (cursor, goal) = movement::up(
11150                    map,
11151                    selection.start,
11152                    selection.goal,
11153                    false,
11154                    text_layout_details,
11155                );
11156                selection.collapse_to(cursor, goal);
11157            });
11158        });
11159
11160        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11161        {
11162            cx.propagate();
11163        }
11164    }
11165
11166    pub fn move_up_by_lines(
11167        &mut self,
11168        action: &MoveUpByLines,
11169        window: &mut Window,
11170        cx: &mut Context<Self>,
11171    ) {
11172        if self.take_rename(true, window, cx).is_some() {
11173            return;
11174        }
11175
11176        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11177            cx.propagate();
11178            return;
11179        }
11180
11181        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11182
11183        let text_layout_details = &self.text_layout_details(window);
11184
11185        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11186            s.move_with(|map, selection| {
11187                if !selection.is_empty() {
11188                    selection.goal = SelectionGoal::None;
11189                }
11190                let (cursor, goal) = movement::up_by_rows(
11191                    map,
11192                    selection.start,
11193                    action.lines,
11194                    selection.goal,
11195                    false,
11196                    text_layout_details,
11197                );
11198                selection.collapse_to(cursor, goal);
11199            });
11200        })
11201    }
11202
11203    pub fn move_down_by_lines(
11204        &mut self,
11205        action: &MoveDownByLines,
11206        window: &mut Window,
11207        cx: &mut Context<Self>,
11208    ) {
11209        if self.take_rename(true, window, cx).is_some() {
11210            return;
11211        }
11212
11213        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11214            cx.propagate();
11215            return;
11216        }
11217
11218        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11219
11220        let text_layout_details = &self.text_layout_details(window);
11221
11222        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11223            s.move_with(|map, selection| {
11224                if !selection.is_empty() {
11225                    selection.goal = SelectionGoal::None;
11226                }
11227                let (cursor, goal) = movement::down_by_rows(
11228                    map,
11229                    selection.start,
11230                    action.lines,
11231                    selection.goal,
11232                    false,
11233                    text_layout_details,
11234                );
11235                selection.collapse_to(cursor, goal);
11236            });
11237        })
11238    }
11239
11240    pub fn select_down_by_lines(
11241        &mut self,
11242        action: &SelectDownByLines,
11243        window: &mut Window,
11244        cx: &mut Context<Self>,
11245    ) {
11246        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11247        let text_layout_details = &self.text_layout_details(window);
11248        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11249            s.move_heads_with(|map, head, goal| {
11250                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11251            })
11252        })
11253    }
11254
11255    pub fn select_up_by_lines(
11256        &mut self,
11257        action: &SelectUpByLines,
11258        window: &mut Window,
11259        cx: &mut Context<Self>,
11260    ) {
11261        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11262        let text_layout_details = &self.text_layout_details(window);
11263        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11264            s.move_heads_with(|map, head, goal| {
11265                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11266            })
11267        })
11268    }
11269
11270    pub fn select_page_up(
11271        &mut self,
11272        _: &SelectPageUp,
11273        window: &mut Window,
11274        cx: &mut Context<Self>,
11275    ) {
11276        let Some(row_count) = self.visible_row_count() else {
11277            return;
11278        };
11279
11280        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11281
11282        let text_layout_details = &self.text_layout_details(window);
11283
11284        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11285            s.move_heads_with(|map, head, goal| {
11286                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11287            })
11288        })
11289    }
11290
11291    pub fn move_page_up(
11292        &mut self,
11293        action: &MovePageUp,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        if self.take_rename(true, window, cx).is_some() {
11298            return;
11299        }
11300
11301        if self
11302            .context_menu
11303            .borrow_mut()
11304            .as_mut()
11305            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11306            .unwrap_or(false)
11307        {
11308            return;
11309        }
11310
11311        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11312            cx.propagate();
11313            return;
11314        }
11315
11316        let Some(row_count) = self.visible_row_count() else {
11317            return;
11318        };
11319
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11321
11322        let autoscroll = if action.center_cursor {
11323            Autoscroll::center()
11324        } else {
11325            Autoscroll::fit()
11326        };
11327
11328        let text_layout_details = &self.text_layout_details(window);
11329
11330        self.change_selections(Some(autoscroll), window, cx, |s| {
11331            s.move_with(|map, selection| {
11332                if !selection.is_empty() {
11333                    selection.goal = SelectionGoal::None;
11334                }
11335                let (cursor, goal) = movement::up_by_rows(
11336                    map,
11337                    selection.end,
11338                    row_count,
11339                    selection.goal,
11340                    false,
11341                    text_layout_details,
11342                );
11343                selection.collapse_to(cursor, goal);
11344            });
11345        });
11346    }
11347
11348    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11349        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11350        let text_layout_details = &self.text_layout_details(window);
11351        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11352            s.move_heads_with(|map, head, goal| {
11353                movement::up(map, head, goal, false, text_layout_details)
11354            })
11355        })
11356    }
11357
11358    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11359        self.take_rename(true, window, cx);
11360
11361        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11362            cx.propagate();
11363            return;
11364        }
11365
11366        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11367
11368        let text_layout_details = &self.text_layout_details(window);
11369        let selection_count = self.selections.count();
11370        let first_selection = self.selections.first_anchor();
11371
11372        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11373            s.move_with(|map, selection| {
11374                if !selection.is_empty() {
11375                    selection.goal = SelectionGoal::None;
11376                }
11377                let (cursor, goal) = movement::down(
11378                    map,
11379                    selection.end,
11380                    selection.goal,
11381                    false,
11382                    text_layout_details,
11383                );
11384                selection.collapse_to(cursor, goal);
11385            });
11386        });
11387
11388        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11389        {
11390            cx.propagate();
11391        }
11392    }
11393
11394    pub fn select_page_down(
11395        &mut self,
11396        _: &SelectPageDown,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        let Some(row_count) = self.visible_row_count() else {
11401            return;
11402        };
11403
11404        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11405
11406        let text_layout_details = &self.text_layout_details(window);
11407
11408        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11409            s.move_heads_with(|map, head, goal| {
11410                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11411            })
11412        })
11413    }
11414
11415    pub fn move_page_down(
11416        &mut self,
11417        action: &MovePageDown,
11418        window: &mut Window,
11419        cx: &mut Context<Self>,
11420    ) {
11421        if self.take_rename(true, window, cx).is_some() {
11422            return;
11423        }
11424
11425        if self
11426            .context_menu
11427            .borrow_mut()
11428            .as_mut()
11429            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11430            .unwrap_or(false)
11431        {
11432            return;
11433        }
11434
11435        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11436            cx.propagate();
11437            return;
11438        }
11439
11440        let Some(row_count) = self.visible_row_count() else {
11441            return;
11442        };
11443
11444        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11445
11446        let autoscroll = if action.center_cursor {
11447            Autoscroll::center()
11448        } else {
11449            Autoscroll::fit()
11450        };
11451
11452        let text_layout_details = &self.text_layout_details(window);
11453        self.change_selections(Some(autoscroll), window, cx, |s| {
11454            s.move_with(|map, selection| {
11455                if !selection.is_empty() {
11456                    selection.goal = SelectionGoal::None;
11457                }
11458                let (cursor, goal) = movement::down_by_rows(
11459                    map,
11460                    selection.end,
11461                    row_count,
11462                    selection.goal,
11463                    false,
11464                    text_layout_details,
11465                );
11466                selection.collapse_to(cursor, goal);
11467            });
11468        });
11469    }
11470
11471    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11472        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11473        let text_layout_details = &self.text_layout_details(window);
11474        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11475            s.move_heads_with(|map, head, goal| {
11476                movement::down(map, head, goal, false, text_layout_details)
11477            })
11478        });
11479    }
11480
11481    pub fn context_menu_first(
11482        &mut self,
11483        _: &ContextMenuFirst,
11484        _window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11488            context_menu.select_first(self.completion_provider.as_deref(), cx);
11489        }
11490    }
11491
11492    pub fn context_menu_prev(
11493        &mut self,
11494        _: &ContextMenuPrevious,
11495        _window: &mut Window,
11496        cx: &mut Context<Self>,
11497    ) {
11498        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11499            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11500        }
11501    }
11502
11503    pub fn context_menu_next(
11504        &mut self,
11505        _: &ContextMenuNext,
11506        _window: &mut Window,
11507        cx: &mut Context<Self>,
11508    ) {
11509        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11510            context_menu.select_next(self.completion_provider.as_deref(), cx);
11511        }
11512    }
11513
11514    pub fn context_menu_last(
11515        &mut self,
11516        _: &ContextMenuLast,
11517        _window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11521            context_menu.select_last(self.completion_provider.as_deref(), cx);
11522        }
11523    }
11524
11525    pub fn move_to_previous_word_start(
11526        &mut self,
11527        _: &MoveToPreviousWordStart,
11528        window: &mut Window,
11529        cx: &mut Context<Self>,
11530    ) {
11531        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11532        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11533            s.move_cursors_with(|map, head, _| {
11534                (
11535                    movement::previous_word_start(map, head),
11536                    SelectionGoal::None,
11537                )
11538            });
11539        })
11540    }
11541
11542    pub fn move_to_previous_subword_start(
11543        &mut self,
11544        _: &MoveToPreviousSubwordStart,
11545        window: &mut Window,
11546        cx: &mut Context<Self>,
11547    ) {
11548        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11549        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11550            s.move_cursors_with(|map, head, _| {
11551                (
11552                    movement::previous_subword_start(map, head),
11553                    SelectionGoal::None,
11554                )
11555            });
11556        })
11557    }
11558
11559    pub fn select_to_previous_word_start(
11560        &mut self,
11561        _: &SelectToPreviousWordStart,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564    ) {
11565        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11566        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11567            s.move_heads_with(|map, head, _| {
11568                (
11569                    movement::previous_word_start(map, head),
11570                    SelectionGoal::None,
11571                )
11572            });
11573        })
11574    }
11575
11576    pub fn select_to_previous_subword_start(
11577        &mut self,
11578        _: &SelectToPreviousSubwordStart,
11579        window: &mut Window,
11580        cx: &mut Context<Self>,
11581    ) {
11582        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11583        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11584            s.move_heads_with(|map, head, _| {
11585                (
11586                    movement::previous_subword_start(map, head),
11587                    SelectionGoal::None,
11588                )
11589            });
11590        })
11591    }
11592
11593    pub fn delete_to_previous_word_start(
11594        &mut self,
11595        action: &DeleteToPreviousWordStart,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11600        self.transact(window, cx, |this, window, cx| {
11601            this.select_autoclose_pair(window, cx);
11602            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11603                s.move_with(|map, selection| {
11604                    if selection.is_empty() {
11605                        let cursor = if action.ignore_newlines {
11606                            movement::previous_word_start(map, selection.head())
11607                        } else {
11608                            movement::previous_word_start_or_newline(map, selection.head())
11609                        };
11610                        selection.set_head(cursor, SelectionGoal::None);
11611                    }
11612                });
11613            });
11614            this.insert("", window, cx);
11615        });
11616    }
11617
11618    pub fn delete_to_previous_subword_start(
11619        &mut self,
11620        _: &DeleteToPreviousSubwordStart,
11621        window: &mut Window,
11622        cx: &mut Context<Self>,
11623    ) {
11624        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11625        self.transact(window, cx, |this, window, cx| {
11626            this.select_autoclose_pair(window, cx);
11627            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11628                s.move_with(|map, selection| {
11629                    if selection.is_empty() {
11630                        let cursor = movement::previous_subword_start(map, selection.head());
11631                        selection.set_head(cursor, SelectionGoal::None);
11632                    }
11633                });
11634            });
11635            this.insert("", window, cx);
11636        });
11637    }
11638
11639    pub fn move_to_next_word_end(
11640        &mut self,
11641        _: &MoveToNextWordEnd,
11642        window: &mut Window,
11643        cx: &mut Context<Self>,
11644    ) {
11645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11646        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11647            s.move_cursors_with(|map, head, _| {
11648                (movement::next_word_end(map, head), SelectionGoal::None)
11649            });
11650        })
11651    }
11652
11653    pub fn move_to_next_subword_end(
11654        &mut self,
11655        _: &MoveToNextSubwordEnd,
11656        window: &mut Window,
11657        cx: &mut Context<Self>,
11658    ) {
11659        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11660        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11661            s.move_cursors_with(|map, head, _| {
11662                (movement::next_subword_end(map, head), SelectionGoal::None)
11663            });
11664        })
11665    }
11666
11667    pub fn select_to_next_word_end(
11668        &mut self,
11669        _: &SelectToNextWordEnd,
11670        window: &mut Window,
11671        cx: &mut Context<Self>,
11672    ) {
11673        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11674        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11675            s.move_heads_with(|map, head, _| {
11676                (movement::next_word_end(map, head), SelectionGoal::None)
11677            });
11678        })
11679    }
11680
11681    pub fn select_to_next_subword_end(
11682        &mut self,
11683        _: &SelectToNextSubwordEnd,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11688        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11689            s.move_heads_with(|map, head, _| {
11690                (movement::next_subword_end(map, head), SelectionGoal::None)
11691            });
11692        })
11693    }
11694
11695    pub fn delete_to_next_word_end(
11696        &mut self,
11697        action: &DeleteToNextWordEnd,
11698        window: &mut Window,
11699        cx: &mut Context<Self>,
11700    ) {
11701        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11702        self.transact(window, cx, |this, window, cx| {
11703            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11704                s.move_with(|map, selection| {
11705                    if selection.is_empty() {
11706                        let cursor = if action.ignore_newlines {
11707                            movement::next_word_end(map, selection.head())
11708                        } else {
11709                            movement::next_word_end_or_newline(map, selection.head())
11710                        };
11711                        selection.set_head(cursor, SelectionGoal::None);
11712                    }
11713                });
11714            });
11715            this.insert("", window, cx);
11716        });
11717    }
11718
11719    pub fn delete_to_next_subword_end(
11720        &mut self,
11721        _: &DeleteToNextSubwordEnd,
11722        window: &mut Window,
11723        cx: &mut Context<Self>,
11724    ) {
11725        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11726        self.transact(window, cx, |this, window, cx| {
11727            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11728                s.move_with(|map, selection| {
11729                    if selection.is_empty() {
11730                        let cursor = movement::next_subword_end(map, selection.head());
11731                        selection.set_head(cursor, SelectionGoal::None);
11732                    }
11733                });
11734            });
11735            this.insert("", window, cx);
11736        });
11737    }
11738
11739    pub fn move_to_beginning_of_line(
11740        &mut self,
11741        action: &MoveToBeginningOfLine,
11742        window: &mut Window,
11743        cx: &mut Context<Self>,
11744    ) {
11745        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11746        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11747            s.move_cursors_with(|map, head, _| {
11748                (
11749                    movement::indented_line_beginning(
11750                        map,
11751                        head,
11752                        action.stop_at_soft_wraps,
11753                        action.stop_at_indent,
11754                    ),
11755                    SelectionGoal::None,
11756                )
11757            });
11758        })
11759    }
11760
11761    pub fn select_to_beginning_of_line(
11762        &mut self,
11763        action: &SelectToBeginningOfLine,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11768        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11769            s.move_heads_with(|map, head, _| {
11770                (
11771                    movement::indented_line_beginning(
11772                        map,
11773                        head,
11774                        action.stop_at_soft_wraps,
11775                        action.stop_at_indent,
11776                    ),
11777                    SelectionGoal::None,
11778                )
11779            });
11780        });
11781    }
11782
11783    pub fn delete_to_beginning_of_line(
11784        &mut self,
11785        action: &DeleteToBeginningOfLine,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788    ) {
11789        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11790        self.transact(window, cx, |this, window, cx| {
11791            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11792                s.move_with(|_, selection| {
11793                    selection.reversed = true;
11794                });
11795            });
11796
11797            this.select_to_beginning_of_line(
11798                &SelectToBeginningOfLine {
11799                    stop_at_soft_wraps: false,
11800                    stop_at_indent: action.stop_at_indent,
11801                },
11802                window,
11803                cx,
11804            );
11805            this.backspace(&Backspace, window, cx);
11806        });
11807    }
11808
11809    pub fn move_to_end_of_line(
11810        &mut self,
11811        action: &MoveToEndOfLine,
11812        window: &mut Window,
11813        cx: &mut Context<Self>,
11814    ) {
11815        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11816        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11817            s.move_cursors_with(|map, head, _| {
11818                (
11819                    movement::line_end(map, head, action.stop_at_soft_wraps),
11820                    SelectionGoal::None,
11821                )
11822            });
11823        })
11824    }
11825
11826    pub fn select_to_end_of_line(
11827        &mut self,
11828        action: &SelectToEndOfLine,
11829        window: &mut Window,
11830        cx: &mut Context<Self>,
11831    ) {
11832        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11833        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11834            s.move_heads_with(|map, head, _| {
11835                (
11836                    movement::line_end(map, head, action.stop_at_soft_wraps),
11837                    SelectionGoal::None,
11838                )
11839            });
11840        })
11841    }
11842
11843    pub fn delete_to_end_of_line(
11844        &mut self,
11845        _: &DeleteToEndOfLine,
11846        window: &mut Window,
11847        cx: &mut Context<Self>,
11848    ) {
11849        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11850        self.transact(window, cx, |this, window, cx| {
11851            this.select_to_end_of_line(
11852                &SelectToEndOfLine {
11853                    stop_at_soft_wraps: false,
11854                },
11855                window,
11856                cx,
11857            );
11858            this.delete(&Delete, window, cx);
11859        });
11860    }
11861
11862    pub fn cut_to_end_of_line(
11863        &mut self,
11864        _: &CutToEndOfLine,
11865        window: &mut Window,
11866        cx: &mut Context<Self>,
11867    ) {
11868        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11869        self.transact(window, cx, |this, window, cx| {
11870            this.select_to_end_of_line(
11871                &SelectToEndOfLine {
11872                    stop_at_soft_wraps: false,
11873                },
11874                window,
11875                cx,
11876            );
11877            this.cut(&Cut, window, cx);
11878        });
11879    }
11880
11881    pub fn move_to_start_of_paragraph(
11882        &mut self,
11883        _: &MoveToStartOfParagraph,
11884        window: &mut Window,
11885        cx: &mut Context<Self>,
11886    ) {
11887        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11888            cx.propagate();
11889            return;
11890        }
11891        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11892        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11893            s.move_with(|map, selection| {
11894                selection.collapse_to(
11895                    movement::start_of_paragraph(map, selection.head(), 1),
11896                    SelectionGoal::None,
11897                )
11898            });
11899        })
11900    }
11901
11902    pub fn move_to_end_of_paragraph(
11903        &mut self,
11904        _: &MoveToEndOfParagraph,
11905        window: &mut Window,
11906        cx: &mut Context<Self>,
11907    ) {
11908        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11909            cx.propagate();
11910            return;
11911        }
11912        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11913        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11914            s.move_with(|map, selection| {
11915                selection.collapse_to(
11916                    movement::end_of_paragraph(map, selection.head(), 1),
11917                    SelectionGoal::None,
11918                )
11919            });
11920        })
11921    }
11922
11923    pub fn select_to_start_of_paragraph(
11924        &mut self,
11925        _: &SelectToStartOfParagraph,
11926        window: &mut Window,
11927        cx: &mut Context<Self>,
11928    ) {
11929        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11930            cx.propagate();
11931            return;
11932        }
11933        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11934        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11935            s.move_heads_with(|map, head, _| {
11936                (
11937                    movement::start_of_paragraph(map, head, 1),
11938                    SelectionGoal::None,
11939                )
11940            });
11941        })
11942    }
11943
11944    pub fn select_to_end_of_paragraph(
11945        &mut self,
11946        _: &SelectToEndOfParagraph,
11947        window: &mut Window,
11948        cx: &mut Context<Self>,
11949    ) {
11950        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11951            cx.propagate();
11952            return;
11953        }
11954        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11955        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11956            s.move_heads_with(|map, head, _| {
11957                (
11958                    movement::end_of_paragraph(map, head, 1),
11959                    SelectionGoal::None,
11960                )
11961            });
11962        })
11963    }
11964
11965    pub fn move_to_start_of_excerpt(
11966        &mut self,
11967        _: &MoveToStartOfExcerpt,
11968        window: &mut Window,
11969        cx: &mut Context<Self>,
11970    ) {
11971        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11972            cx.propagate();
11973            return;
11974        }
11975        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11976        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11977            s.move_with(|map, selection| {
11978                selection.collapse_to(
11979                    movement::start_of_excerpt(
11980                        map,
11981                        selection.head(),
11982                        workspace::searchable::Direction::Prev,
11983                    ),
11984                    SelectionGoal::None,
11985                )
11986            });
11987        })
11988    }
11989
11990    pub fn move_to_start_of_next_excerpt(
11991        &mut self,
11992        _: &MoveToStartOfNextExcerpt,
11993        window: &mut Window,
11994        cx: &mut Context<Self>,
11995    ) {
11996        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11997            cx.propagate();
11998            return;
11999        }
12000
12001        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12002            s.move_with(|map, selection| {
12003                selection.collapse_to(
12004                    movement::start_of_excerpt(
12005                        map,
12006                        selection.head(),
12007                        workspace::searchable::Direction::Next,
12008                    ),
12009                    SelectionGoal::None,
12010                )
12011            });
12012        })
12013    }
12014
12015    pub fn move_to_end_of_excerpt(
12016        &mut self,
12017        _: &MoveToEndOfExcerpt,
12018        window: &mut Window,
12019        cx: &mut Context<Self>,
12020    ) {
12021        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12022            cx.propagate();
12023            return;
12024        }
12025        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12026        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12027            s.move_with(|map, selection| {
12028                selection.collapse_to(
12029                    movement::end_of_excerpt(
12030                        map,
12031                        selection.head(),
12032                        workspace::searchable::Direction::Next,
12033                    ),
12034                    SelectionGoal::None,
12035                )
12036            });
12037        })
12038    }
12039
12040    pub fn move_to_end_of_previous_excerpt(
12041        &mut self,
12042        _: &MoveToEndOfPreviousExcerpt,
12043        window: &mut Window,
12044        cx: &mut Context<Self>,
12045    ) {
12046        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12047            cx.propagate();
12048            return;
12049        }
12050        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12051        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12052            s.move_with(|map, selection| {
12053                selection.collapse_to(
12054                    movement::end_of_excerpt(
12055                        map,
12056                        selection.head(),
12057                        workspace::searchable::Direction::Prev,
12058                    ),
12059                    SelectionGoal::None,
12060                )
12061            });
12062        })
12063    }
12064
12065    pub fn select_to_start_of_excerpt(
12066        &mut self,
12067        _: &SelectToStartOfExcerpt,
12068        window: &mut Window,
12069        cx: &mut Context<Self>,
12070    ) {
12071        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12072            cx.propagate();
12073            return;
12074        }
12075        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12076        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12077            s.move_heads_with(|map, head, _| {
12078                (
12079                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12080                    SelectionGoal::None,
12081                )
12082            });
12083        })
12084    }
12085
12086    pub fn select_to_start_of_next_excerpt(
12087        &mut self,
12088        _: &SelectToStartOfNextExcerpt,
12089        window: &mut Window,
12090        cx: &mut Context<Self>,
12091    ) {
12092        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12093            cx.propagate();
12094            return;
12095        }
12096        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12097        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12098            s.move_heads_with(|map, head, _| {
12099                (
12100                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12101                    SelectionGoal::None,
12102                )
12103            });
12104        })
12105    }
12106
12107    pub fn select_to_end_of_excerpt(
12108        &mut self,
12109        _: &SelectToEndOfExcerpt,
12110        window: &mut Window,
12111        cx: &mut Context<Self>,
12112    ) {
12113        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12114            cx.propagate();
12115            return;
12116        }
12117        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12118        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12119            s.move_heads_with(|map, head, _| {
12120                (
12121                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12122                    SelectionGoal::None,
12123                )
12124            });
12125        })
12126    }
12127
12128    pub fn select_to_end_of_previous_excerpt(
12129        &mut self,
12130        _: &SelectToEndOfPreviousExcerpt,
12131        window: &mut Window,
12132        cx: &mut Context<Self>,
12133    ) {
12134        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12135            cx.propagate();
12136            return;
12137        }
12138        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12139        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12140            s.move_heads_with(|map, head, _| {
12141                (
12142                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12143                    SelectionGoal::None,
12144                )
12145            });
12146        })
12147    }
12148
12149    pub fn move_to_beginning(
12150        &mut self,
12151        _: &MoveToBeginning,
12152        window: &mut Window,
12153        cx: &mut Context<Self>,
12154    ) {
12155        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12156            cx.propagate();
12157            return;
12158        }
12159        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12160        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12161            s.select_ranges(vec![0..0]);
12162        });
12163    }
12164
12165    pub fn select_to_beginning(
12166        &mut self,
12167        _: &SelectToBeginning,
12168        window: &mut Window,
12169        cx: &mut Context<Self>,
12170    ) {
12171        let mut selection = self.selections.last::<Point>(cx);
12172        selection.set_head(Point::zero(), SelectionGoal::None);
12173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12174        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12175            s.select(vec![selection]);
12176        });
12177    }
12178
12179    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12180        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12181            cx.propagate();
12182            return;
12183        }
12184        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12185        let cursor = self.buffer.read(cx).read(cx).len();
12186        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12187            s.select_ranges(vec![cursor..cursor])
12188        });
12189    }
12190
12191    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12192        self.nav_history = nav_history;
12193    }
12194
12195    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12196        self.nav_history.as_ref()
12197    }
12198
12199    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12200        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12201    }
12202
12203    fn push_to_nav_history(
12204        &mut self,
12205        cursor_anchor: Anchor,
12206        new_position: Option<Point>,
12207        is_deactivate: bool,
12208        cx: &mut Context<Self>,
12209    ) {
12210        if let Some(nav_history) = self.nav_history.as_mut() {
12211            let buffer = self.buffer.read(cx).read(cx);
12212            let cursor_position = cursor_anchor.to_point(&buffer);
12213            let scroll_state = self.scroll_manager.anchor();
12214            let scroll_top_row = scroll_state.top_row(&buffer);
12215            drop(buffer);
12216
12217            if let Some(new_position) = new_position {
12218                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12219                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12220                    return;
12221                }
12222            }
12223
12224            nav_history.push(
12225                Some(NavigationData {
12226                    cursor_anchor,
12227                    cursor_position,
12228                    scroll_anchor: scroll_state,
12229                    scroll_top_row,
12230                }),
12231                cx,
12232            );
12233            cx.emit(EditorEvent::PushedToNavHistory {
12234                anchor: cursor_anchor,
12235                is_deactivate,
12236            })
12237        }
12238    }
12239
12240    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12241        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12242        let buffer = self.buffer.read(cx).snapshot(cx);
12243        let mut selection = self.selections.first::<usize>(cx);
12244        selection.set_head(buffer.len(), SelectionGoal::None);
12245        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12246            s.select(vec![selection]);
12247        });
12248    }
12249
12250    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12251        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12252        let end = self.buffer.read(cx).read(cx).len();
12253        self.change_selections(None, window, cx, |s| {
12254            s.select_ranges(vec![0..end]);
12255        });
12256    }
12257
12258    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12259        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12261        let mut selections = self.selections.all::<Point>(cx);
12262        let max_point = display_map.buffer_snapshot.max_point();
12263        for selection in &mut selections {
12264            let rows = selection.spanned_rows(true, &display_map);
12265            selection.start = Point::new(rows.start.0, 0);
12266            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12267            selection.reversed = false;
12268        }
12269        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12270            s.select(selections);
12271        });
12272    }
12273
12274    pub fn split_selection_into_lines(
12275        &mut self,
12276        _: &SplitSelectionIntoLines,
12277        window: &mut Window,
12278        cx: &mut Context<Self>,
12279    ) {
12280        let selections = self
12281            .selections
12282            .all::<Point>(cx)
12283            .into_iter()
12284            .map(|selection| selection.start..selection.end)
12285            .collect::<Vec<_>>();
12286        self.unfold_ranges(&selections, true, true, cx);
12287
12288        let mut new_selection_ranges = Vec::new();
12289        {
12290            let buffer = self.buffer.read(cx).read(cx);
12291            for selection in selections {
12292                for row in selection.start.row..selection.end.row {
12293                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12294                    new_selection_ranges.push(cursor..cursor);
12295                }
12296
12297                let is_multiline_selection = selection.start.row != selection.end.row;
12298                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12299                // so this action feels more ergonomic when paired with other selection operations
12300                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12301                if !should_skip_last {
12302                    new_selection_ranges.push(selection.end..selection.end);
12303                }
12304            }
12305        }
12306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12307            s.select_ranges(new_selection_ranges);
12308        });
12309    }
12310
12311    pub fn add_selection_above(
12312        &mut self,
12313        _: &AddSelectionAbove,
12314        window: &mut Window,
12315        cx: &mut Context<Self>,
12316    ) {
12317        self.add_selection(true, window, cx);
12318    }
12319
12320    pub fn add_selection_below(
12321        &mut self,
12322        _: &AddSelectionBelow,
12323        window: &mut Window,
12324        cx: &mut Context<Self>,
12325    ) {
12326        self.add_selection(false, window, cx);
12327    }
12328
12329    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12330        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12331
12332        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12333        let mut selections = self.selections.all::<Point>(cx);
12334        let text_layout_details = self.text_layout_details(window);
12335        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12336            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12337            let range = oldest_selection.display_range(&display_map).sorted();
12338
12339            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12340            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12341            let positions = start_x.min(end_x)..start_x.max(end_x);
12342
12343            selections.clear();
12344            let mut stack = Vec::new();
12345            for row in range.start.row().0..=range.end.row().0 {
12346                if let Some(selection) = self.selections.build_columnar_selection(
12347                    &display_map,
12348                    DisplayRow(row),
12349                    &positions,
12350                    oldest_selection.reversed,
12351                    &text_layout_details,
12352                ) {
12353                    stack.push(selection.id);
12354                    selections.push(selection);
12355                }
12356            }
12357
12358            if above {
12359                stack.reverse();
12360            }
12361
12362            AddSelectionsState { above, stack }
12363        });
12364
12365        let last_added_selection = *state.stack.last().unwrap();
12366        let mut new_selections = Vec::new();
12367        if above == state.above {
12368            let end_row = if above {
12369                DisplayRow(0)
12370            } else {
12371                display_map.max_point().row()
12372            };
12373
12374            'outer: for selection in selections {
12375                if selection.id == last_added_selection {
12376                    let range = selection.display_range(&display_map).sorted();
12377                    debug_assert_eq!(range.start.row(), range.end.row());
12378                    let mut row = range.start.row();
12379                    let positions =
12380                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12381                            px(start)..px(end)
12382                        } else {
12383                            let start_x =
12384                                display_map.x_for_display_point(range.start, &text_layout_details);
12385                            let end_x =
12386                                display_map.x_for_display_point(range.end, &text_layout_details);
12387                            start_x.min(end_x)..start_x.max(end_x)
12388                        };
12389
12390                    while row != end_row {
12391                        if above {
12392                            row.0 -= 1;
12393                        } else {
12394                            row.0 += 1;
12395                        }
12396
12397                        if let Some(new_selection) = self.selections.build_columnar_selection(
12398                            &display_map,
12399                            row,
12400                            &positions,
12401                            selection.reversed,
12402                            &text_layout_details,
12403                        ) {
12404                            state.stack.push(new_selection.id);
12405                            if above {
12406                                new_selections.push(new_selection);
12407                                new_selections.push(selection);
12408                            } else {
12409                                new_selections.push(selection);
12410                                new_selections.push(new_selection);
12411                            }
12412
12413                            continue 'outer;
12414                        }
12415                    }
12416                }
12417
12418                new_selections.push(selection);
12419            }
12420        } else {
12421            new_selections = selections;
12422            new_selections.retain(|s| s.id != last_added_selection);
12423            state.stack.pop();
12424        }
12425
12426        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12427            s.select(new_selections);
12428        });
12429        if state.stack.len() > 1 {
12430            self.add_selections_state = Some(state);
12431        }
12432    }
12433
12434    fn select_match_ranges(
12435        &mut self,
12436        range: Range<usize>,
12437        reversed: bool,
12438        replace_newest: bool,
12439        auto_scroll: Option<Autoscroll>,
12440        window: &mut Window,
12441        cx: &mut Context<Editor>,
12442    ) {
12443        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12444        self.change_selections(auto_scroll, window, cx, |s| {
12445            if replace_newest {
12446                s.delete(s.newest_anchor().id);
12447            }
12448            if reversed {
12449                s.insert_range(range.end..range.start);
12450            } else {
12451                s.insert_range(range);
12452            }
12453        });
12454    }
12455
12456    pub fn select_next_match_internal(
12457        &mut self,
12458        display_map: &DisplaySnapshot,
12459        replace_newest: bool,
12460        autoscroll: Option<Autoscroll>,
12461        window: &mut Window,
12462        cx: &mut Context<Self>,
12463    ) -> Result<()> {
12464        let buffer = &display_map.buffer_snapshot;
12465        let mut selections = self.selections.all::<usize>(cx);
12466        if let Some(mut select_next_state) = self.select_next_state.take() {
12467            let query = &select_next_state.query;
12468            if !select_next_state.done {
12469                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12470                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12471                let mut next_selected_range = None;
12472
12473                let bytes_after_last_selection =
12474                    buffer.bytes_in_range(last_selection.end..buffer.len());
12475                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12476                let query_matches = query
12477                    .stream_find_iter(bytes_after_last_selection)
12478                    .map(|result| (last_selection.end, result))
12479                    .chain(
12480                        query
12481                            .stream_find_iter(bytes_before_first_selection)
12482                            .map(|result| (0, result)),
12483                    );
12484
12485                for (start_offset, query_match) in query_matches {
12486                    let query_match = query_match.unwrap(); // can only fail due to I/O
12487                    let offset_range =
12488                        start_offset + query_match.start()..start_offset + query_match.end();
12489                    let display_range = offset_range.start.to_display_point(display_map)
12490                        ..offset_range.end.to_display_point(display_map);
12491
12492                    if !select_next_state.wordwise
12493                        || (!movement::is_inside_word(display_map, display_range.start)
12494                            && !movement::is_inside_word(display_map, display_range.end))
12495                    {
12496                        // TODO: This is n^2, because we might check all the selections
12497                        if !selections
12498                            .iter()
12499                            .any(|selection| selection.range().overlaps(&offset_range))
12500                        {
12501                            next_selected_range = Some(offset_range);
12502                            break;
12503                        }
12504                    }
12505                }
12506
12507                if let Some(next_selected_range) = next_selected_range {
12508                    self.select_match_ranges(
12509                        next_selected_range,
12510                        last_selection.reversed,
12511                        replace_newest,
12512                        autoscroll,
12513                        window,
12514                        cx,
12515                    );
12516                } else {
12517                    select_next_state.done = true;
12518                }
12519            }
12520
12521            self.select_next_state = Some(select_next_state);
12522        } else {
12523            let mut only_carets = true;
12524            let mut same_text_selected = true;
12525            let mut selected_text = None;
12526
12527            let mut selections_iter = selections.iter().peekable();
12528            while let Some(selection) = selections_iter.next() {
12529                if selection.start != selection.end {
12530                    only_carets = false;
12531                }
12532
12533                if same_text_selected {
12534                    if selected_text.is_none() {
12535                        selected_text =
12536                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12537                    }
12538
12539                    if let Some(next_selection) = selections_iter.peek() {
12540                        if next_selection.range().len() == selection.range().len() {
12541                            let next_selected_text = buffer
12542                                .text_for_range(next_selection.range())
12543                                .collect::<String>();
12544                            if Some(next_selected_text) != selected_text {
12545                                same_text_selected = false;
12546                                selected_text = None;
12547                            }
12548                        } else {
12549                            same_text_selected = false;
12550                            selected_text = None;
12551                        }
12552                    }
12553                }
12554            }
12555
12556            if only_carets {
12557                for selection in &mut selections {
12558                    let word_range = movement::surrounding_word(
12559                        display_map,
12560                        selection.start.to_display_point(display_map),
12561                    );
12562                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12563                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12564                    selection.goal = SelectionGoal::None;
12565                    selection.reversed = false;
12566                    self.select_match_ranges(
12567                        selection.start..selection.end,
12568                        selection.reversed,
12569                        replace_newest,
12570                        autoscroll,
12571                        window,
12572                        cx,
12573                    );
12574                }
12575
12576                if selections.len() == 1 {
12577                    let selection = selections
12578                        .last()
12579                        .expect("ensured that there's only one selection");
12580                    let query = buffer
12581                        .text_for_range(selection.start..selection.end)
12582                        .collect::<String>();
12583                    let is_empty = query.is_empty();
12584                    let select_state = SelectNextState {
12585                        query: AhoCorasick::new(&[query])?,
12586                        wordwise: true,
12587                        done: is_empty,
12588                    };
12589                    self.select_next_state = Some(select_state);
12590                } else {
12591                    self.select_next_state = None;
12592                }
12593            } else if let Some(selected_text) = selected_text {
12594                self.select_next_state = Some(SelectNextState {
12595                    query: AhoCorasick::new(&[selected_text])?,
12596                    wordwise: false,
12597                    done: false,
12598                });
12599                self.select_next_match_internal(
12600                    display_map,
12601                    replace_newest,
12602                    autoscroll,
12603                    window,
12604                    cx,
12605                )?;
12606            }
12607        }
12608        Ok(())
12609    }
12610
12611    pub fn select_all_matches(
12612        &mut self,
12613        _action: &SelectAllMatches,
12614        window: &mut Window,
12615        cx: &mut Context<Self>,
12616    ) -> Result<()> {
12617        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12618
12619        self.push_to_selection_history();
12620        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12621
12622        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12623        let Some(select_next_state) = self.select_next_state.as_mut() else {
12624            return Ok(());
12625        };
12626        if select_next_state.done {
12627            return Ok(());
12628        }
12629
12630        let mut new_selections = Vec::new();
12631
12632        let reversed = self.selections.oldest::<usize>(cx).reversed;
12633        let buffer = &display_map.buffer_snapshot;
12634        let query_matches = select_next_state
12635            .query
12636            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12637
12638        for query_match in query_matches.into_iter() {
12639            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12640            let offset_range = if reversed {
12641                query_match.end()..query_match.start()
12642            } else {
12643                query_match.start()..query_match.end()
12644            };
12645            let display_range = offset_range.start.to_display_point(&display_map)
12646                ..offset_range.end.to_display_point(&display_map);
12647
12648            if !select_next_state.wordwise
12649                || (!movement::is_inside_word(&display_map, display_range.start)
12650                    && !movement::is_inside_word(&display_map, display_range.end))
12651            {
12652                new_selections.push(offset_range.start..offset_range.end);
12653            }
12654        }
12655
12656        select_next_state.done = true;
12657        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12658        self.change_selections(None, window, cx, |selections| {
12659            selections.select_ranges(new_selections)
12660        });
12661
12662        Ok(())
12663    }
12664
12665    pub fn select_next(
12666        &mut self,
12667        action: &SelectNext,
12668        window: &mut Window,
12669        cx: &mut Context<Self>,
12670    ) -> Result<()> {
12671        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12672        self.push_to_selection_history();
12673        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12674        self.select_next_match_internal(
12675            &display_map,
12676            action.replace_newest,
12677            Some(Autoscroll::newest()),
12678            window,
12679            cx,
12680        )?;
12681        Ok(())
12682    }
12683
12684    pub fn select_previous(
12685        &mut self,
12686        action: &SelectPrevious,
12687        window: &mut Window,
12688        cx: &mut Context<Self>,
12689    ) -> Result<()> {
12690        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12691        self.push_to_selection_history();
12692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12693        let buffer = &display_map.buffer_snapshot;
12694        let mut selections = self.selections.all::<usize>(cx);
12695        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12696            let query = &select_prev_state.query;
12697            if !select_prev_state.done {
12698                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12699                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12700                let mut next_selected_range = None;
12701                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12702                let bytes_before_last_selection =
12703                    buffer.reversed_bytes_in_range(0..last_selection.start);
12704                let bytes_after_first_selection =
12705                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12706                let query_matches = query
12707                    .stream_find_iter(bytes_before_last_selection)
12708                    .map(|result| (last_selection.start, result))
12709                    .chain(
12710                        query
12711                            .stream_find_iter(bytes_after_first_selection)
12712                            .map(|result| (buffer.len(), result)),
12713                    );
12714                for (end_offset, query_match) in query_matches {
12715                    let query_match = query_match.unwrap(); // can only fail due to I/O
12716                    let offset_range =
12717                        end_offset - query_match.end()..end_offset - query_match.start();
12718                    let display_range = offset_range.start.to_display_point(&display_map)
12719                        ..offset_range.end.to_display_point(&display_map);
12720
12721                    if !select_prev_state.wordwise
12722                        || (!movement::is_inside_word(&display_map, display_range.start)
12723                            && !movement::is_inside_word(&display_map, display_range.end))
12724                    {
12725                        next_selected_range = Some(offset_range);
12726                        break;
12727                    }
12728                }
12729
12730                if let Some(next_selected_range) = next_selected_range {
12731                    self.select_match_ranges(
12732                        next_selected_range,
12733                        last_selection.reversed,
12734                        action.replace_newest,
12735                        Some(Autoscroll::newest()),
12736                        window,
12737                        cx,
12738                    );
12739                } else {
12740                    select_prev_state.done = true;
12741                }
12742            }
12743
12744            self.select_prev_state = Some(select_prev_state);
12745        } else {
12746            let mut only_carets = true;
12747            let mut same_text_selected = true;
12748            let mut selected_text = None;
12749
12750            let mut selections_iter = selections.iter().peekable();
12751            while let Some(selection) = selections_iter.next() {
12752                if selection.start != selection.end {
12753                    only_carets = false;
12754                }
12755
12756                if same_text_selected {
12757                    if selected_text.is_none() {
12758                        selected_text =
12759                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12760                    }
12761
12762                    if let Some(next_selection) = selections_iter.peek() {
12763                        if next_selection.range().len() == selection.range().len() {
12764                            let next_selected_text = buffer
12765                                .text_for_range(next_selection.range())
12766                                .collect::<String>();
12767                            if Some(next_selected_text) != selected_text {
12768                                same_text_selected = false;
12769                                selected_text = None;
12770                            }
12771                        } else {
12772                            same_text_selected = false;
12773                            selected_text = None;
12774                        }
12775                    }
12776                }
12777            }
12778
12779            if only_carets {
12780                for selection in &mut selections {
12781                    let word_range = movement::surrounding_word(
12782                        &display_map,
12783                        selection.start.to_display_point(&display_map),
12784                    );
12785                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12786                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12787                    selection.goal = SelectionGoal::None;
12788                    selection.reversed = false;
12789                    self.select_match_ranges(
12790                        selection.start..selection.end,
12791                        selection.reversed,
12792                        action.replace_newest,
12793                        Some(Autoscroll::newest()),
12794                        window,
12795                        cx,
12796                    );
12797                }
12798                if selections.len() == 1 {
12799                    let selection = selections
12800                        .last()
12801                        .expect("ensured that there's only one selection");
12802                    let query = buffer
12803                        .text_for_range(selection.start..selection.end)
12804                        .collect::<String>();
12805                    let is_empty = query.is_empty();
12806                    let select_state = SelectNextState {
12807                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12808                        wordwise: true,
12809                        done: is_empty,
12810                    };
12811                    self.select_prev_state = Some(select_state);
12812                } else {
12813                    self.select_prev_state = None;
12814                }
12815            } else if let Some(selected_text) = selected_text {
12816                self.select_prev_state = Some(SelectNextState {
12817                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12818                    wordwise: false,
12819                    done: false,
12820                });
12821                self.select_previous(action, window, cx)?;
12822            }
12823        }
12824        Ok(())
12825    }
12826
12827    pub fn find_next_match(
12828        &mut self,
12829        _: &FindNextMatch,
12830        window: &mut Window,
12831        cx: &mut Context<Self>,
12832    ) -> Result<()> {
12833        let selections = self.selections.disjoint_anchors();
12834        match selections.first() {
12835            Some(first) if selections.len() >= 2 => {
12836                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12837                    s.select_ranges([first.range()]);
12838                });
12839            }
12840            _ => self.select_next(
12841                &SelectNext {
12842                    replace_newest: true,
12843                },
12844                window,
12845                cx,
12846            )?,
12847        }
12848        Ok(())
12849    }
12850
12851    pub fn find_previous_match(
12852        &mut self,
12853        _: &FindPreviousMatch,
12854        window: &mut Window,
12855        cx: &mut Context<Self>,
12856    ) -> Result<()> {
12857        let selections = self.selections.disjoint_anchors();
12858        match selections.last() {
12859            Some(last) if selections.len() >= 2 => {
12860                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12861                    s.select_ranges([last.range()]);
12862                });
12863            }
12864            _ => self.select_previous(
12865                &SelectPrevious {
12866                    replace_newest: true,
12867                },
12868                window,
12869                cx,
12870            )?,
12871        }
12872        Ok(())
12873    }
12874
12875    pub fn toggle_comments(
12876        &mut self,
12877        action: &ToggleComments,
12878        window: &mut Window,
12879        cx: &mut Context<Self>,
12880    ) {
12881        if self.read_only(cx) {
12882            return;
12883        }
12884        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12885        let text_layout_details = &self.text_layout_details(window);
12886        self.transact(window, cx, |this, window, cx| {
12887            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12888            let mut edits = Vec::new();
12889            let mut selection_edit_ranges = Vec::new();
12890            let mut last_toggled_row = None;
12891            let snapshot = this.buffer.read(cx).read(cx);
12892            let empty_str: Arc<str> = Arc::default();
12893            let mut suffixes_inserted = Vec::new();
12894            let ignore_indent = action.ignore_indent;
12895
12896            fn comment_prefix_range(
12897                snapshot: &MultiBufferSnapshot,
12898                row: MultiBufferRow,
12899                comment_prefix: &str,
12900                comment_prefix_whitespace: &str,
12901                ignore_indent: bool,
12902            ) -> Range<Point> {
12903                let indent_size = if ignore_indent {
12904                    0
12905                } else {
12906                    snapshot.indent_size_for_line(row).len
12907                };
12908
12909                let start = Point::new(row.0, indent_size);
12910
12911                let mut line_bytes = snapshot
12912                    .bytes_in_range(start..snapshot.max_point())
12913                    .flatten()
12914                    .copied();
12915
12916                // If this line currently begins with the line comment prefix, then record
12917                // the range containing the prefix.
12918                if line_bytes
12919                    .by_ref()
12920                    .take(comment_prefix.len())
12921                    .eq(comment_prefix.bytes())
12922                {
12923                    // Include any whitespace that matches the comment prefix.
12924                    let matching_whitespace_len = line_bytes
12925                        .zip(comment_prefix_whitespace.bytes())
12926                        .take_while(|(a, b)| a == b)
12927                        .count() as u32;
12928                    let end = Point::new(
12929                        start.row,
12930                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12931                    );
12932                    start..end
12933                } else {
12934                    start..start
12935                }
12936            }
12937
12938            fn comment_suffix_range(
12939                snapshot: &MultiBufferSnapshot,
12940                row: MultiBufferRow,
12941                comment_suffix: &str,
12942                comment_suffix_has_leading_space: bool,
12943            ) -> Range<Point> {
12944                let end = Point::new(row.0, snapshot.line_len(row));
12945                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12946
12947                let mut line_end_bytes = snapshot
12948                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12949                    .flatten()
12950                    .copied();
12951
12952                let leading_space_len = if suffix_start_column > 0
12953                    && line_end_bytes.next() == Some(b' ')
12954                    && comment_suffix_has_leading_space
12955                {
12956                    1
12957                } else {
12958                    0
12959                };
12960
12961                // If this line currently begins with the line comment prefix, then record
12962                // the range containing the prefix.
12963                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12964                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12965                    start..end
12966                } else {
12967                    end..end
12968                }
12969            }
12970
12971            // TODO: Handle selections that cross excerpts
12972            for selection in &mut selections {
12973                let start_column = snapshot
12974                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12975                    .len;
12976                let language = if let Some(language) =
12977                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12978                {
12979                    language
12980                } else {
12981                    continue;
12982                };
12983
12984                selection_edit_ranges.clear();
12985
12986                // If multiple selections contain a given row, avoid processing that
12987                // row more than once.
12988                let mut start_row = MultiBufferRow(selection.start.row);
12989                if last_toggled_row == Some(start_row) {
12990                    start_row = start_row.next_row();
12991                }
12992                let end_row =
12993                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12994                        MultiBufferRow(selection.end.row - 1)
12995                    } else {
12996                        MultiBufferRow(selection.end.row)
12997                    };
12998                last_toggled_row = Some(end_row);
12999
13000                if start_row > end_row {
13001                    continue;
13002                }
13003
13004                // If the language has line comments, toggle those.
13005                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13006
13007                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13008                if ignore_indent {
13009                    full_comment_prefixes = full_comment_prefixes
13010                        .into_iter()
13011                        .map(|s| Arc::from(s.trim_end()))
13012                        .collect();
13013                }
13014
13015                if !full_comment_prefixes.is_empty() {
13016                    let first_prefix = full_comment_prefixes
13017                        .first()
13018                        .expect("prefixes is non-empty");
13019                    let prefix_trimmed_lengths = full_comment_prefixes
13020                        .iter()
13021                        .map(|p| p.trim_end_matches(' ').len())
13022                        .collect::<SmallVec<[usize; 4]>>();
13023
13024                    let mut all_selection_lines_are_comments = true;
13025
13026                    for row in start_row.0..=end_row.0 {
13027                        let row = MultiBufferRow(row);
13028                        if start_row < end_row && snapshot.is_line_blank(row) {
13029                            continue;
13030                        }
13031
13032                        let prefix_range = full_comment_prefixes
13033                            .iter()
13034                            .zip(prefix_trimmed_lengths.iter().copied())
13035                            .map(|(prefix, trimmed_prefix_len)| {
13036                                comment_prefix_range(
13037                                    snapshot.deref(),
13038                                    row,
13039                                    &prefix[..trimmed_prefix_len],
13040                                    &prefix[trimmed_prefix_len..],
13041                                    ignore_indent,
13042                                )
13043                            })
13044                            .max_by_key(|range| range.end.column - range.start.column)
13045                            .expect("prefixes is non-empty");
13046
13047                        if prefix_range.is_empty() {
13048                            all_selection_lines_are_comments = false;
13049                        }
13050
13051                        selection_edit_ranges.push(prefix_range);
13052                    }
13053
13054                    if all_selection_lines_are_comments {
13055                        edits.extend(
13056                            selection_edit_ranges
13057                                .iter()
13058                                .cloned()
13059                                .map(|range| (range, empty_str.clone())),
13060                        );
13061                    } else {
13062                        let min_column = selection_edit_ranges
13063                            .iter()
13064                            .map(|range| range.start.column)
13065                            .min()
13066                            .unwrap_or(0);
13067                        edits.extend(selection_edit_ranges.iter().map(|range| {
13068                            let position = Point::new(range.start.row, min_column);
13069                            (position..position, first_prefix.clone())
13070                        }));
13071                    }
13072                } else if let Some((full_comment_prefix, comment_suffix)) =
13073                    language.block_comment_delimiters()
13074                {
13075                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13076                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13077                    let prefix_range = comment_prefix_range(
13078                        snapshot.deref(),
13079                        start_row,
13080                        comment_prefix,
13081                        comment_prefix_whitespace,
13082                        ignore_indent,
13083                    );
13084                    let suffix_range = comment_suffix_range(
13085                        snapshot.deref(),
13086                        end_row,
13087                        comment_suffix.trim_start_matches(' '),
13088                        comment_suffix.starts_with(' '),
13089                    );
13090
13091                    if prefix_range.is_empty() || suffix_range.is_empty() {
13092                        edits.push((
13093                            prefix_range.start..prefix_range.start,
13094                            full_comment_prefix.clone(),
13095                        ));
13096                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13097                        suffixes_inserted.push((end_row, comment_suffix.len()));
13098                    } else {
13099                        edits.push((prefix_range, empty_str.clone()));
13100                        edits.push((suffix_range, empty_str.clone()));
13101                    }
13102                } else {
13103                    continue;
13104                }
13105            }
13106
13107            drop(snapshot);
13108            this.buffer.update(cx, |buffer, cx| {
13109                buffer.edit(edits, None, cx);
13110            });
13111
13112            // Adjust selections so that they end before any comment suffixes that
13113            // were inserted.
13114            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13115            let mut selections = this.selections.all::<Point>(cx);
13116            let snapshot = this.buffer.read(cx).read(cx);
13117            for selection in &mut selections {
13118                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13119                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13120                        Ordering::Less => {
13121                            suffixes_inserted.next();
13122                            continue;
13123                        }
13124                        Ordering::Greater => break,
13125                        Ordering::Equal => {
13126                            if selection.end.column == snapshot.line_len(row) {
13127                                if selection.is_empty() {
13128                                    selection.start.column -= suffix_len as u32;
13129                                }
13130                                selection.end.column -= suffix_len as u32;
13131                            }
13132                            break;
13133                        }
13134                    }
13135                }
13136            }
13137
13138            drop(snapshot);
13139            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13140                s.select(selections)
13141            });
13142
13143            let selections = this.selections.all::<Point>(cx);
13144            let selections_on_single_row = selections.windows(2).all(|selections| {
13145                selections[0].start.row == selections[1].start.row
13146                    && selections[0].end.row == selections[1].end.row
13147                    && selections[0].start.row == selections[0].end.row
13148            });
13149            let selections_selecting = selections
13150                .iter()
13151                .any(|selection| selection.start != selection.end);
13152            let advance_downwards = action.advance_downwards
13153                && selections_on_single_row
13154                && !selections_selecting
13155                && !matches!(this.mode, EditorMode::SingleLine { .. });
13156
13157            if advance_downwards {
13158                let snapshot = this.buffer.read(cx).snapshot(cx);
13159
13160                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13161                    s.move_cursors_with(|display_snapshot, display_point, _| {
13162                        let mut point = display_point.to_point(display_snapshot);
13163                        point.row += 1;
13164                        point = snapshot.clip_point(point, Bias::Left);
13165                        let display_point = point.to_display_point(display_snapshot);
13166                        let goal = SelectionGoal::HorizontalPosition(
13167                            display_snapshot
13168                                .x_for_display_point(display_point, text_layout_details)
13169                                .into(),
13170                        );
13171                        (display_point, goal)
13172                    })
13173                });
13174            }
13175        });
13176    }
13177
13178    pub fn select_enclosing_symbol(
13179        &mut self,
13180        _: &SelectEnclosingSymbol,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13185
13186        let buffer = self.buffer.read(cx).snapshot(cx);
13187        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13188
13189        fn update_selection(
13190            selection: &Selection<usize>,
13191            buffer_snap: &MultiBufferSnapshot,
13192        ) -> Option<Selection<usize>> {
13193            let cursor = selection.head();
13194            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13195            for symbol in symbols.iter().rev() {
13196                let start = symbol.range.start.to_offset(buffer_snap);
13197                let end = symbol.range.end.to_offset(buffer_snap);
13198                let new_range = start..end;
13199                if start < selection.start || end > selection.end {
13200                    return Some(Selection {
13201                        id: selection.id,
13202                        start: new_range.start,
13203                        end: new_range.end,
13204                        goal: SelectionGoal::None,
13205                        reversed: selection.reversed,
13206                    });
13207                }
13208            }
13209            None
13210        }
13211
13212        let mut selected_larger_symbol = false;
13213        let new_selections = old_selections
13214            .iter()
13215            .map(|selection| match update_selection(selection, &buffer) {
13216                Some(new_selection) => {
13217                    if new_selection.range() != selection.range() {
13218                        selected_larger_symbol = true;
13219                    }
13220                    new_selection
13221                }
13222                None => selection.clone(),
13223            })
13224            .collect::<Vec<_>>();
13225
13226        if selected_larger_symbol {
13227            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13228                s.select(new_selections);
13229            });
13230        }
13231    }
13232
13233    pub fn select_larger_syntax_node(
13234        &mut self,
13235        _: &SelectLargerSyntaxNode,
13236        window: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        let Some(visible_row_count) = self.visible_row_count() else {
13240            return;
13241        };
13242        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13243        if old_selections.is_empty() {
13244            return;
13245        }
13246
13247        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13248
13249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13250        let buffer = self.buffer.read(cx).snapshot(cx);
13251
13252        let mut selected_larger_node = false;
13253        let mut new_selections = old_selections
13254            .iter()
13255            .map(|selection| {
13256                let old_range = selection.start..selection.end;
13257
13258                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13259                    // manually select word at selection
13260                    if ["string_content", "inline"].contains(&node.kind()) {
13261                        let word_range = {
13262                            let display_point = buffer
13263                                .offset_to_point(old_range.start)
13264                                .to_display_point(&display_map);
13265                            let Range { start, end } =
13266                                movement::surrounding_word(&display_map, display_point);
13267                            start.to_point(&display_map).to_offset(&buffer)
13268                                ..end.to_point(&display_map).to_offset(&buffer)
13269                        };
13270                        // ignore if word is already selected
13271                        if !word_range.is_empty() && old_range != word_range {
13272                            let last_word_range = {
13273                                let display_point = buffer
13274                                    .offset_to_point(old_range.end)
13275                                    .to_display_point(&display_map);
13276                                let Range { start, end } =
13277                                    movement::surrounding_word(&display_map, display_point);
13278                                start.to_point(&display_map).to_offset(&buffer)
13279                                    ..end.to_point(&display_map).to_offset(&buffer)
13280                            };
13281                            // only select word if start and end point belongs to same word
13282                            if word_range == last_word_range {
13283                                selected_larger_node = true;
13284                                return Selection {
13285                                    id: selection.id,
13286                                    start: word_range.start,
13287                                    end: word_range.end,
13288                                    goal: SelectionGoal::None,
13289                                    reversed: selection.reversed,
13290                                };
13291                            }
13292                        }
13293                    }
13294                }
13295
13296                let mut new_range = old_range.clone();
13297                while let Some((_node, containing_range)) =
13298                    buffer.syntax_ancestor(new_range.clone())
13299                {
13300                    new_range = match containing_range {
13301                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13302                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13303                    };
13304                    if !display_map.intersects_fold(new_range.start)
13305                        && !display_map.intersects_fold(new_range.end)
13306                    {
13307                        break;
13308                    }
13309                }
13310
13311                selected_larger_node |= new_range != old_range;
13312                Selection {
13313                    id: selection.id,
13314                    start: new_range.start,
13315                    end: new_range.end,
13316                    goal: SelectionGoal::None,
13317                    reversed: selection.reversed,
13318                }
13319            })
13320            .collect::<Vec<_>>();
13321
13322        if !selected_larger_node {
13323            return; // don't put this call in the history
13324        }
13325
13326        // scroll based on transformation done to the last selection created by the user
13327        let (last_old, last_new) = old_selections
13328            .last()
13329            .zip(new_selections.last().cloned())
13330            .expect("old_selections isn't empty");
13331
13332        // revert selection
13333        let is_selection_reversed = {
13334            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13335            new_selections.last_mut().expect("checked above").reversed =
13336                should_newest_selection_be_reversed;
13337            should_newest_selection_be_reversed
13338        };
13339
13340        if selected_larger_node {
13341            self.select_syntax_node_history.disable_clearing = true;
13342            self.change_selections(None, window, cx, |s| {
13343                s.select(new_selections.clone());
13344            });
13345            self.select_syntax_node_history.disable_clearing = false;
13346        }
13347
13348        let start_row = last_new.start.to_display_point(&display_map).row().0;
13349        let end_row = last_new.end.to_display_point(&display_map).row().0;
13350        let selection_height = end_row - start_row + 1;
13351        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13352
13353        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13354        let scroll_behavior = if fits_on_the_screen {
13355            self.request_autoscroll(Autoscroll::fit(), cx);
13356            SelectSyntaxNodeScrollBehavior::FitSelection
13357        } else if is_selection_reversed {
13358            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13359            SelectSyntaxNodeScrollBehavior::CursorTop
13360        } else {
13361            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13362            SelectSyntaxNodeScrollBehavior::CursorBottom
13363        };
13364
13365        self.select_syntax_node_history.push((
13366            old_selections,
13367            scroll_behavior,
13368            is_selection_reversed,
13369        ));
13370    }
13371
13372    pub fn select_smaller_syntax_node(
13373        &mut self,
13374        _: &SelectSmallerSyntaxNode,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13379
13380        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13381            self.select_syntax_node_history.pop()
13382        {
13383            if let Some(selection) = selections.last_mut() {
13384                selection.reversed = is_selection_reversed;
13385            }
13386
13387            self.select_syntax_node_history.disable_clearing = true;
13388            self.change_selections(None, window, cx, |s| {
13389                s.select(selections.to_vec());
13390            });
13391            self.select_syntax_node_history.disable_clearing = false;
13392
13393            match scroll_behavior {
13394                SelectSyntaxNodeScrollBehavior::CursorTop => {
13395                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13396                }
13397                SelectSyntaxNodeScrollBehavior::FitSelection => {
13398                    self.request_autoscroll(Autoscroll::fit(), cx);
13399                }
13400                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13401                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13402                }
13403            }
13404        }
13405    }
13406
13407    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13408        if !EditorSettings::get_global(cx).gutter.runnables {
13409            self.clear_tasks();
13410            return Task::ready(());
13411        }
13412        let project = self.project.as_ref().map(Entity::downgrade);
13413        let task_sources = self.lsp_task_sources(cx);
13414        cx.spawn_in(window, async move |editor, cx| {
13415            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13416            let Some(project) = project.and_then(|p| p.upgrade()) else {
13417                return;
13418            };
13419            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13420                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13421            }) else {
13422                return;
13423            };
13424
13425            let hide_runnables = project
13426                .update(cx, |project, cx| {
13427                    // Do not display any test indicators in non-dev server remote projects.
13428                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13429                })
13430                .unwrap_or(true);
13431            if hide_runnables {
13432                return;
13433            }
13434            let new_rows =
13435                cx.background_spawn({
13436                    let snapshot = display_snapshot.clone();
13437                    async move {
13438                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13439                    }
13440                })
13441                    .await;
13442            let Ok(lsp_tasks) =
13443                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13444            else {
13445                return;
13446            };
13447            let lsp_tasks = lsp_tasks.await;
13448
13449            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13450                lsp_tasks
13451                    .into_iter()
13452                    .flat_map(|(kind, tasks)| {
13453                        tasks.into_iter().filter_map(move |(location, task)| {
13454                            Some((kind.clone(), location?, task))
13455                        })
13456                    })
13457                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13458                        let buffer = location.target.buffer;
13459                        let buffer_snapshot = buffer.read(cx).snapshot();
13460                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13461                            |(excerpt_id, snapshot, _)| {
13462                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13463                                    display_snapshot
13464                                        .buffer_snapshot
13465                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13466                                } else {
13467                                    None
13468                                }
13469                            },
13470                        );
13471                        if let Some(offset) = offset {
13472                            let task_buffer_range =
13473                                location.target.range.to_point(&buffer_snapshot);
13474                            let context_buffer_range =
13475                                task_buffer_range.to_offset(&buffer_snapshot);
13476                            let context_range = BufferOffset(context_buffer_range.start)
13477                                ..BufferOffset(context_buffer_range.end);
13478
13479                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13480                                .or_insert_with(|| RunnableTasks {
13481                                    templates: Vec::new(),
13482                                    offset,
13483                                    column: task_buffer_range.start.column,
13484                                    extra_variables: HashMap::default(),
13485                                    context_range,
13486                                })
13487                                .templates
13488                                .push((kind, task.original_task().clone()));
13489                        }
13490
13491                        acc
13492                    })
13493            }) else {
13494                return;
13495            };
13496
13497            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13498            editor
13499                .update(cx, |editor, _| {
13500                    editor.clear_tasks();
13501                    for (key, mut value) in rows {
13502                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13503                            value.templates.extend(lsp_tasks.templates);
13504                        }
13505
13506                        editor.insert_tasks(key, value);
13507                    }
13508                    for (key, value) in lsp_tasks_by_rows {
13509                        editor.insert_tasks(key, value);
13510                    }
13511                })
13512                .ok();
13513        })
13514    }
13515    fn fetch_runnable_ranges(
13516        snapshot: &DisplaySnapshot,
13517        range: Range<Anchor>,
13518    ) -> Vec<language::RunnableRange> {
13519        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13520    }
13521
13522    fn runnable_rows(
13523        project: Entity<Project>,
13524        snapshot: DisplaySnapshot,
13525        runnable_ranges: Vec<RunnableRange>,
13526        mut cx: AsyncWindowContext,
13527    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13528        runnable_ranges
13529            .into_iter()
13530            .filter_map(|mut runnable| {
13531                let tasks = cx
13532                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13533                    .ok()?;
13534                if tasks.is_empty() {
13535                    return None;
13536                }
13537
13538                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13539
13540                let row = snapshot
13541                    .buffer_snapshot
13542                    .buffer_line_for_row(MultiBufferRow(point.row))?
13543                    .1
13544                    .start
13545                    .row;
13546
13547                let context_range =
13548                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13549                Some((
13550                    (runnable.buffer_id, row),
13551                    RunnableTasks {
13552                        templates: tasks,
13553                        offset: snapshot
13554                            .buffer_snapshot
13555                            .anchor_before(runnable.run_range.start),
13556                        context_range,
13557                        column: point.column,
13558                        extra_variables: runnable.extra_captures,
13559                    },
13560                ))
13561            })
13562            .collect()
13563    }
13564
13565    fn templates_with_tags(
13566        project: &Entity<Project>,
13567        runnable: &mut Runnable,
13568        cx: &mut App,
13569    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13570        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13571            let (worktree_id, file) = project
13572                .buffer_for_id(runnable.buffer, cx)
13573                .and_then(|buffer| buffer.read(cx).file())
13574                .map(|file| (file.worktree_id(cx), file.clone()))
13575                .unzip();
13576
13577            (
13578                project.task_store().read(cx).task_inventory().cloned(),
13579                worktree_id,
13580                file,
13581            )
13582        });
13583
13584        let mut templates_with_tags = mem::take(&mut runnable.tags)
13585            .into_iter()
13586            .flat_map(|RunnableTag(tag)| {
13587                inventory
13588                    .as_ref()
13589                    .into_iter()
13590                    .flat_map(|inventory| {
13591                        inventory.read(cx).list_tasks(
13592                            file.clone(),
13593                            Some(runnable.language.clone()),
13594                            worktree_id,
13595                            cx,
13596                        )
13597                    })
13598                    .filter(move |(_, template)| {
13599                        template.tags.iter().any(|source_tag| source_tag == &tag)
13600                    })
13601            })
13602            .sorted_by_key(|(kind, _)| kind.to_owned())
13603            .collect::<Vec<_>>();
13604        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13605            // Strongest source wins; if we have worktree tag binding, prefer that to
13606            // global and language bindings;
13607            // if we have a global binding, prefer that to language binding.
13608            let first_mismatch = templates_with_tags
13609                .iter()
13610                .position(|(tag_source, _)| tag_source != leading_tag_source);
13611            if let Some(index) = first_mismatch {
13612                templates_with_tags.truncate(index);
13613            }
13614        }
13615
13616        templates_with_tags
13617    }
13618
13619    pub fn move_to_enclosing_bracket(
13620        &mut self,
13621        _: &MoveToEnclosingBracket,
13622        window: &mut Window,
13623        cx: &mut Context<Self>,
13624    ) {
13625        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13626        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13627            s.move_offsets_with(|snapshot, selection| {
13628                let Some(enclosing_bracket_ranges) =
13629                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13630                else {
13631                    return;
13632                };
13633
13634                let mut best_length = usize::MAX;
13635                let mut best_inside = false;
13636                let mut best_in_bracket_range = false;
13637                let mut best_destination = None;
13638                for (open, close) in enclosing_bracket_ranges {
13639                    let close = close.to_inclusive();
13640                    let length = close.end() - open.start;
13641                    let inside = selection.start >= open.end && selection.end <= *close.start();
13642                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13643                        || close.contains(&selection.head());
13644
13645                    // If best is next to a bracket and current isn't, skip
13646                    if !in_bracket_range && best_in_bracket_range {
13647                        continue;
13648                    }
13649
13650                    // Prefer smaller lengths unless best is inside and current isn't
13651                    if length > best_length && (best_inside || !inside) {
13652                        continue;
13653                    }
13654
13655                    best_length = length;
13656                    best_inside = inside;
13657                    best_in_bracket_range = in_bracket_range;
13658                    best_destination = Some(
13659                        if close.contains(&selection.start) && close.contains(&selection.end) {
13660                            if inside { open.end } else { open.start }
13661                        } else if inside {
13662                            *close.start()
13663                        } else {
13664                            *close.end()
13665                        },
13666                    );
13667                }
13668
13669                if let Some(destination) = best_destination {
13670                    selection.collapse_to(destination, SelectionGoal::None);
13671                }
13672            })
13673        });
13674    }
13675
13676    pub fn undo_selection(
13677        &mut self,
13678        _: &UndoSelection,
13679        window: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13683        self.end_selection(window, cx);
13684        self.selection_history.mode = SelectionHistoryMode::Undoing;
13685        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13686            self.change_selections(None, window, cx, |s| {
13687                s.select_anchors(entry.selections.to_vec())
13688            });
13689            self.select_next_state = entry.select_next_state;
13690            self.select_prev_state = entry.select_prev_state;
13691            self.add_selections_state = entry.add_selections_state;
13692            self.request_autoscroll(Autoscroll::newest(), cx);
13693        }
13694        self.selection_history.mode = SelectionHistoryMode::Normal;
13695    }
13696
13697    pub fn redo_selection(
13698        &mut self,
13699        _: &RedoSelection,
13700        window: &mut Window,
13701        cx: &mut Context<Self>,
13702    ) {
13703        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13704        self.end_selection(window, cx);
13705        self.selection_history.mode = SelectionHistoryMode::Redoing;
13706        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13707            self.change_selections(None, window, cx, |s| {
13708                s.select_anchors(entry.selections.to_vec())
13709            });
13710            self.select_next_state = entry.select_next_state;
13711            self.select_prev_state = entry.select_prev_state;
13712            self.add_selections_state = entry.add_selections_state;
13713            self.request_autoscroll(Autoscroll::newest(), cx);
13714        }
13715        self.selection_history.mode = SelectionHistoryMode::Normal;
13716    }
13717
13718    pub fn expand_excerpts(
13719        &mut self,
13720        action: &ExpandExcerpts,
13721        _: &mut Window,
13722        cx: &mut Context<Self>,
13723    ) {
13724        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13725    }
13726
13727    pub fn expand_excerpts_down(
13728        &mut self,
13729        action: &ExpandExcerptsDown,
13730        _: &mut Window,
13731        cx: &mut Context<Self>,
13732    ) {
13733        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13734    }
13735
13736    pub fn expand_excerpts_up(
13737        &mut self,
13738        action: &ExpandExcerptsUp,
13739        _: &mut Window,
13740        cx: &mut Context<Self>,
13741    ) {
13742        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13743    }
13744
13745    pub fn expand_excerpts_for_direction(
13746        &mut self,
13747        lines: u32,
13748        direction: ExpandExcerptDirection,
13749
13750        cx: &mut Context<Self>,
13751    ) {
13752        let selections = self.selections.disjoint_anchors();
13753
13754        let lines = if lines == 0 {
13755            EditorSettings::get_global(cx).expand_excerpt_lines
13756        } else {
13757            lines
13758        };
13759
13760        self.buffer.update(cx, |buffer, cx| {
13761            let snapshot = buffer.snapshot(cx);
13762            let mut excerpt_ids = selections
13763                .iter()
13764                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13765                .collect::<Vec<_>>();
13766            excerpt_ids.sort();
13767            excerpt_ids.dedup();
13768            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13769        })
13770    }
13771
13772    pub fn expand_excerpt(
13773        &mut self,
13774        excerpt: ExcerptId,
13775        direction: ExpandExcerptDirection,
13776        window: &mut Window,
13777        cx: &mut Context<Self>,
13778    ) {
13779        let current_scroll_position = self.scroll_position(cx);
13780        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13781        let mut should_scroll_up = false;
13782
13783        if direction == ExpandExcerptDirection::Down {
13784            let multi_buffer = self.buffer.read(cx);
13785            let snapshot = multi_buffer.snapshot(cx);
13786            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13787                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13788                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13789                        let buffer_snapshot = buffer.read(cx).snapshot();
13790                        let excerpt_end_row =
13791                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13792                        let last_row = buffer_snapshot.max_point().row;
13793                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13794                        should_scroll_up = lines_below >= lines_to_expand;
13795                    }
13796                }
13797            }
13798        }
13799
13800        self.buffer.update(cx, |buffer, cx| {
13801            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13802        });
13803
13804        if should_scroll_up {
13805            let new_scroll_position =
13806                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13807            self.set_scroll_position(new_scroll_position, window, cx);
13808        }
13809    }
13810
13811    pub fn go_to_singleton_buffer_point(
13812        &mut self,
13813        point: Point,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        self.go_to_singleton_buffer_range(point..point, window, cx);
13818    }
13819
13820    pub fn go_to_singleton_buffer_range(
13821        &mut self,
13822        range: Range<Point>,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) {
13826        let multibuffer = self.buffer().read(cx);
13827        let Some(buffer) = multibuffer.as_singleton() else {
13828            return;
13829        };
13830        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13831            return;
13832        };
13833        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13834            return;
13835        };
13836        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13837            s.select_anchor_ranges([start..end])
13838        });
13839    }
13840
13841    pub fn go_to_diagnostic(
13842        &mut self,
13843        _: &GoToDiagnostic,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13848        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13849    }
13850
13851    pub fn go_to_prev_diagnostic(
13852        &mut self,
13853        _: &GoToPreviousDiagnostic,
13854        window: &mut Window,
13855        cx: &mut Context<Self>,
13856    ) {
13857        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13858        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13859    }
13860
13861    pub fn go_to_diagnostic_impl(
13862        &mut self,
13863        direction: Direction,
13864        window: &mut Window,
13865        cx: &mut Context<Self>,
13866    ) {
13867        let buffer = self.buffer.read(cx).snapshot(cx);
13868        let selection = self.selections.newest::<usize>(cx);
13869
13870        let mut active_group_id = None;
13871        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13872            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13873                active_group_id = Some(active_group.group_id);
13874            }
13875        }
13876
13877        fn filtered(
13878            snapshot: EditorSnapshot,
13879            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13880        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13881            diagnostics
13882                .filter(|entry| entry.range.start != entry.range.end)
13883                .filter(|entry| !entry.diagnostic.is_unnecessary)
13884                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13885        }
13886
13887        let snapshot = self.snapshot(window, cx);
13888        let before = filtered(
13889            snapshot.clone(),
13890            buffer
13891                .diagnostics_in_range(0..selection.start)
13892                .filter(|entry| entry.range.start <= selection.start),
13893        );
13894        let after = filtered(
13895            snapshot,
13896            buffer
13897                .diagnostics_in_range(selection.start..buffer.len())
13898                .filter(|entry| entry.range.start >= selection.start),
13899        );
13900
13901        let mut found: Option<DiagnosticEntry<usize>> = None;
13902        if direction == Direction::Prev {
13903            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13904            {
13905                for diagnostic in prev_diagnostics.into_iter().rev() {
13906                    if diagnostic.range.start != selection.start
13907                        || active_group_id
13908                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13909                    {
13910                        found = Some(diagnostic);
13911                        break 'outer;
13912                    }
13913                }
13914            }
13915        } else {
13916            for diagnostic in after.chain(before) {
13917                if diagnostic.range.start != selection.start
13918                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13919                {
13920                    found = Some(diagnostic);
13921                    break;
13922                }
13923            }
13924        }
13925        let Some(next_diagnostic) = found else {
13926            return;
13927        };
13928
13929        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13930            return;
13931        };
13932        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13933            s.select_ranges(vec![
13934                next_diagnostic.range.start..next_diagnostic.range.start,
13935            ])
13936        });
13937        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13938        self.refresh_inline_completion(false, true, window, cx);
13939    }
13940
13941    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13942        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13943        let snapshot = self.snapshot(window, cx);
13944        let selection = self.selections.newest::<Point>(cx);
13945        self.go_to_hunk_before_or_after_position(
13946            &snapshot,
13947            selection.head(),
13948            Direction::Next,
13949            window,
13950            cx,
13951        );
13952    }
13953
13954    pub fn go_to_hunk_before_or_after_position(
13955        &mut self,
13956        snapshot: &EditorSnapshot,
13957        position: Point,
13958        direction: Direction,
13959        window: &mut Window,
13960        cx: &mut Context<Editor>,
13961    ) {
13962        let row = if direction == Direction::Next {
13963            self.hunk_after_position(snapshot, position)
13964                .map(|hunk| hunk.row_range.start)
13965        } else {
13966            self.hunk_before_position(snapshot, position)
13967        };
13968
13969        if let Some(row) = row {
13970            let destination = Point::new(row.0, 0);
13971            let autoscroll = Autoscroll::center();
13972
13973            self.unfold_ranges(&[destination..destination], false, false, cx);
13974            self.change_selections(Some(autoscroll), window, cx, |s| {
13975                s.select_ranges([destination..destination]);
13976            });
13977        }
13978    }
13979
13980    fn hunk_after_position(
13981        &mut self,
13982        snapshot: &EditorSnapshot,
13983        position: Point,
13984    ) -> Option<MultiBufferDiffHunk> {
13985        snapshot
13986            .buffer_snapshot
13987            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13988            .find(|hunk| hunk.row_range.start.0 > position.row)
13989            .or_else(|| {
13990                snapshot
13991                    .buffer_snapshot
13992                    .diff_hunks_in_range(Point::zero()..position)
13993                    .find(|hunk| hunk.row_range.end.0 < position.row)
13994            })
13995    }
13996
13997    fn go_to_prev_hunk(
13998        &mut self,
13999        _: &GoToPreviousHunk,
14000        window: &mut Window,
14001        cx: &mut Context<Self>,
14002    ) {
14003        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14004        let snapshot = self.snapshot(window, cx);
14005        let selection = self.selections.newest::<Point>(cx);
14006        self.go_to_hunk_before_or_after_position(
14007            &snapshot,
14008            selection.head(),
14009            Direction::Prev,
14010            window,
14011            cx,
14012        );
14013    }
14014
14015    fn hunk_before_position(
14016        &mut self,
14017        snapshot: &EditorSnapshot,
14018        position: Point,
14019    ) -> Option<MultiBufferRow> {
14020        snapshot
14021            .buffer_snapshot
14022            .diff_hunk_before(position)
14023            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14024    }
14025
14026    fn go_to_next_change(
14027        &mut self,
14028        _: &GoToNextChange,
14029        window: &mut Window,
14030        cx: &mut Context<Self>,
14031    ) {
14032        if let Some(selections) = self
14033            .change_list
14034            .next_change(1, Direction::Next)
14035            .map(|s| s.to_vec())
14036        {
14037            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14038                let map = s.display_map();
14039                s.select_display_ranges(selections.iter().map(|a| {
14040                    let point = a.to_display_point(&map);
14041                    point..point
14042                }))
14043            })
14044        }
14045    }
14046
14047    fn go_to_previous_change(
14048        &mut self,
14049        _: &GoToPreviousChange,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        if let Some(selections) = self
14054            .change_list
14055            .next_change(1, Direction::Prev)
14056            .map(|s| s.to_vec())
14057        {
14058            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14059                let map = s.display_map();
14060                s.select_display_ranges(selections.iter().map(|a| {
14061                    let point = a.to_display_point(&map);
14062                    point..point
14063                }))
14064            })
14065        }
14066    }
14067
14068    fn go_to_line<T: 'static>(
14069        &mut self,
14070        position: Anchor,
14071        highlight_color: Option<Hsla>,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        let snapshot = self.snapshot(window, cx).display_snapshot;
14076        let position = position.to_point(&snapshot.buffer_snapshot);
14077        let start = snapshot
14078            .buffer_snapshot
14079            .clip_point(Point::new(position.row, 0), Bias::Left);
14080        let end = start + Point::new(1, 0);
14081        let start = snapshot.buffer_snapshot.anchor_before(start);
14082        let end = snapshot.buffer_snapshot.anchor_before(end);
14083
14084        self.highlight_rows::<T>(
14085            start..end,
14086            highlight_color
14087                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14088            Default::default(),
14089            cx,
14090        );
14091
14092        if self.buffer.read(cx).is_singleton() {
14093            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14094        }
14095    }
14096
14097    pub fn go_to_definition(
14098        &mut self,
14099        _: &GoToDefinition,
14100        window: &mut Window,
14101        cx: &mut Context<Self>,
14102    ) -> Task<Result<Navigated>> {
14103        let definition =
14104            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14105        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14106        cx.spawn_in(window, async move |editor, cx| {
14107            if definition.await? == Navigated::Yes {
14108                return Ok(Navigated::Yes);
14109            }
14110            match fallback_strategy {
14111                GoToDefinitionFallback::None => Ok(Navigated::No),
14112                GoToDefinitionFallback::FindAllReferences => {
14113                    match editor.update_in(cx, |editor, window, cx| {
14114                        editor.find_all_references(&FindAllReferences, window, cx)
14115                    })? {
14116                        Some(references) => references.await,
14117                        None => Ok(Navigated::No),
14118                    }
14119                }
14120            }
14121        })
14122    }
14123
14124    pub fn go_to_declaration(
14125        &mut self,
14126        _: &GoToDeclaration,
14127        window: &mut Window,
14128        cx: &mut Context<Self>,
14129    ) -> Task<Result<Navigated>> {
14130        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14131    }
14132
14133    pub fn go_to_declaration_split(
14134        &mut self,
14135        _: &GoToDeclaration,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) -> Task<Result<Navigated>> {
14139        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14140    }
14141
14142    pub fn go_to_implementation(
14143        &mut self,
14144        _: &GoToImplementation,
14145        window: &mut Window,
14146        cx: &mut Context<Self>,
14147    ) -> Task<Result<Navigated>> {
14148        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14149    }
14150
14151    pub fn go_to_implementation_split(
14152        &mut self,
14153        _: &GoToImplementationSplit,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) -> Task<Result<Navigated>> {
14157        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14158    }
14159
14160    pub fn go_to_type_definition(
14161        &mut self,
14162        _: &GoToTypeDefinition,
14163        window: &mut Window,
14164        cx: &mut Context<Self>,
14165    ) -> Task<Result<Navigated>> {
14166        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14167    }
14168
14169    pub fn go_to_definition_split(
14170        &mut self,
14171        _: &GoToDefinitionSplit,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) -> Task<Result<Navigated>> {
14175        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14176    }
14177
14178    pub fn go_to_type_definition_split(
14179        &mut self,
14180        _: &GoToTypeDefinitionSplit,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) -> Task<Result<Navigated>> {
14184        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14185    }
14186
14187    fn go_to_definition_of_kind(
14188        &mut self,
14189        kind: GotoDefinitionKind,
14190        split: bool,
14191        window: &mut Window,
14192        cx: &mut Context<Self>,
14193    ) -> Task<Result<Navigated>> {
14194        let Some(provider) = self.semantics_provider.clone() else {
14195            return Task::ready(Ok(Navigated::No));
14196        };
14197        let head = self.selections.newest::<usize>(cx).head();
14198        let buffer = self.buffer.read(cx);
14199        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14200            text_anchor
14201        } else {
14202            return Task::ready(Ok(Navigated::No));
14203        };
14204
14205        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14206            return Task::ready(Ok(Navigated::No));
14207        };
14208
14209        cx.spawn_in(window, async move |editor, cx| {
14210            let definitions = definitions.await?;
14211            let navigated = editor
14212                .update_in(cx, |editor, window, cx| {
14213                    editor.navigate_to_hover_links(
14214                        Some(kind),
14215                        definitions
14216                            .into_iter()
14217                            .filter(|location| {
14218                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14219                            })
14220                            .map(HoverLink::Text)
14221                            .collect::<Vec<_>>(),
14222                        split,
14223                        window,
14224                        cx,
14225                    )
14226                })?
14227                .await?;
14228            anyhow::Ok(navigated)
14229        })
14230    }
14231
14232    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14233        let selection = self.selections.newest_anchor();
14234        let head = selection.head();
14235        let tail = selection.tail();
14236
14237        let Some((buffer, start_position)) =
14238            self.buffer.read(cx).text_anchor_for_position(head, cx)
14239        else {
14240            return;
14241        };
14242
14243        let end_position = if head != tail {
14244            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14245                return;
14246            };
14247            Some(pos)
14248        } else {
14249            None
14250        };
14251
14252        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14253            let url = if let Some(end_pos) = end_position {
14254                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14255            } else {
14256                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14257            };
14258
14259            if let Some(url) = url {
14260                editor.update(cx, |_, cx| {
14261                    cx.open_url(&url);
14262                })
14263            } else {
14264                Ok(())
14265            }
14266        });
14267
14268        url_finder.detach();
14269    }
14270
14271    pub fn open_selected_filename(
14272        &mut self,
14273        _: &OpenSelectedFilename,
14274        window: &mut Window,
14275        cx: &mut Context<Self>,
14276    ) {
14277        let Some(workspace) = self.workspace() else {
14278            return;
14279        };
14280
14281        let position = self.selections.newest_anchor().head();
14282
14283        let Some((buffer, buffer_position)) =
14284            self.buffer.read(cx).text_anchor_for_position(position, cx)
14285        else {
14286            return;
14287        };
14288
14289        let project = self.project.clone();
14290
14291        cx.spawn_in(window, async move |_, cx| {
14292            let result = find_file(&buffer, project, buffer_position, cx).await;
14293
14294            if let Some((_, path)) = result {
14295                workspace
14296                    .update_in(cx, |workspace, window, cx| {
14297                        workspace.open_resolved_path(path, window, cx)
14298                    })?
14299                    .await?;
14300            }
14301            anyhow::Ok(())
14302        })
14303        .detach();
14304    }
14305
14306    pub(crate) fn navigate_to_hover_links(
14307        &mut self,
14308        kind: Option<GotoDefinitionKind>,
14309        mut definitions: Vec<HoverLink>,
14310        split: bool,
14311        window: &mut Window,
14312        cx: &mut Context<Editor>,
14313    ) -> Task<Result<Navigated>> {
14314        // If there is one definition, just open it directly
14315        if definitions.len() == 1 {
14316            let definition = definitions.pop().unwrap();
14317
14318            enum TargetTaskResult {
14319                Location(Option<Location>),
14320                AlreadyNavigated,
14321            }
14322
14323            let target_task = match definition {
14324                HoverLink::Text(link) => {
14325                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14326                }
14327                HoverLink::InlayHint(lsp_location, server_id) => {
14328                    let computation =
14329                        self.compute_target_location(lsp_location, server_id, window, cx);
14330                    cx.background_spawn(async move {
14331                        let location = computation.await?;
14332                        Ok(TargetTaskResult::Location(location))
14333                    })
14334                }
14335                HoverLink::Url(url) => {
14336                    cx.open_url(&url);
14337                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14338                }
14339                HoverLink::File(path) => {
14340                    if let Some(workspace) = self.workspace() {
14341                        cx.spawn_in(window, async move |_, cx| {
14342                            workspace
14343                                .update_in(cx, |workspace, window, cx| {
14344                                    workspace.open_resolved_path(path, window, cx)
14345                                })?
14346                                .await
14347                                .map(|_| TargetTaskResult::AlreadyNavigated)
14348                        })
14349                    } else {
14350                        Task::ready(Ok(TargetTaskResult::Location(None)))
14351                    }
14352                }
14353            };
14354            cx.spawn_in(window, async move |editor, cx| {
14355                let target = match target_task.await.context("target resolution task")? {
14356                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14357                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14358                    TargetTaskResult::Location(Some(target)) => target,
14359                };
14360
14361                editor.update_in(cx, |editor, window, cx| {
14362                    let Some(workspace) = editor.workspace() else {
14363                        return Navigated::No;
14364                    };
14365                    let pane = workspace.read(cx).active_pane().clone();
14366
14367                    let range = target.range.to_point(target.buffer.read(cx));
14368                    let range = editor.range_for_match(&range);
14369                    let range = collapse_multiline_range(range);
14370
14371                    if !split
14372                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14373                    {
14374                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14375                    } else {
14376                        window.defer(cx, move |window, cx| {
14377                            let target_editor: Entity<Self> =
14378                                workspace.update(cx, |workspace, cx| {
14379                                    let pane = if split {
14380                                        workspace.adjacent_pane(window, cx)
14381                                    } else {
14382                                        workspace.active_pane().clone()
14383                                    };
14384
14385                                    workspace.open_project_item(
14386                                        pane,
14387                                        target.buffer.clone(),
14388                                        true,
14389                                        true,
14390                                        window,
14391                                        cx,
14392                                    )
14393                                });
14394                            target_editor.update(cx, |target_editor, cx| {
14395                                // When selecting a definition in a different buffer, disable the nav history
14396                                // to avoid creating a history entry at the previous cursor location.
14397                                pane.update(cx, |pane, _| pane.disable_history());
14398                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14399                                pane.update(cx, |pane, _| pane.enable_history());
14400                            });
14401                        });
14402                    }
14403                    Navigated::Yes
14404                })
14405            })
14406        } else if !definitions.is_empty() {
14407            cx.spawn_in(window, async move |editor, cx| {
14408                let (title, location_tasks, workspace) = editor
14409                    .update_in(cx, |editor, window, cx| {
14410                        let tab_kind = match kind {
14411                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14412                            _ => "Definitions",
14413                        };
14414                        let title = definitions
14415                            .iter()
14416                            .find_map(|definition| match definition {
14417                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14418                                    let buffer = origin.buffer.read(cx);
14419                                    format!(
14420                                        "{} for {}",
14421                                        tab_kind,
14422                                        buffer
14423                                            .text_for_range(origin.range.clone())
14424                                            .collect::<String>()
14425                                    )
14426                                }),
14427                                HoverLink::InlayHint(_, _) => None,
14428                                HoverLink::Url(_) => None,
14429                                HoverLink::File(_) => None,
14430                            })
14431                            .unwrap_or(tab_kind.to_string());
14432                        let location_tasks = definitions
14433                            .into_iter()
14434                            .map(|definition| match definition {
14435                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14436                                HoverLink::InlayHint(lsp_location, server_id) => editor
14437                                    .compute_target_location(lsp_location, server_id, window, cx),
14438                                HoverLink::Url(_) => Task::ready(Ok(None)),
14439                                HoverLink::File(_) => Task::ready(Ok(None)),
14440                            })
14441                            .collect::<Vec<_>>();
14442                        (title, location_tasks, editor.workspace().clone())
14443                    })
14444                    .context("location tasks preparation")?;
14445
14446                let locations = future::join_all(location_tasks)
14447                    .await
14448                    .into_iter()
14449                    .filter_map(|location| location.transpose())
14450                    .collect::<Result<_>>()
14451                    .context("location tasks")?;
14452
14453                let Some(workspace) = workspace else {
14454                    return Ok(Navigated::No);
14455                };
14456                let opened = workspace
14457                    .update_in(cx, |workspace, window, cx| {
14458                        Self::open_locations_in_multibuffer(
14459                            workspace,
14460                            locations,
14461                            title,
14462                            split,
14463                            MultibufferSelectionMode::First,
14464                            window,
14465                            cx,
14466                        )
14467                    })
14468                    .ok();
14469
14470                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14471            })
14472        } else {
14473            Task::ready(Ok(Navigated::No))
14474        }
14475    }
14476
14477    fn compute_target_location(
14478        &self,
14479        lsp_location: lsp::Location,
14480        server_id: LanguageServerId,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) -> Task<anyhow::Result<Option<Location>>> {
14484        let Some(project) = self.project.clone() else {
14485            return Task::ready(Ok(None));
14486        };
14487
14488        cx.spawn_in(window, async move |editor, cx| {
14489            let location_task = editor.update(cx, |_, cx| {
14490                project.update(cx, |project, cx| {
14491                    let language_server_name = project
14492                        .language_server_statuses(cx)
14493                        .find(|(id, _)| server_id == *id)
14494                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14495                    language_server_name.map(|language_server_name| {
14496                        project.open_local_buffer_via_lsp(
14497                            lsp_location.uri.clone(),
14498                            server_id,
14499                            language_server_name,
14500                            cx,
14501                        )
14502                    })
14503                })
14504            })?;
14505            let location = match location_task {
14506                Some(task) => Some({
14507                    let target_buffer_handle = task.await.context("open local buffer")?;
14508                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14509                        let target_start = target_buffer
14510                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14511                        let target_end = target_buffer
14512                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14513                        target_buffer.anchor_after(target_start)
14514                            ..target_buffer.anchor_before(target_end)
14515                    })?;
14516                    Location {
14517                        buffer: target_buffer_handle,
14518                        range,
14519                    }
14520                }),
14521                None => None,
14522            };
14523            Ok(location)
14524        })
14525    }
14526
14527    pub fn find_all_references(
14528        &mut self,
14529        _: &FindAllReferences,
14530        window: &mut Window,
14531        cx: &mut Context<Self>,
14532    ) -> Option<Task<Result<Navigated>>> {
14533        let selection = self.selections.newest::<usize>(cx);
14534        let multi_buffer = self.buffer.read(cx);
14535        let head = selection.head();
14536
14537        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14538        let head_anchor = multi_buffer_snapshot.anchor_at(
14539            head,
14540            if head < selection.tail() {
14541                Bias::Right
14542            } else {
14543                Bias::Left
14544            },
14545        );
14546
14547        match self
14548            .find_all_references_task_sources
14549            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14550        {
14551            Ok(_) => {
14552                log::info!(
14553                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14554                );
14555                return None;
14556            }
14557            Err(i) => {
14558                self.find_all_references_task_sources.insert(i, head_anchor);
14559            }
14560        }
14561
14562        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14563        let workspace = self.workspace()?;
14564        let project = workspace.read(cx).project().clone();
14565        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14566        Some(cx.spawn_in(window, async move |editor, cx| {
14567            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14568                if let Ok(i) = editor
14569                    .find_all_references_task_sources
14570                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14571                {
14572                    editor.find_all_references_task_sources.remove(i);
14573                }
14574            });
14575
14576            let locations = references.await?;
14577            if locations.is_empty() {
14578                return anyhow::Ok(Navigated::No);
14579            }
14580
14581            workspace.update_in(cx, |workspace, window, cx| {
14582                let title = locations
14583                    .first()
14584                    .as_ref()
14585                    .map(|location| {
14586                        let buffer = location.buffer.read(cx);
14587                        format!(
14588                            "References to `{}`",
14589                            buffer
14590                                .text_for_range(location.range.clone())
14591                                .collect::<String>()
14592                        )
14593                    })
14594                    .unwrap();
14595                Self::open_locations_in_multibuffer(
14596                    workspace,
14597                    locations,
14598                    title,
14599                    false,
14600                    MultibufferSelectionMode::First,
14601                    window,
14602                    cx,
14603                );
14604                Navigated::Yes
14605            })
14606        }))
14607    }
14608
14609    /// Opens a multibuffer with the given project locations in it
14610    pub fn open_locations_in_multibuffer(
14611        workspace: &mut Workspace,
14612        mut locations: Vec<Location>,
14613        title: String,
14614        split: bool,
14615        multibuffer_selection_mode: MultibufferSelectionMode,
14616        window: &mut Window,
14617        cx: &mut Context<Workspace>,
14618    ) {
14619        // If there are multiple definitions, open them in a multibuffer
14620        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14621        let mut locations = locations.into_iter().peekable();
14622        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14623        let capability = workspace.project().read(cx).capability();
14624
14625        let excerpt_buffer = cx.new(|cx| {
14626            let mut multibuffer = MultiBuffer::new(capability);
14627            while let Some(location) = locations.next() {
14628                let buffer = location.buffer.read(cx);
14629                let mut ranges_for_buffer = Vec::new();
14630                let range = location.range.to_point(buffer);
14631                ranges_for_buffer.push(range.clone());
14632
14633                while let Some(next_location) = locations.peek() {
14634                    if next_location.buffer == location.buffer {
14635                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14636                        locations.next();
14637                    } else {
14638                        break;
14639                    }
14640                }
14641
14642                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14643                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14644                    PathKey::for_buffer(&location.buffer, cx),
14645                    location.buffer.clone(),
14646                    ranges_for_buffer,
14647                    DEFAULT_MULTIBUFFER_CONTEXT,
14648                    cx,
14649                );
14650                ranges.extend(new_ranges)
14651            }
14652
14653            multibuffer.with_title(title)
14654        });
14655
14656        let editor = cx.new(|cx| {
14657            Editor::for_multibuffer(
14658                excerpt_buffer,
14659                Some(workspace.project().clone()),
14660                window,
14661                cx,
14662            )
14663        });
14664        editor.update(cx, |editor, cx| {
14665            match multibuffer_selection_mode {
14666                MultibufferSelectionMode::First => {
14667                    if let Some(first_range) = ranges.first() {
14668                        editor.change_selections(None, window, cx, |selections| {
14669                            selections.clear_disjoint();
14670                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14671                        });
14672                    }
14673                    editor.highlight_background::<Self>(
14674                        &ranges,
14675                        |theme| theme.editor_highlighted_line_background,
14676                        cx,
14677                    );
14678                }
14679                MultibufferSelectionMode::All => {
14680                    editor.change_selections(None, window, cx, |selections| {
14681                        selections.clear_disjoint();
14682                        selections.select_anchor_ranges(ranges);
14683                    });
14684                }
14685            }
14686            editor.register_buffers_with_language_servers(cx);
14687        });
14688
14689        let item = Box::new(editor);
14690        let item_id = item.item_id();
14691
14692        if split {
14693            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14694        } else {
14695            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14696                let (preview_item_id, preview_item_idx) =
14697                    workspace.active_pane().update(cx, |pane, _| {
14698                        (pane.preview_item_id(), pane.preview_item_idx())
14699                    });
14700
14701                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14702
14703                if let Some(preview_item_id) = preview_item_id {
14704                    workspace.active_pane().update(cx, |pane, cx| {
14705                        pane.remove_item(preview_item_id, false, false, window, cx);
14706                    });
14707                }
14708            } else {
14709                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14710            }
14711        }
14712        workspace.active_pane().update(cx, |pane, cx| {
14713            pane.set_preview_item_id(Some(item_id), cx);
14714        });
14715    }
14716
14717    pub fn rename(
14718        &mut self,
14719        _: &Rename,
14720        window: &mut Window,
14721        cx: &mut Context<Self>,
14722    ) -> Option<Task<Result<()>>> {
14723        use language::ToOffset as _;
14724
14725        let provider = self.semantics_provider.clone()?;
14726        let selection = self.selections.newest_anchor().clone();
14727        let (cursor_buffer, cursor_buffer_position) = self
14728            .buffer
14729            .read(cx)
14730            .text_anchor_for_position(selection.head(), cx)?;
14731        let (tail_buffer, cursor_buffer_position_end) = self
14732            .buffer
14733            .read(cx)
14734            .text_anchor_for_position(selection.tail(), cx)?;
14735        if tail_buffer != cursor_buffer {
14736            return None;
14737        }
14738
14739        let snapshot = cursor_buffer.read(cx).snapshot();
14740        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14741        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14742        let prepare_rename = provider
14743            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14744            .unwrap_or_else(|| Task::ready(Ok(None)));
14745        drop(snapshot);
14746
14747        Some(cx.spawn_in(window, async move |this, cx| {
14748            let rename_range = if let Some(range) = prepare_rename.await? {
14749                Some(range)
14750            } else {
14751                this.update(cx, |this, cx| {
14752                    let buffer = this.buffer.read(cx).snapshot(cx);
14753                    let mut buffer_highlights = this
14754                        .document_highlights_for_position(selection.head(), &buffer)
14755                        .filter(|highlight| {
14756                            highlight.start.excerpt_id == selection.head().excerpt_id
14757                                && highlight.end.excerpt_id == selection.head().excerpt_id
14758                        });
14759                    buffer_highlights
14760                        .next()
14761                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14762                })?
14763            };
14764            if let Some(rename_range) = rename_range {
14765                this.update_in(cx, |this, window, cx| {
14766                    let snapshot = cursor_buffer.read(cx).snapshot();
14767                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14768                    let cursor_offset_in_rename_range =
14769                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14770                    let cursor_offset_in_rename_range_end =
14771                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14772
14773                    this.take_rename(false, window, cx);
14774                    let buffer = this.buffer.read(cx).read(cx);
14775                    let cursor_offset = selection.head().to_offset(&buffer);
14776                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14777                    let rename_end = rename_start + rename_buffer_range.len();
14778                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14779                    let mut old_highlight_id = None;
14780                    let old_name: Arc<str> = buffer
14781                        .chunks(rename_start..rename_end, true)
14782                        .map(|chunk| {
14783                            if old_highlight_id.is_none() {
14784                                old_highlight_id = chunk.syntax_highlight_id;
14785                            }
14786                            chunk.text
14787                        })
14788                        .collect::<String>()
14789                        .into();
14790
14791                    drop(buffer);
14792
14793                    // Position the selection in the rename editor so that it matches the current selection.
14794                    this.show_local_selections = false;
14795                    let rename_editor = cx.new(|cx| {
14796                        let mut editor = Editor::single_line(window, cx);
14797                        editor.buffer.update(cx, |buffer, cx| {
14798                            buffer.edit([(0..0, old_name.clone())], None, cx)
14799                        });
14800                        let rename_selection_range = match cursor_offset_in_rename_range
14801                            .cmp(&cursor_offset_in_rename_range_end)
14802                        {
14803                            Ordering::Equal => {
14804                                editor.select_all(&SelectAll, window, cx);
14805                                return editor;
14806                            }
14807                            Ordering::Less => {
14808                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14809                            }
14810                            Ordering::Greater => {
14811                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14812                            }
14813                        };
14814                        if rename_selection_range.end > old_name.len() {
14815                            editor.select_all(&SelectAll, window, cx);
14816                        } else {
14817                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14818                                s.select_ranges([rename_selection_range]);
14819                            });
14820                        }
14821                        editor
14822                    });
14823                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14824                        if e == &EditorEvent::Focused {
14825                            cx.emit(EditorEvent::FocusedIn)
14826                        }
14827                    })
14828                    .detach();
14829
14830                    let write_highlights =
14831                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14832                    let read_highlights =
14833                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14834                    let ranges = write_highlights
14835                        .iter()
14836                        .flat_map(|(_, ranges)| ranges.iter())
14837                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14838                        .cloned()
14839                        .collect();
14840
14841                    this.highlight_text::<Rename>(
14842                        ranges,
14843                        HighlightStyle {
14844                            fade_out: Some(0.6),
14845                            ..Default::default()
14846                        },
14847                        cx,
14848                    );
14849                    let rename_focus_handle = rename_editor.focus_handle(cx);
14850                    window.focus(&rename_focus_handle);
14851                    let block_id = this.insert_blocks(
14852                        [BlockProperties {
14853                            style: BlockStyle::Flex,
14854                            placement: BlockPlacement::Below(range.start),
14855                            height: Some(1),
14856                            render: Arc::new({
14857                                let rename_editor = rename_editor.clone();
14858                                move |cx: &mut BlockContext| {
14859                                    let mut text_style = cx.editor_style.text.clone();
14860                                    if let Some(highlight_style) = old_highlight_id
14861                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14862                                    {
14863                                        text_style = text_style.highlight(highlight_style);
14864                                    }
14865                                    div()
14866                                        .block_mouse_down()
14867                                        .pl(cx.anchor_x)
14868                                        .child(EditorElement::new(
14869                                            &rename_editor,
14870                                            EditorStyle {
14871                                                background: cx.theme().system().transparent,
14872                                                local_player: cx.editor_style.local_player,
14873                                                text: text_style,
14874                                                scrollbar_width: cx.editor_style.scrollbar_width,
14875                                                syntax: cx.editor_style.syntax.clone(),
14876                                                status: cx.editor_style.status.clone(),
14877                                                inlay_hints_style: HighlightStyle {
14878                                                    font_weight: Some(FontWeight::BOLD),
14879                                                    ..make_inlay_hints_style(cx.app)
14880                                                },
14881                                                inline_completion_styles: make_suggestion_styles(
14882                                                    cx.app,
14883                                                ),
14884                                                ..EditorStyle::default()
14885                                            },
14886                                        ))
14887                                        .into_any_element()
14888                                }
14889                            }),
14890                            priority: 0,
14891                            render_in_minimap: true,
14892                        }],
14893                        Some(Autoscroll::fit()),
14894                        cx,
14895                    )[0];
14896                    this.pending_rename = Some(RenameState {
14897                        range,
14898                        old_name,
14899                        editor: rename_editor,
14900                        block_id,
14901                    });
14902                })?;
14903            }
14904
14905            Ok(())
14906        }))
14907    }
14908
14909    pub fn confirm_rename(
14910        &mut self,
14911        _: &ConfirmRename,
14912        window: &mut Window,
14913        cx: &mut Context<Self>,
14914    ) -> Option<Task<Result<()>>> {
14915        let rename = self.take_rename(false, window, cx)?;
14916        let workspace = self.workspace()?.downgrade();
14917        let (buffer, start) = self
14918            .buffer
14919            .read(cx)
14920            .text_anchor_for_position(rename.range.start, cx)?;
14921        let (end_buffer, _) = self
14922            .buffer
14923            .read(cx)
14924            .text_anchor_for_position(rename.range.end, cx)?;
14925        if buffer != end_buffer {
14926            return None;
14927        }
14928
14929        let old_name = rename.old_name;
14930        let new_name = rename.editor.read(cx).text(cx);
14931
14932        let rename = self.semantics_provider.as_ref()?.perform_rename(
14933            &buffer,
14934            start,
14935            new_name.clone(),
14936            cx,
14937        )?;
14938
14939        Some(cx.spawn_in(window, async move |editor, cx| {
14940            let project_transaction = rename.await?;
14941            Self::open_project_transaction(
14942                &editor,
14943                workspace,
14944                project_transaction,
14945                format!("Rename: {}{}", old_name, new_name),
14946                cx,
14947            )
14948            .await?;
14949
14950            editor.update(cx, |editor, cx| {
14951                editor.refresh_document_highlights(cx);
14952            })?;
14953            Ok(())
14954        }))
14955    }
14956
14957    fn take_rename(
14958        &mut self,
14959        moving_cursor: bool,
14960        window: &mut Window,
14961        cx: &mut Context<Self>,
14962    ) -> Option<RenameState> {
14963        let rename = self.pending_rename.take()?;
14964        if rename.editor.focus_handle(cx).is_focused(window) {
14965            window.focus(&self.focus_handle);
14966        }
14967
14968        self.remove_blocks(
14969            [rename.block_id].into_iter().collect(),
14970            Some(Autoscroll::fit()),
14971            cx,
14972        );
14973        self.clear_highlights::<Rename>(cx);
14974        self.show_local_selections = true;
14975
14976        if moving_cursor {
14977            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14978                editor.selections.newest::<usize>(cx).head()
14979            });
14980
14981            // Update the selection to match the position of the selection inside
14982            // the rename editor.
14983            let snapshot = self.buffer.read(cx).read(cx);
14984            let rename_range = rename.range.to_offset(&snapshot);
14985            let cursor_in_editor = snapshot
14986                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14987                .min(rename_range.end);
14988            drop(snapshot);
14989
14990            self.change_selections(None, window, cx, |s| {
14991                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14992            });
14993        } else {
14994            self.refresh_document_highlights(cx);
14995        }
14996
14997        Some(rename)
14998    }
14999
15000    pub fn pending_rename(&self) -> Option<&RenameState> {
15001        self.pending_rename.as_ref()
15002    }
15003
15004    fn format(
15005        &mut self,
15006        _: &Format,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) -> Option<Task<Result<()>>> {
15010        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15011
15012        let project = match &self.project {
15013            Some(project) => project.clone(),
15014            None => return None,
15015        };
15016
15017        Some(self.perform_format(
15018            project,
15019            FormatTrigger::Manual,
15020            FormatTarget::Buffers,
15021            window,
15022            cx,
15023        ))
15024    }
15025
15026    fn format_selections(
15027        &mut self,
15028        _: &FormatSelections,
15029        window: &mut Window,
15030        cx: &mut Context<Self>,
15031    ) -> Option<Task<Result<()>>> {
15032        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15033
15034        let project = match &self.project {
15035            Some(project) => project.clone(),
15036            None => return None,
15037        };
15038
15039        let ranges = self
15040            .selections
15041            .all_adjusted(cx)
15042            .into_iter()
15043            .map(|selection| selection.range())
15044            .collect_vec();
15045
15046        Some(self.perform_format(
15047            project,
15048            FormatTrigger::Manual,
15049            FormatTarget::Ranges(ranges),
15050            window,
15051            cx,
15052        ))
15053    }
15054
15055    fn perform_format(
15056        &mut self,
15057        project: Entity<Project>,
15058        trigger: FormatTrigger,
15059        target: FormatTarget,
15060        window: &mut Window,
15061        cx: &mut Context<Self>,
15062    ) -> Task<Result<()>> {
15063        let buffer = self.buffer.clone();
15064        let (buffers, target) = match target {
15065            FormatTarget::Buffers => {
15066                let mut buffers = buffer.read(cx).all_buffers();
15067                if trigger == FormatTrigger::Save {
15068                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15069                }
15070                (buffers, LspFormatTarget::Buffers)
15071            }
15072            FormatTarget::Ranges(selection_ranges) => {
15073                let multi_buffer = buffer.read(cx);
15074                let snapshot = multi_buffer.read(cx);
15075                let mut buffers = HashSet::default();
15076                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15077                    BTreeMap::new();
15078                for selection_range in selection_ranges {
15079                    for (buffer, buffer_range, _) in
15080                        snapshot.range_to_buffer_ranges(selection_range)
15081                    {
15082                        let buffer_id = buffer.remote_id();
15083                        let start = buffer.anchor_before(buffer_range.start);
15084                        let end = buffer.anchor_after(buffer_range.end);
15085                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15086                        buffer_id_to_ranges
15087                            .entry(buffer_id)
15088                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15089                            .or_insert_with(|| vec![start..end]);
15090                    }
15091                }
15092                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15093            }
15094        };
15095
15096        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15097        let selections_prev = transaction_id_prev
15098            .and_then(|transaction_id_prev| {
15099                // default to selections as they were after the last edit, if we have them,
15100                // instead of how they are now.
15101                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15102                // will take you back to where you made the last edit, instead of staying where you scrolled
15103                self.selection_history
15104                    .transaction(transaction_id_prev)
15105                    .map(|t| t.0.clone())
15106            })
15107            .unwrap_or_else(|| {
15108                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15109                self.selections.disjoint_anchors()
15110            });
15111
15112        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15113        let format = project.update(cx, |project, cx| {
15114            project.format(buffers, target, true, trigger, cx)
15115        });
15116
15117        cx.spawn_in(window, async move |editor, cx| {
15118            let transaction = futures::select_biased! {
15119                transaction = format.log_err().fuse() => transaction,
15120                () = timeout => {
15121                    log::warn!("timed out waiting for formatting");
15122                    None
15123                }
15124            };
15125
15126            buffer
15127                .update(cx, |buffer, cx| {
15128                    if let Some(transaction) = transaction {
15129                        if !buffer.is_singleton() {
15130                            buffer.push_transaction(&transaction.0, cx);
15131                        }
15132                    }
15133                    cx.notify();
15134                })
15135                .ok();
15136
15137            if let Some(transaction_id_now) =
15138                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15139            {
15140                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15141                if has_new_transaction {
15142                    _ = editor.update(cx, |editor, _| {
15143                        editor
15144                            .selection_history
15145                            .insert_transaction(transaction_id_now, selections_prev);
15146                    });
15147                }
15148            }
15149
15150            Ok(())
15151        })
15152    }
15153
15154    fn organize_imports(
15155        &mut self,
15156        _: &OrganizeImports,
15157        window: &mut Window,
15158        cx: &mut Context<Self>,
15159    ) -> Option<Task<Result<()>>> {
15160        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15161        let project = match &self.project {
15162            Some(project) => project.clone(),
15163            None => return None,
15164        };
15165        Some(self.perform_code_action_kind(
15166            project,
15167            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15168            window,
15169            cx,
15170        ))
15171    }
15172
15173    fn perform_code_action_kind(
15174        &mut self,
15175        project: Entity<Project>,
15176        kind: CodeActionKind,
15177        window: &mut Window,
15178        cx: &mut Context<Self>,
15179    ) -> Task<Result<()>> {
15180        let buffer = self.buffer.clone();
15181        let buffers = buffer.read(cx).all_buffers();
15182        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15183        let apply_action = project.update(cx, |project, cx| {
15184            project.apply_code_action_kind(buffers, kind, true, cx)
15185        });
15186        cx.spawn_in(window, async move |_, cx| {
15187            let transaction = futures::select_biased! {
15188                () = timeout => {
15189                    log::warn!("timed out waiting for executing code action");
15190                    None
15191                }
15192                transaction = apply_action.log_err().fuse() => transaction,
15193            };
15194            buffer
15195                .update(cx, |buffer, cx| {
15196                    // check if we need this
15197                    if let Some(transaction) = transaction {
15198                        if !buffer.is_singleton() {
15199                            buffer.push_transaction(&transaction.0, cx);
15200                        }
15201                    }
15202                    cx.notify();
15203                })
15204                .ok();
15205            Ok(())
15206        })
15207    }
15208
15209    fn restart_language_server(
15210        &mut self,
15211        _: &RestartLanguageServer,
15212        _: &mut Window,
15213        cx: &mut Context<Self>,
15214    ) {
15215        if let Some(project) = self.project.clone() {
15216            self.buffer.update(cx, |multi_buffer, cx| {
15217                project.update(cx, |project, cx| {
15218                    project.restart_language_servers_for_buffers(
15219                        multi_buffer.all_buffers().into_iter().collect(),
15220                        cx,
15221                    );
15222                });
15223            })
15224        }
15225    }
15226
15227    fn stop_language_server(
15228        &mut self,
15229        _: &StopLanguageServer,
15230        _: &mut Window,
15231        cx: &mut Context<Self>,
15232    ) {
15233        if let Some(project) = self.project.clone() {
15234            self.buffer.update(cx, |multi_buffer, cx| {
15235                project.update(cx, |project, cx| {
15236                    project.stop_language_servers_for_buffers(
15237                        multi_buffer.all_buffers().into_iter().collect(),
15238                        cx,
15239                    );
15240                    cx.emit(project::Event::RefreshInlayHints);
15241                });
15242            });
15243        }
15244    }
15245
15246    fn cancel_language_server_work(
15247        workspace: &mut Workspace,
15248        _: &actions::CancelLanguageServerWork,
15249        _: &mut Window,
15250        cx: &mut Context<Workspace>,
15251    ) {
15252        let project = workspace.project();
15253        let buffers = workspace
15254            .active_item(cx)
15255            .and_then(|item| item.act_as::<Editor>(cx))
15256            .map_or(HashSet::default(), |editor| {
15257                editor.read(cx).buffer.read(cx).all_buffers()
15258            });
15259        project.update(cx, |project, cx| {
15260            project.cancel_language_server_work_for_buffers(buffers, cx);
15261        });
15262    }
15263
15264    fn show_character_palette(
15265        &mut self,
15266        _: &ShowCharacterPalette,
15267        window: &mut Window,
15268        _: &mut Context<Self>,
15269    ) {
15270        window.show_character_palette();
15271    }
15272
15273    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15274        if self.mode.is_minimap() {
15275            return;
15276        }
15277
15278        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15279            let buffer = self.buffer.read(cx).snapshot(cx);
15280            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15281            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15282            let is_valid = buffer
15283                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15284                .any(|entry| {
15285                    entry.diagnostic.is_primary
15286                        && !entry.range.is_empty()
15287                        && entry.range.start == primary_range_start
15288                        && entry.diagnostic.message == active_diagnostics.active_message
15289                });
15290
15291            if !is_valid {
15292                self.dismiss_diagnostics(cx);
15293            }
15294        }
15295    }
15296
15297    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15298        match &self.active_diagnostics {
15299            ActiveDiagnostic::Group(group) => Some(group),
15300            _ => None,
15301        }
15302    }
15303
15304    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15305        self.dismiss_diagnostics(cx);
15306        self.active_diagnostics = ActiveDiagnostic::All;
15307    }
15308
15309    fn activate_diagnostics(
15310        &mut self,
15311        buffer_id: BufferId,
15312        diagnostic: DiagnosticEntry<usize>,
15313        window: &mut Window,
15314        cx: &mut Context<Self>,
15315    ) {
15316        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15317            return;
15318        }
15319        self.dismiss_diagnostics(cx);
15320        let snapshot = self.snapshot(window, cx);
15321        let buffer = self.buffer.read(cx).snapshot(cx);
15322        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15323            return;
15324        };
15325
15326        let diagnostic_group = buffer
15327            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15328            .collect::<Vec<_>>();
15329
15330        let blocks =
15331            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15332
15333        let blocks = self.display_map.update(cx, |display_map, cx| {
15334            display_map.insert_blocks(blocks, cx).into_iter().collect()
15335        });
15336        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15337            active_range: buffer.anchor_before(diagnostic.range.start)
15338                ..buffer.anchor_after(diagnostic.range.end),
15339            active_message: diagnostic.diagnostic.message.clone(),
15340            group_id: diagnostic.diagnostic.group_id,
15341            blocks,
15342        });
15343        cx.notify();
15344    }
15345
15346    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15347        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15348            return;
15349        };
15350
15351        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15352        if let ActiveDiagnostic::Group(group) = prev {
15353            self.display_map.update(cx, |display_map, cx| {
15354                display_map.remove_blocks(group.blocks, cx);
15355            });
15356            cx.notify();
15357        }
15358    }
15359
15360    /// Disable inline diagnostics rendering for this editor.
15361    pub fn disable_inline_diagnostics(&mut self) {
15362        self.inline_diagnostics_enabled = false;
15363        self.inline_diagnostics_update = Task::ready(());
15364        self.inline_diagnostics.clear();
15365    }
15366
15367    pub fn diagnostics_enabled(&self) -> bool {
15368        self.mode.is_full()
15369    }
15370
15371    pub fn inline_diagnostics_enabled(&self) -> bool {
15372        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15373    }
15374
15375    pub fn show_inline_diagnostics(&self) -> bool {
15376        self.show_inline_diagnostics
15377    }
15378
15379    pub fn toggle_inline_diagnostics(
15380        &mut self,
15381        _: &ToggleInlineDiagnostics,
15382        window: &mut Window,
15383        cx: &mut Context<Editor>,
15384    ) {
15385        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15386        self.refresh_inline_diagnostics(false, window, cx);
15387    }
15388
15389    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15390        self.diagnostics_max_severity = severity;
15391        self.display_map.update(cx, |display_map, _| {
15392            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15393        });
15394    }
15395
15396    pub fn toggle_diagnostics(
15397        &mut self,
15398        _: &ToggleDiagnostics,
15399        window: &mut Window,
15400        cx: &mut Context<Editor>,
15401    ) {
15402        if !self.diagnostics_enabled() {
15403            return;
15404        }
15405
15406        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15407            EditorSettings::get_global(cx)
15408                .diagnostics_max_severity
15409                .filter(|severity| severity != &DiagnosticSeverity::Off)
15410                .unwrap_or(DiagnosticSeverity::Hint)
15411        } else {
15412            DiagnosticSeverity::Off
15413        };
15414        self.set_max_diagnostics_severity(new_severity, cx);
15415        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15416            self.active_diagnostics = ActiveDiagnostic::None;
15417            self.inline_diagnostics_update = Task::ready(());
15418            self.inline_diagnostics.clear();
15419        } else {
15420            self.refresh_inline_diagnostics(false, window, cx);
15421        }
15422
15423        cx.notify();
15424    }
15425
15426    pub fn toggle_minimap(
15427        &mut self,
15428        _: &ToggleMinimap,
15429        window: &mut Window,
15430        cx: &mut Context<Editor>,
15431    ) {
15432        if self.supports_minimap(cx) {
15433            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15434        }
15435    }
15436
15437    fn refresh_inline_diagnostics(
15438        &mut self,
15439        debounce: bool,
15440        window: &mut Window,
15441        cx: &mut Context<Self>,
15442    ) {
15443        let max_severity = ProjectSettings::get_global(cx)
15444            .diagnostics
15445            .inline
15446            .max_severity
15447            .unwrap_or(self.diagnostics_max_severity);
15448
15449        if !self.inline_diagnostics_enabled()
15450            || !self.show_inline_diagnostics
15451            || max_severity == DiagnosticSeverity::Off
15452        {
15453            self.inline_diagnostics_update = Task::ready(());
15454            self.inline_diagnostics.clear();
15455            return;
15456        }
15457
15458        let debounce_ms = ProjectSettings::get_global(cx)
15459            .diagnostics
15460            .inline
15461            .update_debounce_ms;
15462        let debounce = if debounce && debounce_ms > 0 {
15463            Some(Duration::from_millis(debounce_ms))
15464        } else {
15465            None
15466        };
15467        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15468            let editor = editor.upgrade().unwrap();
15469
15470            if let Some(debounce) = debounce {
15471                cx.background_executor().timer(debounce).await;
15472            }
15473            let Some(snapshot) = editor
15474                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15475                .ok()
15476            else {
15477                return;
15478            };
15479
15480            let new_inline_diagnostics = cx
15481                .background_spawn(async move {
15482                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15483                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15484                        let message = diagnostic_entry
15485                            .diagnostic
15486                            .message
15487                            .split_once('\n')
15488                            .map(|(line, _)| line)
15489                            .map(SharedString::new)
15490                            .unwrap_or_else(|| {
15491                                SharedString::from(diagnostic_entry.diagnostic.message)
15492                            });
15493                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15494                        let (Ok(i) | Err(i)) = inline_diagnostics
15495                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15496                        inline_diagnostics.insert(
15497                            i,
15498                            (
15499                                start_anchor,
15500                                InlineDiagnostic {
15501                                    message,
15502                                    group_id: diagnostic_entry.diagnostic.group_id,
15503                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15504                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15505                                    severity: diagnostic_entry.diagnostic.severity,
15506                                },
15507                            ),
15508                        );
15509                    }
15510                    inline_diagnostics
15511                })
15512                .await;
15513
15514            editor
15515                .update(cx, |editor, cx| {
15516                    editor.inline_diagnostics = new_inline_diagnostics;
15517                    cx.notify();
15518                })
15519                .ok();
15520        });
15521    }
15522
15523    pub fn set_selections_from_remote(
15524        &mut self,
15525        selections: Vec<Selection<Anchor>>,
15526        pending_selection: Option<Selection<Anchor>>,
15527        window: &mut Window,
15528        cx: &mut Context<Self>,
15529    ) {
15530        let old_cursor_position = self.selections.newest_anchor().head();
15531        self.selections.change_with(cx, |s| {
15532            s.select_anchors(selections);
15533            if let Some(pending_selection) = pending_selection {
15534                s.set_pending(pending_selection, SelectMode::Character);
15535            } else {
15536                s.clear_pending();
15537            }
15538        });
15539        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15540    }
15541
15542    fn push_to_selection_history(&mut self) {
15543        self.selection_history.push(SelectionHistoryEntry {
15544            selections: self.selections.disjoint_anchors(),
15545            select_next_state: self.select_next_state.clone(),
15546            select_prev_state: self.select_prev_state.clone(),
15547            add_selections_state: self.add_selections_state.clone(),
15548        });
15549    }
15550
15551    pub fn transact(
15552        &mut self,
15553        window: &mut Window,
15554        cx: &mut Context<Self>,
15555        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15556    ) -> Option<TransactionId> {
15557        self.start_transaction_at(Instant::now(), window, cx);
15558        update(self, window, cx);
15559        self.end_transaction_at(Instant::now(), cx)
15560    }
15561
15562    pub fn start_transaction_at(
15563        &mut self,
15564        now: Instant,
15565        window: &mut Window,
15566        cx: &mut Context<Self>,
15567    ) {
15568        self.end_selection(window, cx);
15569        if let Some(tx_id) = self
15570            .buffer
15571            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15572        {
15573            self.selection_history
15574                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15575            cx.emit(EditorEvent::TransactionBegun {
15576                transaction_id: tx_id,
15577            })
15578        }
15579    }
15580
15581    pub fn end_transaction_at(
15582        &mut self,
15583        now: Instant,
15584        cx: &mut Context<Self>,
15585    ) -> Option<TransactionId> {
15586        if let Some(transaction_id) = self
15587            .buffer
15588            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15589        {
15590            if let Some((_, end_selections)) =
15591                self.selection_history.transaction_mut(transaction_id)
15592            {
15593                *end_selections = Some(self.selections.disjoint_anchors());
15594            } else {
15595                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15596            }
15597
15598            cx.emit(EditorEvent::Edited { transaction_id });
15599            Some(transaction_id)
15600        } else {
15601            None
15602        }
15603    }
15604
15605    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15606        if self.selection_mark_mode {
15607            self.change_selections(None, window, cx, |s| {
15608                s.move_with(|_, sel| {
15609                    sel.collapse_to(sel.head(), SelectionGoal::None);
15610                });
15611            })
15612        }
15613        self.selection_mark_mode = true;
15614        cx.notify();
15615    }
15616
15617    pub fn swap_selection_ends(
15618        &mut self,
15619        _: &actions::SwapSelectionEnds,
15620        window: &mut Window,
15621        cx: &mut Context<Self>,
15622    ) {
15623        self.change_selections(None, window, cx, |s| {
15624            s.move_with(|_, sel| {
15625                if sel.start != sel.end {
15626                    sel.reversed = !sel.reversed
15627                }
15628            });
15629        });
15630        self.request_autoscroll(Autoscroll::newest(), cx);
15631        cx.notify();
15632    }
15633
15634    pub fn toggle_fold(
15635        &mut self,
15636        _: &actions::ToggleFold,
15637        window: &mut Window,
15638        cx: &mut Context<Self>,
15639    ) {
15640        if self.is_singleton(cx) {
15641            let selection = self.selections.newest::<Point>(cx);
15642
15643            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15644            let range = if selection.is_empty() {
15645                let point = selection.head().to_display_point(&display_map);
15646                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15647                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15648                    .to_point(&display_map);
15649                start..end
15650            } else {
15651                selection.range()
15652            };
15653            if display_map.folds_in_range(range).next().is_some() {
15654                self.unfold_lines(&Default::default(), window, cx)
15655            } else {
15656                self.fold(&Default::default(), window, cx)
15657            }
15658        } else {
15659            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15660            let buffer_ids: HashSet<_> = self
15661                .selections
15662                .disjoint_anchor_ranges()
15663                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15664                .collect();
15665
15666            let should_unfold = buffer_ids
15667                .iter()
15668                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15669
15670            for buffer_id in buffer_ids {
15671                if should_unfold {
15672                    self.unfold_buffer(buffer_id, cx);
15673                } else {
15674                    self.fold_buffer(buffer_id, cx);
15675                }
15676            }
15677        }
15678    }
15679
15680    pub fn toggle_fold_recursive(
15681        &mut self,
15682        _: &actions::ToggleFoldRecursive,
15683        window: &mut Window,
15684        cx: &mut Context<Self>,
15685    ) {
15686        let selection = self.selections.newest::<Point>(cx);
15687
15688        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15689        let range = if selection.is_empty() {
15690            let point = selection.head().to_display_point(&display_map);
15691            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15692            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15693                .to_point(&display_map);
15694            start..end
15695        } else {
15696            selection.range()
15697        };
15698        if display_map.folds_in_range(range).next().is_some() {
15699            self.unfold_recursive(&Default::default(), window, cx)
15700        } else {
15701            self.fold_recursive(&Default::default(), window, cx)
15702        }
15703    }
15704
15705    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15706        if self.is_singleton(cx) {
15707            let mut to_fold = Vec::new();
15708            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15709            let selections = self.selections.all_adjusted(cx);
15710
15711            for selection in selections {
15712                let range = selection.range().sorted();
15713                let buffer_start_row = range.start.row;
15714
15715                if range.start.row != range.end.row {
15716                    let mut found = false;
15717                    let mut row = range.start.row;
15718                    while row <= range.end.row {
15719                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15720                        {
15721                            found = true;
15722                            row = crease.range().end.row + 1;
15723                            to_fold.push(crease);
15724                        } else {
15725                            row += 1
15726                        }
15727                    }
15728                    if found {
15729                        continue;
15730                    }
15731                }
15732
15733                for row in (0..=range.start.row).rev() {
15734                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15735                        if crease.range().end.row >= buffer_start_row {
15736                            to_fold.push(crease);
15737                            if row <= range.start.row {
15738                                break;
15739                            }
15740                        }
15741                    }
15742                }
15743            }
15744
15745            self.fold_creases(to_fold, true, window, cx);
15746        } else {
15747            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15748            let buffer_ids = self
15749                .selections
15750                .disjoint_anchor_ranges()
15751                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15752                .collect::<HashSet<_>>();
15753            for buffer_id in buffer_ids {
15754                self.fold_buffer(buffer_id, cx);
15755            }
15756        }
15757    }
15758
15759    fn fold_at_level(
15760        &mut self,
15761        fold_at: &FoldAtLevel,
15762        window: &mut Window,
15763        cx: &mut Context<Self>,
15764    ) {
15765        if !self.buffer.read(cx).is_singleton() {
15766            return;
15767        }
15768
15769        let fold_at_level = fold_at.0;
15770        let snapshot = self.buffer.read(cx).snapshot(cx);
15771        let mut to_fold = Vec::new();
15772        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15773
15774        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15775            while start_row < end_row {
15776                match self
15777                    .snapshot(window, cx)
15778                    .crease_for_buffer_row(MultiBufferRow(start_row))
15779                {
15780                    Some(crease) => {
15781                        let nested_start_row = crease.range().start.row + 1;
15782                        let nested_end_row = crease.range().end.row;
15783
15784                        if current_level < fold_at_level {
15785                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15786                        } else if current_level == fold_at_level {
15787                            to_fold.push(crease);
15788                        }
15789
15790                        start_row = nested_end_row + 1;
15791                    }
15792                    None => start_row += 1,
15793                }
15794            }
15795        }
15796
15797        self.fold_creases(to_fold, true, window, cx);
15798    }
15799
15800    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15801        if self.buffer.read(cx).is_singleton() {
15802            let mut fold_ranges = Vec::new();
15803            let snapshot = self.buffer.read(cx).snapshot(cx);
15804
15805            for row in 0..snapshot.max_row().0 {
15806                if let Some(foldable_range) = self
15807                    .snapshot(window, cx)
15808                    .crease_for_buffer_row(MultiBufferRow(row))
15809                {
15810                    fold_ranges.push(foldable_range);
15811                }
15812            }
15813
15814            self.fold_creases(fold_ranges, true, window, cx);
15815        } else {
15816            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15817                editor
15818                    .update_in(cx, |editor, _, cx| {
15819                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15820                            editor.fold_buffer(buffer_id, cx);
15821                        }
15822                    })
15823                    .ok();
15824            });
15825        }
15826    }
15827
15828    pub fn fold_function_bodies(
15829        &mut self,
15830        _: &actions::FoldFunctionBodies,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        let snapshot = self.buffer.read(cx).snapshot(cx);
15835
15836        let ranges = snapshot
15837            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15838            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15839            .collect::<Vec<_>>();
15840
15841        let creases = ranges
15842            .into_iter()
15843            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15844            .collect();
15845
15846        self.fold_creases(creases, true, window, cx);
15847    }
15848
15849    pub fn fold_recursive(
15850        &mut self,
15851        _: &actions::FoldRecursive,
15852        window: &mut Window,
15853        cx: &mut Context<Self>,
15854    ) {
15855        let mut to_fold = Vec::new();
15856        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15857        let selections = self.selections.all_adjusted(cx);
15858
15859        for selection in selections {
15860            let range = selection.range().sorted();
15861            let buffer_start_row = range.start.row;
15862
15863            if range.start.row != range.end.row {
15864                let mut found = false;
15865                for row in range.start.row..=range.end.row {
15866                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15867                        found = true;
15868                        to_fold.push(crease);
15869                    }
15870                }
15871                if found {
15872                    continue;
15873                }
15874            }
15875
15876            for row in (0..=range.start.row).rev() {
15877                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15878                    if crease.range().end.row >= buffer_start_row {
15879                        to_fold.push(crease);
15880                    } else {
15881                        break;
15882                    }
15883                }
15884            }
15885        }
15886
15887        self.fold_creases(to_fold, true, window, cx);
15888    }
15889
15890    pub fn fold_at(
15891        &mut self,
15892        buffer_row: MultiBufferRow,
15893        window: &mut Window,
15894        cx: &mut Context<Self>,
15895    ) {
15896        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15897
15898        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15899            let autoscroll = self
15900                .selections
15901                .all::<Point>(cx)
15902                .iter()
15903                .any(|selection| crease.range().overlaps(&selection.range()));
15904
15905            self.fold_creases(vec![crease], autoscroll, window, cx);
15906        }
15907    }
15908
15909    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15910        if self.is_singleton(cx) {
15911            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15912            let buffer = &display_map.buffer_snapshot;
15913            let selections = self.selections.all::<Point>(cx);
15914            let ranges = selections
15915                .iter()
15916                .map(|s| {
15917                    let range = s.display_range(&display_map).sorted();
15918                    let mut start = range.start.to_point(&display_map);
15919                    let mut end = range.end.to_point(&display_map);
15920                    start.column = 0;
15921                    end.column = buffer.line_len(MultiBufferRow(end.row));
15922                    start..end
15923                })
15924                .collect::<Vec<_>>();
15925
15926            self.unfold_ranges(&ranges, true, true, cx);
15927        } else {
15928            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15929            let buffer_ids = self
15930                .selections
15931                .disjoint_anchor_ranges()
15932                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15933                .collect::<HashSet<_>>();
15934            for buffer_id in buffer_ids {
15935                self.unfold_buffer(buffer_id, cx);
15936            }
15937        }
15938    }
15939
15940    pub fn unfold_recursive(
15941        &mut self,
15942        _: &UnfoldRecursive,
15943        _window: &mut Window,
15944        cx: &mut Context<Self>,
15945    ) {
15946        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15947        let selections = self.selections.all::<Point>(cx);
15948        let ranges = selections
15949            .iter()
15950            .map(|s| {
15951                let mut range = s.display_range(&display_map).sorted();
15952                *range.start.column_mut() = 0;
15953                *range.end.column_mut() = display_map.line_len(range.end.row());
15954                let start = range.start.to_point(&display_map);
15955                let end = range.end.to_point(&display_map);
15956                start..end
15957            })
15958            .collect::<Vec<_>>();
15959
15960        self.unfold_ranges(&ranges, true, true, cx);
15961    }
15962
15963    pub fn unfold_at(
15964        &mut self,
15965        buffer_row: MultiBufferRow,
15966        _window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) {
15969        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15970
15971        let intersection_range = Point::new(buffer_row.0, 0)
15972            ..Point::new(
15973                buffer_row.0,
15974                display_map.buffer_snapshot.line_len(buffer_row),
15975            );
15976
15977        let autoscroll = self
15978            .selections
15979            .all::<Point>(cx)
15980            .iter()
15981            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15982
15983        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15984    }
15985
15986    pub fn unfold_all(
15987        &mut self,
15988        _: &actions::UnfoldAll,
15989        _window: &mut Window,
15990        cx: &mut Context<Self>,
15991    ) {
15992        if self.buffer.read(cx).is_singleton() {
15993            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15994            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15995        } else {
15996            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15997                editor
15998                    .update(cx, |editor, cx| {
15999                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16000                            editor.unfold_buffer(buffer_id, cx);
16001                        }
16002                    })
16003                    .ok();
16004            });
16005        }
16006    }
16007
16008    pub fn fold_selected_ranges(
16009        &mut self,
16010        _: &FoldSelectedRanges,
16011        window: &mut Window,
16012        cx: &mut Context<Self>,
16013    ) {
16014        let selections = self.selections.all_adjusted(cx);
16015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16016        let ranges = selections
16017            .into_iter()
16018            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16019            .collect::<Vec<_>>();
16020        self.fold_creases(ranges, true, window, cx);
16021    }
16022
16023    pub fn fold_ranges<T: ToOffset + Clone>(
16024        &mut self,
16025        ranges: Vec<Range<T>>,
16026        auto_scroll: bool,
16027        window: &mut Window,
16028        cx: &mut Context<Self>,
16029    ) {
16030        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16031        let ranges = ranges
16032            .into_iter()
16033            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16034            .collect::<Vec<_>>();
16035        self.fold_creases(ranges, auto_scroll, window, cx);
16036    }
16037
16038    pub fn fold_creases<T: ToOffset + Clone>(
16039        &mut self,
16040        creases: Vec<Crease<T>>,
16041        auto_scroll: bool,
16042        _window: &mut Window,
16043        cx: &mut Context<Self>,
16044    ) {
16045        if creases.is_empty() {
16046            return;
16047        }
16048
16049        let mut buffers_affected = HashSet::default();
16050        let multi_buffer = self.buffer().read(cx);
16051        for crease in &creases {
16052            if let Some((_, buffer, _)) =
16053                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16054            {
16055                buffers_affected.insert(buffer.read(cx).remote_id());
16056            };
16057        }
16058
16059        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16060
16061        if auto_scroll {
16062            self.request_autoscroll(Autoscroll::fit(), cx);
16063        }
16064
16065        cx.notify();
16066
16067        self.scrollbar_marker_state.dirty = true;
16068        self.folds_did_change(cx);
16069    }
16070
16071    /// Removes any folds whose ranges intersect any of the given ranges.
16072    pub fn unfold_ranges<T: ToOffset + Clone>(
16073        &mut self,
16074        ranges: &[Range<T>],
16075        inclusive: bool,
16076        auto_scroll: bool,
16077        cx: &mut Context<Self>,
16078    ) {
16079        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16080            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16081        });
16082        self.folds_did_change(cx);
16083    }
16084
16085    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16086        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16087            return;
16088        }
16089        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16090        self.display_map.update(cx, |display_map, cx| {
16091            display_map.fold_buffers([buffer_id], cx)
16092        });
16093        cx.emit(EditorEvent::BufferFoldToggled {
16094            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16095            folded: true,
16096        });
16097        cx.notify();
16098    }
16099
16100    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16101        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16102            return;
16103        }
16104        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16105        self.display_map.update(cx, |display_map, cx| {
16106            display_map.unfold_buffers([buffer_id], cx);
16107        });
16108        cx.emit(EditorEvent::BufferFoldToggled {
16109            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16110            folded: false,
16111        });
16112        cx.notify();
16113    }
16114
16115    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16116        self.display_map.read(cx).is_buffer_folded(buffer)
16117    }
16118
16119    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16120        self.display_map.read(cx).folded_buffers()
16121    }
16122
16123    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16124        self.display_map.update(cx, |display_map, cx| {
16125            display_map.disable_header_for_buffer(buffer_id, cx);
16126        });
16127        cx.notify();
16128    }
16129
16130    /// Removes any folds with the given ranges.
16131    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16132        &mut self,
16133        ranges: &[Range<T>],
16134        type_id: TypeId,
16135        auto_scroll: bool,
16136        cx: &mut Context<Self>,
16137    ) {
16138        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16139            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16140        });
16141        self.folds_did_change(cx);
16142    }
16143
16144    fn remove_folds_with<T: ToOffset + Clone>(
16145        &mut self,
16146        ranges: &[Range<T>],
16147        auto_scroll: bool,
16148        cx: &mut Context<Self>,
16149        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16150    ) {
16151        if ranges.is_empty() {
16152            return;
16153        }
16154
16155        let mut buffers_affected = HashSet::default();
16156        let multi_buffer = self.buffer().read(cx);
16157        for range in ranges {
16158            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16159                buffers_affected.insert(buffer.read(cx).remote_id());
16160            };
16161        }
16162
16163        self.display_map.update(cx, update);
16164
16165        if auto_scroll {
16166            self.request_autoscroll(Autoscroll::fit(), cx);
16167        }
16168
16169        cx.notify();
16170        self.scrollbar_marker_state.dirty = true;
16171        self.active_indent_guides_state.dirty = true;
16172    }
16173
16174    pub fn update_fold_widths(
16175        &mut self,
16176        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16177        cx: &mut Context<Self>,
16178    ) -> bool {
16179        self.display_map
16180            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16181    }
16182
16183    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16184        self.display_map.read(cx).fold_placeholder.clone()
16185    }
16186
16187    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16188        self.buffer.update(cx, |buffer, cx| {
16189            buffer.set_all_diff_hunks_expanded(cx);
16190        });
16191    }
16192
16193    pub fn expand_all_diff_hunks(
16194        &mut self,
16195        _: &ExpandAllDiffHunks,
16196        _window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.buffer.update(cx, |buffer, cx| {
16200            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16201        });
16202    }
16203
16204    pub fn toggle_selected_diff_hunks(
16205        &mut self,
16206        _: &ToggleSelectedDiffHunks,
16207        _window: &mut Window,
16208        cx: &mut Context<Self>,
16209    ) {
16210        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16211        self.toggle_diff_hunks_in_ranges(ranges, cx);
16212    }
16213
16214    pub fn diff_hunks_in_ranges<'a>(
16215        &'a self,
16216        ranges: &'a [Range<Anchor>],
16217        buffer: &'a MultiBufferSnapshot,
16218    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16219        ranges.iter().flat_map(move |range| {
16220            let end_excerpt_id = range.end.excerpt_id;
16221            let range = range.to_point(buffer);
16222            let mut peek_end = range.end;
16223            if range.end.row < buffer.max_row().0 {
16224                peek_end = Point::new(range.end.row + 1, 0);
16225            }
16226            buffer
16227                .diff_hunks_in_range(range.start..peek_end)
16228                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16229        })
16230    }
16231
16232    pub fn has_stageable_diff_hunks_in_ranges(
16233        &self,
16234        ranges: &[Range<Anchor>],
16235        snapshot: &MultiBufferSnapshot,
16236    ) -> bool {
16237        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16238        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16239    }
16240
16241    pub fn toggle_staged_selected_diff_hunks(
16242        &mut self,
16243        _: &::git::ToggleStaged,
16244        _: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        let snapshot = self.buffer.read(cx).snapshot(cx);
16248        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16249        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16250        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16251    }
16252
16253    pub fn set_render_diff_hunk_controls(
16254        &mut self,
16255        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16256        cx: &mut Context<Self>,
16257    ) {
16258        self.render_diff_hunk_controls = render_diff_hunk_controls;
16259        cx.notify();
16260    }
16261
16262    pub fn stage_and_next(
16263        &mut self,
16264        _: &::git::StageAndNext,
16265        window: &mut Window,
16266        cx: &mut Context<Self>,
16267    ) {
16268        self.do_stage_or_unstage_and_next(true, window, cx);
16269    }
16270
16271    pub fn unstage_and_next(
16272        &mut self,
16273        _: &::git::UnstageAndNext,
16274        window: &mut Window,
16275        cx: &mut Context<Self>,
16276    ) {
16277        self.do_stage_or_unstage_and_next(false, window, cx);
16278    }
16279
16280    pub fn stage_or_unstage_diff_hunks(
16281        &mut self,
16282        stage: bool,
16283        ranges: Vec<Range<Anchor>>,
16284        cx: &mut Context<Self>,
16285    ) {
16286        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16287        cx.spawn(async move |this, cx| {
16288            task.await?;
16289            this.update(cx, |this, cx| {
16290                let snapshot = this.buffer.read(cx).snapshot(cx);
16291                let chunk_by = this
16292                    .diff_hunks_in_ranges(&ranges, &snapshot)
16293                    .chunk_by(|hunk| hunk.buffer_id);
16294                for (buffer_id, hunks) in &chunk_by {
16295                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16296                }
16297            })
16298        })
16299        .detach_and_log_err(cx);
16300    }
16301
16302    fn save_buffers_for_ranges_if_needed(
16303        &mut self,
16304        ranges: &[Range<Anchor>],
16305        cx: &mut Context<Editor>,
16306    ) -> Task<Result<()>> {
16307        let multibuffer = self.buffer.read(cx);
16308        let snapshot = multibuffer.read(cx);
16309        let buffer_ids: HashSet<_> = ranges
16310            .iter()
16311            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16312            .collect();
16313        drop(snapshot);
16314
16315        let mut buffers = HashSet::default();
16316        for buffer_id in buffer_ids {
16317            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16318                let buffer = buffer_entity.read(cx);
16319                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16320                {
16321                    buffers.insert(buffer_entity);
16322                }
16323            }
16324        }
16325
16326        if let Some(project) = &self.project {
16327            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16328        } else {
16329            Task::ready(Ok(()))
16330        }
16331    }
16332
16333    fn do_stage_or_unstage_and_next(
16334        &mut self,
16335        stage: bool,
16336        window: &mut Window,
16337        cx: &mut Context<Self>,
16338    ) {
16339        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16340
16341        if ranges.iter().any(|range| range.start != range.end) {
16342            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16343            return;
16344        }
16345
16346        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16347        let snapshot = self.snapshot(window, cx);
16348        let position = self.selections.newest::<Point>(cx).head();
16349        let mut row = snapshot
16350            .buffer_snapshot
16351            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16352            .find(|hunk| hunk.row_range.start.0 > position.row)
16353            .map(|hunk| hunk.row_range.start);
16354
16355        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16356        // Outside of the project diff editor, wrap around to the beginning.
16357        if !all_diff_hunks_expanded {
16358            row = row.or_else(|| {
16359                snapshot
16360                    .buffer_snapshot
16361                    .diff_hunks_in_range(Point::zero()..position)
16362                    .find(|hunk| hunk.row_range.end.0 < position.row)
16363                    .map(|hunk| hunk.row_range.start)
16364            });
16365        }
16366
16367        if let Some(row) = row {
16368            let destination = Point::new(row.0, 0);
16369            let autoscroll = Autoscroll::center();
16370
16371            self.unfold_ranges(&[destination..destination], false, false, cx);
16372            self.change_selections(Some(autoscroll), window, cx, |s| {
16373                s.select_ranges([destination..destination]);
16374            });
16375        }
16376    }
16377
16378    fn do_stage_or_unstage(
16379        &self,
16380        stage: bool,
16381        buffer_id: BufferId,
16382        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16383        cx: &mut App,
16384    ) -> Option<()> {
16385        let project = self.project.as_ref()?;
16386        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16387        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16388        let buffer_snapshot = buffer.read(cx).snapshot();
16389        let file_exists = buffer_snapshot
16390            .file()
16391            .is_some_and(|file| file.disk_state().exists());
16392        diff.update(cx, |diff, cx| {
16393            diff.stage_or_unstage_hunks(
16394                stage,
16395                &hunks
16396                    .map(|hunk| buffer_diff::DiffHunk {
16397                        buffer_range: hunk.buffer_range,
16398                        diff_base_byte_range: hunk.diff_base_byte_range,
16399                        secondary_status: hunk.secondary_status,
16400                        range: Point::zero()..Point::zero(), // unused
16401                    })
16402                    .collect::<Vec<_>>(),
16403                &buffer_snapshot,
16404                file_exists,
16405                cx,
16406            )
16407        });
16408        None
16409    }
16410
16411    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16412        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16413        self.buffer
16414            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16415    }
16416
16417    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16418        self.buffer.update(cx, |buffer, cx| {
16419            let ranges = vec![Anchor::min()..Anchor::max()];
16420            if !buffer.all_diff_hunks_expanded()
16421                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16422            {
16423                buffer.collapse_diff_hunks(ranges, cx);
16424                true
16425            } else {
16426                false
16427            }
16428        })
16429    }
16430
16431    fn toggle_diff_hunks_in_ranges(
16432        &mut self,
16433        ranges: Vec<Range<Anchor>>,
16434        cx: &mut Context<Editor>,
16435    ) {
16436        self.buffer.update(cx, |buffer, cx| {
16437            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16438            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16439        })
16440    }
16441
16442    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16443        self.buffer.update(cx, |buffer, cx| {
16444            let snapshot = buffer.snapshot(cx);
16445            let excerpt_id = range.end.excerpt_id;
16446            let point_range = range.to_point(&snapshot);
16447            let expand = !buffer.single_hunk_is_expanded(range, cx);
16448            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16449        })
16450    }
16451
16452    pub(crate) fn apply_all_diff_hunks(
16453        &mut self,
16454        _: &ApplyAllDiffHunks,
16455        window: &mut Window,
16456        cx: &mut Context<Self>,
16457    ) {
16458        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16459
16460        let buffers = self.buffer.read(cx).all_buffers();
16461        for branch_buffer in buffers {
16462            branch_buffer.update(cx, |branch_buffer, cx| {
16463                branch_buffer.merge_into_base(Vec::new(), cx);
16464            });
16465        }
16466
16467        if let Some(project) = self.project.clone() {
16468            self.save(true, project, window, cx).detach_and_log_err(cx);
16469        }
16470    }
16471
16472    pub(crate) fn apply_selected_diff_hunks(
16473        &mut self,
16474        _: &ApplyDiffHunk,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) {
16478        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16479        let snapshot = self.snapshot(window, cx);
16480        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16481        let mut ranges_by_buffer = HashMap::default();
16482        self.transact(window, cx, |editor, _window, cx| {
16483            for hunk in hunks {
16484                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16485                    ranges_by_buffer
16486                        .entry(buffer.clone())
16487                        .or_insert_with(Vec::new)
16488                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16489                }
16490            }
16491
16492            for (buffer, ranges) in ranges_by_buffer {
16493                buffer.update(cx, |buffer, cx| {
16494                    buffer.merge_into_base(ranges, cx);
16495                });
16496            }
16497        });
16498
16499        if let Some(project) = self.project.clone() {
16500            self.save(true, project, window, cx).detach_and_log_err(cx);
16501        }
16502    }
16503
16504    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16505        if hovered != self.gutter_hovered {
16506            self.gutter_hovered = hovered;
16507            cx.notify();
16508        }
16509    }
16510
16511    pub fn insert_blocks(
16512        &mut self,
16513        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16514        autoscroll: Option<Autoscroll>,
16515        cx: &mut Context<Self>,
16516    ) -> Vec<CustomBlockId> {
16517        let blocks = self
16518            .display_map
16519            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16520        if let Some(autoscroll) = autoscroll {
16521            self.request_autoscroll(autoscroll, cx);
16522        }
16523        cx.notify();
16524        blocks
16525    }
16526
16527    pub fn resize_blocks(
16528        &mut self,
16529        heights: HashMap<CustomBlockId, u32>,
16530        autoscroll: Option<Autoscroll>,
16531        cx: &mut Context<Self>,
16532    ) {
16533        self.display_map
16534            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16535        if let Some(autoscroll) = autoscroll {
16536            self.request_autoscroll(autoscroll, cx);
16537        }
16538        cx.notify();
16539    }
16540
16541    pub fn replace_blocks(
16542        &mut self,
16543        renderers: HashMap<CustomBlockId, RenderBlock>,
16544        autoscroll: Option<Autoscroll>,
16545        cx: &mut Context<Self>,
16546    ) {
16547        self.display_map
16548            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16549        if let Some(autoscroll) = autoscroll {
16550            self.request_autoscroll(autoscroll, cx);
16551        }
16552        cx.notify();
16553    }
16554
16555    pub fn remove_blocks(
16556        &mut self,
16557        block_ids: HashSet<CustomBlockId>,
16558        autoscroll: Option<Autoscroll>,
16559        cx: &mut Context<Self>,
16560    ) {
16561        self.display_map.update(cx, |display_map, cx| {
16562            display_map.remove_blocks(block_ids, cx)
16563        });
16564        if let Some(autoscroll) = autoscroll {
16565            self.request_autoscroll(autoscroll, cx);
16566        }
16567        cx.notify();
16568    }
16569
16570    pub fn row_for_block(
16571        &self,
16572        block_id: CustomBlockId,
16573        cx: &mut Context<Self>,
16574    ) -> Option<DisplayRow> {
16575        self.display_map
16576            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16577    }
16578
16579    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16580        self.focused_block = Some(focused_block);
16581    }
16582
16583    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16584        self.focused_block.take()
16585    }
16586
16587    pub fn insert_creases(
16588        &mut self,
16589        creases: impl IntoIterator<Item = Crease<Anchor>>,
16590        cx: &mut Context<Self>,
16591    ) -> Vec<CreaseId> {
16592        self.display_map
16593            .update(cx, |map, cx| map.insert_creases(creases, cx))
16594    }
16595
16596    pub fn remove_creases(
16597        &mut self,
16598        ids: impl IntoIterator<Item = CreaseId>,
16599        cx: &mut Context<Self>,
16600    ) -> Vec<(CreaseId, Range<Anchor>)> {
16601        self.display_map
16602            .update(cx, |map, cx| map.remove_creases(ids, cx))
16603    }
16604
16605    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16606        self.display_map
16607            .update(cx, |map, cx| map.snapshot(cx))
16608            .longest_row()
16609    }
16610
16611    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16612        self.display_map
16613            .update(cx, |map, cx| map.snapshot(cx))
16614            .max_point()
16615    }
16616
16617    pub fn text(&self, cx: &App) -> String {
16618        self.buffer.read(cx).read(cx).text()
16619    }
16620
16621    pub fn is_empty(&self, cx: &App) -> bool {
16622        self.buffer.read(cx).read(cx).is_empty()
16623    }
16624
16625    pub fn text_option(&self, cx: &App) -> Option<String> {
16626        let text = self.text(cx);
16627        let text = text.trim();
16628
16629        if text.is_empty() {
16630            return None;
16631        }
16632
16633        Some(text.to_string())
16634    }
16635
16636    pub fn set_text(
16637        &mut self,
16638        text: impl Into<Arc<str>>,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) {
16642        self.transact(window, cx, |this, _, cx| {
16643            this.buffer
16644                .read(cx)
16645                .as_singleton()
16646                .expect("you can only call set_text on editors for singleton buffers")
16647                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16648        });
16649    }
16650
16651    pub fn display_text(&self, cx: &mut App) -> String {
16652        self.display_map
16653            .update(cx, |map, cx| map.snapshot(cx))
16654            .text()
16655    }
16656
16657    fn create_minimap(
16658        &self,
16659        minimap_settings: MinimapSettings,
16660        window: &mut Window,
16661        cx: &mut Context<Self>,
16662    ) -> Option<Entity<Self>> {
16663        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16664            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16665    }
16666
16667    fn initialize_new_minimap(
16668        &self,
16669        minimap_settings: MinimapSettings,
16670        window: &mut Window,
16671        cx: &mut Context<Self>,
16672    ) -> Entity<Self> {
16673        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16674
16675        let mut minimap = Editor::new_internal(
16676            EditorMode::Minimap {
16677                parent: cx.weak_entity(),
16678            },
16679            self.buffer.clone(),
16680            self.project.clone(),
16681            Some(self.display_map.clone()),
16682            window,
16683            cx,
16684        );
16685        minimap.scroll_manager.clone_state(&self.scroll_manager);
16686        minimap.set_text_style_refinement(TextStyleRefinement {
16687            font_size: Some(MINIMAP_FONT_SIZE),
16688            font_weight: Some(MINIMAP_FONT_WEIGHT),
16689            ..Default::default()
16690        });
16691        minimap.update_minimap_configuration(minimap_settings, cx);
16692        cx.new(|_| minimap)
16693    }
16694
16695    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16696        let current_line_highlight = minimap_settings
16697            .current_line_highlight
16698            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16699        self.set_current_line_highlight(Some(current_line_highlight));
16700    }
16701
16702    pub fn minimap(&self) -> Option<&Entity<Self>> {
16703        self.minimap
16704            .as_ref()
16705            .filter(|_| self.minimap_visibility.visible())
16706    }
16707
16708    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16709        let mut wrap_guides = smallvec![];
16710
16711        if self.show_wrap_guides == Some(false) {
16712            return wrap_guides;
16713        }
16714
16715        let settings = self.buffer.read(cx).language_settings(cx);
16716        if settings.show_wrap_guides {
16717            match self.soft_wrap_mode(cx) {
16718                SoftWrap::Column(soft_wrap) => {
16719                    wrap_guides.push((soft_wrap as usize, true));
16720                }
16721                SoftWrap::Bounded(soft_wrap) => {
16722                    wrap_guides.push((soft_wrap as usize, true));
16723                }
16724                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16725            }
16726            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16727        }
16728
16729        wrap_guides
16730    }
16731
16732    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16733        let settings = self.buffer.read(cx).language_settings(cx);
16734        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16735        match mode {
16736            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16737                SoftWrap::None
16738            }
16739            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16740            language_settings::SoftWrap::PreferredLineLength => {
16741                SoftWrap::Column(settings.preferred_line_length)
16742            }
16743            language_settings::SoftWrap::Bounded => {
16744                SoftWrap::Bounded(settings.preferred_line_length)
16745            }
16746        }
16747    }
16748
16749    pub fn set_soft_wrap_mode(
16750        &mut self,
16751        mode: language_settings::SoftWrap,
16752
16753        cx: &mut Context<Self>,
16754    ) {
16755        self.soft_wrap_mode_override = Some(mode);
16756        cx.notify();
16757    }
16758
16759    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16760        self.hard_wrap = hard_wrap;
16761        cx.notify();
16762    }
16763
16764    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16765        self.text_style_refinement = Some(style);
16766    }
16767
16768    /// called by the Element so we know what style we were most recently rendered with.
16769    pub(crate) fn set_style(
16770        &mut self,
16771        style: EditorStyle,
16772        window: &mut Window,
16773        cx: &mut Context<Self>,
16774    ) {
16775        // We intentionally do not inform the display map about the minimap style
16776        // so that wrapping is not recalculated and stays consistent for the editor
16777        // and its linked minimap.
16778        if !self.mode.is_minimap() {
16779            let rem_size = window.rem_size();
16780            self.display_map.update(cx, |map, cx| {
16781                map.set_font(
16782                    style.text.font(),
16783                    style.text.font_size.to_pixels(rem_size),
16784                    cx,
16785                )
16786            });
16787        }
16788        self.style = Some(style);
16789    }
16790
16791    pub fn style(&self) -> Option<&EditorStyle> {
16792        self.style.as_ref()
16793    }
16794
16795    // Called by the element. This method is not designed to be called outside of the editor
16796    // element's layout code because it does not notify when rewrapping is computed synchronously.
16797    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16798        self.display_map
16799            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16800    }
16801
16802    pub fn set_soft_wrap(&mut self) {
16803        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16804    }
16805
16806    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16807        if self.soft_wrap_mode_override.is_some() {
16808            self.soft_wrap_mode_override.take();
16809        } else {
16810            let soft_wrap = match self.soft_wrap_mode(cx) {
16811                SoftWrap::GitDiff => return,
16812                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16813                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16814                    language_settings::SoftWrap::None
16815                }
16816            };
16817            self.soft_wrap_mode_override = Some(soft_wrap);
16818        }
16819        cx.notify();
16820    }
16821
16822    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16823        let Some(workspace) = self.workspace() else {
16824            return;
16825        };
16826        let fs = workspace.read(cx).app_state().fs.clone();
16827        let current_show = TabBarSettings::get_global(cx).show;
16828        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16829            setting.show = Some(!current_show);
16830        });
16831    }
16832
16833    pub fn toggle_indent_guides(
16834        &mut self,
16835        _: &ToggleIndentGuides,
16836        _: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) {
16839        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16840            self.buffer
16841                .read(cx)
16842                .language_settings(cx)
16843                .indent_guides
16844                .enabled
16845        });
16846        self.show_indent_guides = Some(!currently_enabled);
16847        cx.notify();
16848    }
16849
16850    fn should_show_indent_guides(&self) -> Option<bool> {
16851        self.show_indent_guides
16852    }
16853
16854    pub fn toggle_line_numbers(
16855        &mut self,
16856        _: &ToggleLineNumbers,
16857        _: &mut Window,
16858        cx: &mut Context<Self>,
16859    ) {
16860        let mut editor_settings = EditorSettings::get_global(cx).clone();
16861        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16862        EditorSettings::override_global(editor_settings, cx);
16863    }
16864
16865    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16866        if let Some(show_line_numbers) = self.show_line_numbers {
16867            return show_line_numbers;
16868        }
16869        EditorSettings::get_global(cx).gutter.line_numbers
16870    }
16871
16872    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16873        self.use_relative_line_numbers
16874            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16875    }
16876
16877    pub fn toggle_relative_line_numbers(
16878        &mut self,
16879        _: &ToggleRelativeLineNumbers,
16880        _: &mut Window,
16881        cx: &mut Context<Self>,
16882    ) {
16883        let is_relative = self.should_use_relative_line_numbers(cx);
16884        self.set_relative_line_number(Some(!is_relative), cx)
16885    }
16886
16887    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16888        self.use_relative_line_numbers = is_relative;
16889        cx.notify();
16890    }
16891
16892    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16893        self.show_gutter = show_gutter;
16894        cx.notify();
16895    }
16896
16897    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16898        self.show_scrollbars = show_scrollbars;
16899        cx.notify();
16900    }
16901
16902    pub fn set_minimap_visibility(
16903        &mut self,
16904        minimap_visibility: MinimapVisibility,
16905        window: &mut Window,
16906        cx: &mut Context<Self>,
16907    ) {
16908        if self.minimap_visibility != minimap_visibility {
16909            if minimap_visibility.visible() && self.minimap.is_none() {
16910                let minimap_settings = EditorSettings::get_global(cx).minimap;
16911                self.minimap =
16912                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16913            }
16914            self.minimap_visibility = minimap_visibility;
16915            cx.notify();
16916        }
16917    }
16918
16919    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16920        self.set_show_scrollbars(false, cx);
16921        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16922    }
16923
16924    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16925        self.show_line_numbers = Some(show_line_numbers);
16926        cx.notify();
16927    }
16928
16929    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16930        self.disable_expand_excerpt_buttons = true;
16931        cx.notify();
16932    }
16933
16934    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16935        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16936        cx.notify();
16937    }
16938
16939    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16940        self.show_code_actions = Some(show_code_actions);
16941        cx.notify();
16942    }
16943
16944    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16945        self.show_runnables = Some(show_runnables);
16946        cx.notify();
16947    }
16948
16949    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16950        self.show_breakpoints = Some(show_breakpoints);
16951        cx.notify();
16952    }
16953
16954    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16955        if self.display_map.read(cx).masked != masked {
16956            self.display_map.update(cx, |map, _| map.masked = masked);
16957        }
16958        cx.notify()
16959    }
16960
16961    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16962        self.show_wrap_guides = Some(show_wrap_guides);
16963        cx.notify();
16964    }
16965
16966    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16967        self.show_indent_guides = Some(show_indent_guides);
16968        cx.notify();
16969    }
16970
16971    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16972        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16973            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16974                if let Some(dir) = file.abs_path(cx).parent() {
16975                    return Some(dir.to_owned());
16976                }
16977            }
16978
16979            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16980                return Some(project_path.path.to_path_buf());
16981            }
16982        }
16983
16984        None
16985    }
16986
16987    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16988        self.active_excerpt(cx)?
16989            .1
16990            .read(cx)
16991            .file()
16992            .and_then(|f| f.as_local())
16993    }
16994
16995    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16996        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16997            let buffer = buffer.read(cx);
16998            if let Some(project_path) = buffer.project_path(cx) {
16999                let project = self.project.as_ref()?.read(cx);
17000                project.absolute_path(&project_path, cx)
17001            } else {
17002                buffer
17003                    .file()
17004                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17005            }
17006        })
17007    }
17008
17009    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17010        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17011            let project_path = buffer.read(cx).project_path(cx)?;
17012            let project = self.project.as_ref()?.read(cx);
17013            let entry = project.entry_for_path(&project_path, cx)?;
17014            let path = entry.path.to_path_buf();
17015            Some(path)
17016        })
17017    }
17018
17019    pub fn reveal_in_finder(
17020        &mut self,
17021        _: &RevealInFileManager,
17022        _window: &mut Window,
17023        cx: &mut Context<Self>,
17024    ) {
17025        if let Some(target) = self.target_file(cx) {
17026            cx.reveal_path(&target.abs_path(cx));
17027        }
17028    }
17029
17030    pub fn copy_path(
17031        &mut self,
17032        _: &zed_actions::workspace::CopyPath,
17033        _window: &mut Window,
17034        cx: &mut Context<Self>,
17035    ) {
17036        if let Some(path) = self.target_file_abs_path(cx) {
17037            if let Some(path) = path.to_str() {
17038                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17039            }
17040        }
17041    }
17042
17043    pub fn copy_relative_path(
17044        &mut self,
17045        _: &zed_actions::workspace::CopyRelativePath,
17046        _window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        if let Some(path) = self.target_file_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 project_path(&self, cx: &App) -> Option<ProjectPath> {
17057        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17058            buffer.read(cx).project_path(cx)
17059        } else {
17060            None
17061        }
17062    }
17063
17064    // Returns true if the editor handled a go-to-line request
17065    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17066        maybe!({
17067            let breakpoint_store = self.breakpoint_store.as_ref()?;
17068
17069            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17070            else {
17071                self.clear_row_highlights::<ActiveDebugLine>();
17072                return None;
17073            };
17074
17075            let position = active_stack_frame.position;
17076            let buffer_id = position.buffer_id?;
17077            let snapshot = self
17078                .project
17079                .as_ref()?
17080                .read(cx)
17081                .buffer_for_id(buffer_id, cx)?
17082                .read(cx)
17083                .snapshot();
17084
17085            let mut handled = false;
17086            for (id, ExcerptRange { context, .. }) in
17087                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17088            {
17089                if context.start.cmp(&position, &snapshot).is_ge()
17090                    || context.end.cmp(&position, &snapshot).is_lt()
17091                {
17092                    continue;
17093                }
17094                let snapshot = self.buffer.read(cx).snapshot(cx);
17095                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17096
17097                handled = true;
17098                self.clear_row_highlights::<ActiveDebugLine>();
17099
17100                self.go_to_line::<ActiveDebugLine>(
17101                    multibuffer_anchor,
17102                    Some(cx.theme().colors().editor_debugger_active_line_background),
17103                    window,
17104                    cx,
17105                );
17106
17107                cx.notify();
17108            }
17109
17110            handled.then_some(())
17111        })
17112        .is_some()
17113    }
17114
17115    pub fn copy_file_name_without_extension(
17116        &mut self,
17117        _: &CopyFileNameWithoutExtension,
17118        _: &mut Window,
17119        cx: &mut Context<Self>,
17120    ) {
17121        if let Some(file) = self.target_file(cx) {
17122            if let Some(file_stem) = file.path().file_stem() {
17123                if let Some(name) = file_stem.to_str() {
17124                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17125                }
17126            }
17127        }
17128    }
17129
17130    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17131        if let Some(file) = self.target_file(cx) {
17132            if let Some(file_name) = file.path().file_name() {
17133                if let Some(name) = file_name.to_str() {
17134                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17135                }
17136            }
17137        }
17138    }
17139
17140    pub fn toggle_git_blame(
17141        &mut self,
17142        _: &::git::Blame,
17143        window: &mut Window,
17144        cx: &mut Context<Self>,
17145    ) {
17146        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17147
17148        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17149            self.start_git_blame(true, window, cx);
17150        }
17151
17152        cx.notify();
17153    }
17154
17155    pub fn toggle_git_blame_inline(
17156        &mut self,
17157        _: &ToggleGitBlameInline,
17158        window: &mut Window,
17159        cx: &mut Context<Self>,
17160    ) {
17161        self.toggle_git_blame_inline_internal(true, window, cx);
17162        cx.notify();
17163    }
17164
17165    pub fn open_git_blame_commit(
17166        &mut self,
17167        _: &OpenGitBlameCommit,
17168        window: &mut Window,
17169        cx: &mut Context<Self>,
17170    ) {
17171        self.open_git_blame_commit_internal(window, cx);
17172    }
17173
17174    fn open_git_blame_commit_internal(
17175        &mut self,
17176        window: &mut Window,
17177        cx: &mut Context<Self>,
17178    ) -> Option<()> {
17179        let blame = self.blame.as_ref()?;
17180        let snapshot = self.snapshot(window, cx);
17181        let cursor = self.selections.newest::<Point>(cx).head();
17182        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17183        let blame_entry = blame
17184            .update(cx, |blame, cx| {
17185                blame
17186                    .blame_for_rows(
17187                        &[RowInfo {
17188                            buffer_id: Some(buffer.remote_id()),
17189                            buffer_row: Some(point.row),
17190                            ..Default::default()
17191                        }],
17192                        cx,
17193                    )
17194                    .next()
17195            })
17196            .flatten()?;
17197        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17198        let repo = blame.read(cx).repository(cx)?;
17199        let workspace = self.workspace()?.downgrade();
17200        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17201        None
17202    }
17203
17204    pub fn git_blame_inline_enabled(&self) -> bool {
17205        self.git_blame_inline_enabled
17206    }
17207
17208    pub fn toggle_selection_menu(
17209        &mut self,
17210        _: &ToggleSelectionMenu,
17211        _: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        self.show_selection_menu = self
17215            .show_selection_menu
17216            .map(|show_selections_menu| !show_selections_menu)
17217            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17218
17219        cx.notify();
17220    }
17221
17222    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17223        self.show_selection_menu
17224            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17225    }
17226
17227    fn start_git_blame(
17228        &mut self,
17229        user_triggered: bool,
17230        window: &mut Window,
17231        cx: &mut Context<Self>,
17232    ) {
17233        if let Some(project) = self.project.as_ref() {
17234            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17235                return;
17236            };
17237
17238            if buffer.read(cx).file().is_none() {
17239                return;
17240            }
17241
17242            let focused = self.focus_handle(cx).contains_focused(window, cx);
17243
17244            let project = project.clone();
17245            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17246            self.blame_subscription =
17247                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17248            self.blame = Some(blame);
17249        }
17250    }
17251
17252    fn toggle_git_blame_inline_internal(
17253        &mut self,
17254        user_triggered: bool,
17255        window: &mut Window,
17256        cx: &mut Context<Self>,
17257    ) {
17258        if self.git_blame_inline_enabled {
17259            self.git_blame_inline_enabled = false;
17260            self.show_git_blame_inline = false;
17261            self.show_git_blame_inline_delay_task.take();
17262        } else {
17263            self.git_blame_inline_enabled = true;
17264            self.start_git_blame_inline(user_triggered, window, cx);
17265        }
17266
17267        cx.notify();
17268    }
17269
17270    fn start_git_blame_inline(
17271        &mut self,
17272        user_triggered: bool,
17273        window: &mut Window,
17274        cx: &mut Context<Self>,
17275    ) {
17276        self.start_git_blame(user_triggered, window, cx);
17277
17278        if ProjectSettings::get_global(cx)
17279            .git
17280            .inline_blame_delay()
17281            .is_some()
17282        {
17283            self.start_inline_blame_timer(window, cx);
17284        } else {
17285            self.show_git_blame_inline = true
17286        }
17287    }
17288
17289    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17290        self.blame.as_ref()
17291    }
17292
17293    pub fn show_git_blame_gutter(&self) -> bool {
17294        self.show_git_blame_gutter
17295    }
17296
17297    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17298        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17299    }
17300
17301    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17302        self.show_git_blame_inline
17303            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17304            && !self.newest_selection_head_on_empty_line(cx)
17305            && self.has_blame_entries(cx)
17306    }
17307
17308    fn has_blame_entries(&self, cx: &App) -> bool {
17309        self.blame()
17310            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17311    }
17312
17313    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17314        let cursor_anchor = self.selections.newest_anchor().head();
17315
17316        let snapshot = self.buffer.read(cx).snapshot(cx);
17317        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17318
17319        snapshot.line_len(buffer_row) == 0
17320    }
17321
17322    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17323        let buffer_and_selection = maybe!({
17324            let selection = self.selections.newest::<Point>(cx);
17325            let selection_range = selection.range();
17326
17327            let multi_buffer = self.buffer().read(cx);
17328            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17329            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17330
17331            let (buffer, range, _) = if selection.reversed {
17332                buffer_ranges.first()
17333            } else {
17334                buffer_ranges.last()
17335            }?;
17336
17337            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17338                ..text::ToPoint::to_point(&range.end, &buffer).row;
17339            Some((
17340                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17341                selection,
17342            ))
17343        });
17344
17345        let Some((buffer, selection)) = buffer_and_selection else {
17346            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17347        };
17348
17349        let Some(project) = self.project.as_ref() else {
17350            return Task::ready(Err(anyhow!("editor does not have project")));
17351        };
17352
17353        project.update(cx, |project, cx| {
17354            project.get_permalink_to_line(&buffer, selection, cx)
17355        })
17356    }
17357
17358    pub fn copy_permalink_to_line(
17359        &mut self,
17360        _: &CopyPermalinkToLine,
17361        window: &mut Window,
17362        cx: &mut Context<Self>,
17363    ) {
17364        let permalink_task = self.get_permalink_to_line(cx);
17365        let workspace = self.workspace();
17366
17367        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17368            Ok(permalink) => {
17369                cx.update(|_, cx| {
17370                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17371                })
17372                .ok();
17373            }
17374            Err(err) => {
17375                let message = format!("Failed to copy permalink: {err}");
17376
17377                anyhow::Result::<()>::Err(err).log_err();
17378
17379                if let Some(workspace) = workspace {
17380                    workspace
17381                        .update_in(cx, |workspace, _, cx| {
17382                            struct CopyPermalinkToLine;
17383
17384                            workspace.show_toast(
17385                                Toast::new(
17386                                    NotificationId::unique::<CopyPermalinkToLine>(),
17387                                    message,
17388                                ),
17389                                cx,
17390                            )
17391                        })
17392                        .ok();
17393                }
17394            }
17395        })
17396        .detach();
17397    }
17398
17399    pub fn copy_file_location(
17400        &mut self,
17401        _: &CopyFileLocation,
17402        _: &mut Window,
17403        cx: &mut Context<Self>,
17404    ) {
17405        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17406        if let Some(file) = self.target_file(cx) {
17407            if let Some(path) = file.path().to_str() {
17408                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17409            }
17410        }
17411    }
17412
17413    pub fn open_permalink_to_line(
17414        &mut self,
17415        _: &OpenPermalinkToLine,
17416        window: &mut Window,
17417        cx: &mut Context<Self>,
17418    ) {
17419        let permalink_task = self.get_permalink_to_line(cx);
17420        let workspace = self.workspace();
17421
17422        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17423            Ok(permalink) => {
17424                cx.update(|_, cx| {
17425                    cx.open_url(permalink.as_ref());
17426                })
17427                .ok();
17428            }
17429            Err(err) => {
17430                let message = format!("Failed to open permalink: {err}");
17431
17432                anyhow::Result::<()>::Err(err).log_err();
17433
17434                if let Some(workspace) = workspace {
17435                    workspace
17436                        .update(cx, |workspace, cx| {
17437                            struct OpenPermalinkToLine;
17438
17439                            workspace.show_toast(
17440                                Toast::new(
17441                                    NotificationId::unique::<OpenPermalinkToLine>(),
17442                                    message,
17443                                ),
17444                                cx,
17445                            )
17446                        })
17447                        .ok();
17448                }
17449            }
17450        })
17451        .detach();
17452    }
17453
17454    pub fn insert_uuid_v4(
17455        &mut self,
17456        _: &InsertUuidV4,
17457        window: &mut Window,
17458        cx: &mut Context<Self>,
17459    ) {
17460        self.insert_uuid(UuidVersion::V4, window, cx);
17461    }
17462
17463    pub fn insert_uuid_v7(
17464        &mut self,
17465        _: &InsertUuidV7,
17466        window: &mut Window,
17467        cx: &mut Context<Self>,
17468    ) {
17469        self.insert_uuid(UuidVersion::V7, window, cx);
17470    }
17471
17472    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17473        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17474        self.transact(window, cx, |this, window, cx| {
17475            let edits = this
17476                .selections
17477                .all::<Point>(cx)
17478                .into_iter()
17479                .map(|selection| {
17480                    let uuid = match version {
17481                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17482                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17483                    };
17484
17485                    (selection.range(), uuid.to_string())
17486                });
17487            this.edit(edits, cx);
17488            this.refresh_inline_completion(true, false, window, cx);
17489        });
17490    }
17491
17492    pub fn open_selections_in_multibuffer(
17493        &mut self,
17494        _: &OpenSelectionsInMultibuffer,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) {
17498        let multibuffer = self.buffer.read(cx);
17499
17500        let Some(buffer) = multibuffer.as_singleton() else {
17501            return;
17502        };
17503
17504        let Some(workspace) = self.workspace() else {
17505            return;
17506        };
17507
17508        let locations = self
17509            .selections
17510            .disjoint_anchors()
17511            .iter()
17512            .map(|range| Location {
17513                buffer: buffer.clone(),
17514                range: range.start.text_anchor..range.end.text_anchor,
17515            })
17516            .collect::<Vec<_>>();
17517
17518        let title = multibuffer.title(cx).to_string();
17519
17520        cx.spawn_in(window, async move |_, cx| {
17521            workspace.update_in(cx, |workspace, window, cx| {
17522                Self::open_locations_in_multibuffer(
17523                    workspace,
17524                    locations,
17525                    format!("Selections for '{title}'"),
17526                    false,
17527                    MultibufferSelectionMode::All,
17528                    window,
17529                    cx,
17530                );
17531            })
17532        })
17533        .detach();
17534    }
17535
17536    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17537    /// last highlight added will be used.
17538    ///
17539    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17540    pub fn highlight_rows<T: 'static>(
17541        &mut self,
17542        range: Range<Anchor>,
17543        color: Hsla,
17544        options: RowHighlightOptions,
17545        cx: &mut Context<Self>,
17546    ) {
17547        let snapshot = self.buffer().read(cx).snapshot(cx);
17548        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17549        let ix = row_highlights.binary_search_by(|highlight| {
17550            Ordering::Equal
17551                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17552                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17553        });
17554
17555        if let Err(mut ix) = ix {
17556            let index = post_inc(&mut self.highlight_order);
17557
17558            // If this range intersects with the preceding highlight, then merge it with
17559            // the preceding highlight. Otherwise insert a new highlight.
17560            let mut merged = false;
17561            if ix > 0 {
17562                let prev_highlight = &mut row_highlights[ix - 1];
17563                if prev_highlight
17564                    .range
17565                    .end
17566                    .cmp(&range.start, &snapshot)
17567                    .is_ge()
17568                {
17569                    ix -= 1;
17570                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17571                        prev_highlight.range.end = range.end;
17572                    }
17573                    merged = true;
17574                    prev_highlight.index = index;
17575                    prev_highlight.color = color;
17576                    prev_highlight.options = options;
17577                }
17578            }
17579
17580            if !merged {
17581                row_highlights.insert(
17582                    ix,
17583                    RowHighlight {
17584                        range: range.clone(),
17585                        index,
17586                        color,
17587                        options,
17588                        type_id: TypeId::of::<T>(),
17589                    },
17590                );
17591            }
17592
17593            // If any of the following highlights intersect with this one, merge them.
17594            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17595                let highlight = &row_highlights[ix];
17596                if next_highlight
17597                    .range
17598                    .start
17599                    .cmp(&highlight.range.end, &snapshot)
17600                    .is_le()
17601                {
17602                    if next_highlight
17603                        .range
17604                        .end
17605                        .cmp(&highlight.range.end, &snapshot)
17606                        .is_gt()
17607                    {
17608                        row_highlights[ix].range.end = next_highlight.range.end;
17609                    }
17610                    row_highlights.remove(ix + 1);
17611                } else {
17612                    break;
17613                }
17614            }
17615        }
17616    }
17617
17618    /// Remove any highlighted row ranges of the given type that intersect the
17619    /// given ranges.
17620    pub fn remove_highlighted_rows<T: 'static>(
17621        &mut self,
17622        ranges_to_remove: Vec<Range<Anchor>>,
17623        cx: &mut Context<Self>,
17624    ) {
17625        let snapshot = self.buffer().read(cx).snapshot(cx);
17626        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17627        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17628        row_highlights.retain(|highlight| {
17629            while let Some(range_to_remove) = ranges_to_remove.peek() {
17630                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17631                    Ordering::Less | Ordering::Equal => {
17632                        ranges_to_remove.next();
17633                    }
17634                    Ordering::Greater => {
17635                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17636                            Ordering::Less | Ordering::Equal => {
17637                                return false;
17638                            }
17639                            Ordering::Greater => break,
17640                        }
17641                    }
17642                }
17643            }
17644
17645            true
17646        })
17647    }
17648
17649    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17650    pub fn clear_row_highlights<T: 'static>(&mut self) {
17651        self.highlighted_rows.remove(&TypeId::of::<T>());
17652    }
17653
17654    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17655    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17656        self.highlighted_rows
17657            .get(&TypeId::of::<T>())
17658            .map_or(&[] as &[_], |vec| vec.as_slice())
17659            .iter()
17660            .map(|highlight| (highlight.range.clone(), highlight.color))
17661    }
17662
17663    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17664    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17665    /// Allows to ignore certain kinds of highlights.
17666    pub fn highlighted_display_rows(
17667        &self,
17668        window: &mut Window,
17669        cx: &mut App,
17670    ) -> BTreeMap<DisplayRow, LineHighlight> {
17671        let snapshot = self.snapshot(window, cx);
17672        let mut used_highlight_orders = HashMap::default();
17673        self.highlighted_rows
17674            .iter()
17675            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17676            .fold(
17677                BTreeMap::<DisplayRow, LineHighlight>::new(),
17678                |mut unique_rows, highlight| {
17679                    let start = highlight.range.start.to_display_point(&snapshot);
17680                    let end = highlight.range.end.to_display_point(&snapshot);
17681                    let start_row = start.row().0;
17682                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17683                        && end.column() == 0
17684                    {
17685                        end.row().0.saturating_sub(1)
17686                    } else {
17687                        end.row().0
17688                    };
17689                    for row in start_row..=end_row {
17690                        let used_index =
17691                            used_highlight_orders.entry(row).or_insert(highlight.index);
17692                        if highlight.index >= *used_index {
17693                            *used_index = highlight.index;
17694                            unique_rows.insert(
17695                                DisplayRow(row),
17696                                LineHighlight {
17697                                    include_gutter: highlight.options.include_gutter,
17698                                    border: None,
17699                                    background: highlight.color.into(),
17700                                    type_id: Some(highlight.type_id),
17701                                },
17702                            );
17703                        }
17704                    }
17705                    unique_rows
17706                },
17707            )
17708    }
17709
17710    pub fn highlighted_display_row_for_autoscroll(
17711        &self,
17712        snapshot: &DisplaySnapshot,
17713    ) -> Option<DisplayRow> {
17714        self.highlighted_rows
17715            .values()
17716            .flat_map(|highlighted_rows| highlighted_rows.iter())
17717            .filter_map(|highlight| {
17718                if highlight.options.autoscroll {
17719                    Some(highlight.range.start.to_display_point(snapshot).row())
17720                } else {
17721                    None
17722                }
17723            })
17724            .min()
17725    }
17726
17727    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17728        self.highlight_background::<SearchWithinRange>(
17729            ranges,
17730            |colors| colors.editor_document_highlight_read_background,
17731            cx,
17732        )
17733    }
17734
17735    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17736        self.breadcrumb_header = Some(new_header);
17737    }
17738
17739    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17740        self.clear_background_highlights::<SearchWithinRange>(cx);
17741    }
17742
17743    pub fn highlight_background<T: 'static>(
17744        &mut self,
17745        ranges: &[Range<Anchor>],
17746        color_fetcher: fn(&ThemeColors) -> Hsla,
17747        cx: &mut Context<Self>,
17748    ) {
17749        self.background_highlights
17750            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17751        self.scrollbar_marker_state.dirty = true;
17752        cx.notify();
17753    }
17754
17755    pub fn clear_background_highlights<T: 'static>(
17756        &mut self,
17757        cx: &mut Context<Self>,
17758    ) -> Option<BackgroundHighlight> {
17759        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17760        if !text_highlights.1.is_empty() {
17761            self.scrollbar_marker_state.dirty = true;
17762            cx.notify();
17763        }
17764        Some(text_highlights)
17765    }
17766
17767    pub fn highlight_gutter<T: 'static>(
17768        &mut self,
17769        ranges: &[Range<Anchor>],
17770        color_fetcher: fn(&App) -> Hsla,
17771        cx: &mut Context<Self>,
17772    ) {
17773        self.gutter_highlights
17774            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17775        cx.notify();
17776    }
17777
17778    pub fn clear_gutter_highlights<T: 'static>(
17779        &mut self,
17780        cx: &mut Context<Self>,
17781    ) -> Option<GutterHighlight> {
17782        cx.notify();
17783        self.gutter_highlights.remove(&TypeId::of::<T>())
17784    }
17785
17786    #[cfg(feature = "test-support")]
17787    pub fn all_text_background_highlights(
17788        &self,
17789        window: &mut Window,
17790        cx: &mut Context<Self>,
17791    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17792        let snapshot = self.snapshot(window, cx);
17793        let buffer = &snapshot.buffer_snapshot;
17794        let start = buffer.anchor_before(0);
17795        let end = buffer.anchor_after(buffer.len());
17796        let theme = cx.theme().colors();
17797        self.background_highlights_in_range(start..end, &snapshot, theme)
17798    }
17799
17800    #[cfg(feature = "test-support")]
17801    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17802        let snapshot = self.buffer().read(cx).snapshot(cx);
17803
17804        let highlights = self
17805            .background_highlights
17806            .get(&TypeId::of::<items::BufferSearchHighlights>());
17807
17808        if let Some((_color, ranges)) = highlights {
17809            ranges
17810                .iter()
17811                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17812                .collect_vec()
17813        } else {
17814            vec![]
17815        }
17816    }
17817
17818    fn document_highlights_for_position<'a>(
17819        &'a self,
17820        position: Anchor,
17821        buffer: &'a MultiBufferSnapshot,
17822    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17823        let read_highlights = self
17824            .background_highlights
17825            .get(&TypeId::of::<DocumentHighlightRead>())
17826            .map(|h| &h.1);
17827        let write_highlights = self
17828            .background_highlights
17829            .get(&TypeId::of::<DocumentHighlightWrite>())
17830            .map(|h| &h.1);
17831        let left_position = position.bias_left(buffer);
17832        let right_position = position.bias_right(buffer);
17833        read_highlights
17834            .into_iter()
17835            .chain(write_highlights)
17836            .flat_map(move |ranges| {
17837                let start_ix = match ranges.binary_search_by(|probe| {
17838                    let cmp = probe.end.cmp(&left_position, buffer);
17839                    if cmp.is_ge() {
17840                        Ordering::Greater
17841                    } else {
17842                        Ordering::Less
17843                    }
17844                }) {
17845                    Ok(i) | Err(i) => i,
17846                };
17847
17848                ranges[start_ix..]
17849                    .iter()
17850                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17851            })
17852    }
17853
17854    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17855        self.background_highlights
17856            .get(&TypeId::of::<T>())
17857            .map_or(false, |(_, highlights)| !highlights.is_empty())
17858    }
17859
17860    pub fn background_highlights_in_range(
17861        &self,
17862        search_range: Range<Anchor>,
17863        display_snapshot: &DisplaySnapshot,
17864        theme: &ThemeColors,
17865    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17866        let mut results = Vec::new();
17867        for (color_fetcher, ranges) in self.background_highlights.values() {
17868            let color = color_fetcher(theme);
17869            let start_ix = match ranges.binary_search_by(|probe| {
17870                let cmp = probe
17871                    .end
17872                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17873                if cmp.is_gt() {
17874                    Ordering::Greater
17875                } else {
17876                    Ordering::Less
17877                }
17878            }) {
17879                Ok(i) | Err(i) => i,
17880            };
17881            for range in &ranges[start_ix..] {
17882                if range
17883                    .start
17884                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17885                    .is_ge()
17886                {
17887                    break;
17888                }
17889
17890                let start = range.start.to_display_point(display_snapshot);
17891                let end = range.end.to_display_point(display_snapshot);
17892                results.push((start..end, color))
17893            }
17894        }
17895        results
17896    }
17897
17898    pub fn background_highlight_row_ranges<T: 'static>(
17899        &self,
17900        search_range: Range<Anchor>,
17901        display_snapshot: &DisplaySnapshot,
17902        count: usize,
17903    ) -> Vec<RangeInclusive<DisplayPoint>> {
17904        let mut results = Vec::new();
17905        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17906            return vec![];
17907        };
17908
17909        let start_ix = match ranges.binary_search_by(|probe| {
17910            let cmp = probe
17911                .end
17912                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17913            if cmp.is_gt() {
17914                Ordering::Greater
17915            } else {
17916                Ordering::Less
17917            }
17918        }) {
17919            Ok(i) | Err(i) => i,
17920        };
17921        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17922            if let (Some(start_display), Some(end_display)) = (start, end) {
17923                results.push(
17924                    start_display.to_display_point(display_snapshot)
17925                        ..=end_display.to_display_point(display_snapshot),
17926                );
17927            }
17928        };
17929        let mut start_row: Option<Point> = None;
17930        let mut end_row: Option<Point> = None;
17931        if ranges.len() > count {
17932            return Vec::new();
17933        }
17934        for range in &ranges[start_ix..] {
17935            if range
17936                .start
17937                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17938                .is_ge()
17939            {
17940                break;
17941            }
17942            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17943            if let Some(current_row) = &end_row {
17944                if end.row == current_row.row {
17945                    continue;
17946                }
17947            }
17948            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17949            if start_row.is_none() {
17950                assert_eq!(end_row, None);
17951                start_row = Some(start);
17952                end_row = Some(end);
17953                continue;
17954            }
17955            if let Some(current_end) = end_row.as_mut() {
17956                if start.row > current_end.row + 1 {
17957                    push_region(start_row, end_row);
17958                    start_row = Some(start);
17959                    end_row = Some(end);
17960                } else {
17961                    // Merge two hunks.
17962                    *current_end = end;
17963                }
17964            } else {
17965                unreachable!();
17966            }
17967        }
17968        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17969        push_region(start_row, end_row);
17970        results
17971    }
17972
17973    pub fn gutter_highlights_in_range(
17974        &self,
17975        search_range: Range<Anchor>,
17976        display_snapshot: &DisplaySnapshot,
17977        cx: &App,
17978    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17979        let mut results = Vec::new();
17980        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17981            let color = color_fetcher(cx);
17982            let start_ix = match ranges.binary_search_by(|probe| {
17983                let cmp = probe
17984                    .end
17985                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17986                if cmp.is_gt() {
17987                    Ordering::Greater
17988                } else {
17989                    Ordering::Less
17990                }
17991            }) {
17992                Ok(i) | Err(i) => i,
17993            };
17994            for range in &ranges[start_ix..] {
17995                if range
17996                    .start
17997                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17998                    .is_ge()
17999                {
18000                    break;
18001                }
18002
18003                let start = range.start.to_display_point(display_snapshot);
18004                let end = range.end.to_display_point(display_snapshot);
18005                results.push((start..end, color))
18006            }
18007        }
18008        results
18009    }
18010
18011    /// Get the text ranges corresponding to the redaction query
18012    pub fn redacted_ranges(
18013        &self,
18014        search_range: Range<Anchor>,
18015        display_snapshot: &DisplaySnapshot,
18016        cx: &App,
18017    ) -> Vec<Range<DisplayPoint>> {
18018        display_snapshot
18019            .buffer_snapshot
18020            .redacted_ranges(search_range, |file| {
18021                if let Some(file) = file {
18022                    file.is_private()
18023                        && EditorSettings::get(
18024                            Some(SettingsLocation {
18025                                worktree_id: file.worktree_id(cx),
18026                                path: file.path().as_ref(),
18027                            }),
18028                            cx,
18029                        )
18030                        .redact_private_values
18031                } else {
18032                    false
18033                }
18034            })
18035            .map(|range| {
18036                range.start.to_display_point(display_snapshot)
18037                    ..range.end.to_display_point(display_snapshot)
18038            })
18039            .collect()
18040    }
18041
18042    pub fn highlight_text<T: 'static>(
18043        &mut self,
18044        ranges: Vec<Range<Anchor>>,
18045        style: HighlightStyle,
18046        cx: &mut Context<Self>,
18047    ) {
18048        self.display_map.update(cx, |map, _| {
18049            map.highlight_text(TypeId::of::<T>(), ranges, style)
18050        });
18051        cx.notify();
18052    }
18053
18054    pub(crate) fn highlight_inlays<T: 'static>(
18055        &mut self,
18056        highlights: Vec<InlayHighlight>,
18057        style: HighlightStyle,
18058        cx: &mut Context<Self>,
18059    ) {
18060        self.display_map.update(cx, |map, _| {
18061            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18062        });
18063        cx.notify();
18064    }
18065
18066    pub fn text_highlights<'a, T: 'static>(
18067        &'a self,
18068        cx: &'a App,
18069    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18070        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18071    }
18072
18073    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18074        let cleared = self
18075            .display_map
18076            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18077        if cleared {
18078            cx.notify();
18079        }
18080    }
18081
18082    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18083        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18084            && self.focus_handle.is_focused(window)
18085    }
18086
18087    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18088        self.show_cursor_when_unfocused = is_enabled;
18089        cx.notify();
18090    }
18091
18092    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18093        cx.notify();
18094    }
18095
18096    fn on_debug_session_event(
18097        &mut self,
18098        _session: Entity<Session>,
18099        event: &SessionEvent,
18100        cx: &mut Context<Self>,
18101    ) {
18102        match event {
18103            SessionEvent::InvalidateInlineValue => {
18104                self.refresh_inline_values(cx);
18105            }
18106            _ => {}
18107        }
18108    }
18109
18110    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18111        let Some(project) = self.project.clone() else {
18112            return;
18113        };
18114
18115        if !self.inline_value_cache.enabled {
18116            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18117            self.splice_inlays(&inlays, Vec::new(), cx);
18118            return;
18119        }
18120
18121        let current_execution_position = self
18122            .highlighted_rows
18123            .get(&TypeId::of::<ActiveDebugLine>())
18124            .and_then(|lines| lines.last().map(|line| line.range.start));
18125
18126        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18127            let inline_values = editor
18128                .update(cx, |editor, cx| {
18129                    let Some(current_execution_position) = current_execution_position else {
18130                        return Some(Task::ready(Ok(Vec::new())));
18131                    };
18132
18133                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18134                        let snapshot = buffer.snapshot(cx);
18135
18136                        let excerpt = snapshot.excerpt_containing(
18137                            current_execution_position..current_execution_position,
18138                        )?;
18139
18140                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18141                    })?;
18142
18143                    let range =
18144                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18145
18146                    project.inline_values(buffer, range, cx)
18147                })
18148                .ok()
18149                .flatten()?
18150                .await
18151                .context("refreshing debugger inlays")
18152                .log_err()?;
18153
18154            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18155
18156            for (buffer_id, inline_value) in inline_values
18157                .into_iter()
18158                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18159            {
18160                buffer_inline_values
18161                    .entry(buffer_id)
18162                    .or_default()
18163                    .push(inline_value);
18164            }
18165
18166            editor
18167                .update(cx, |editor, cx| {
18168                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18169                    let mut new_inlays = Vec::default();
18170
18171                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18172                        let buffer_id = buffer_snapshot.remote_id();
18173                        buffer_inline_values
18174                            .get(&buffer_id)
18175                            .into_iter()
18176                            .flatten()
18177                            .for_each(|hint| {
18178                                let inlay = Inlay::debugger_hint(
18179                                    post_inc(&mut editor.next_inlay_id),
18180                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18181                                    hint.text(),
18182                                );
18183
18184                                new_inlays.push(inlay);
18185                            });
18186                    }
18187
18188                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18189                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18190
18191                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18192                })
18193                .ok()?;
18194            Some(())
18195        });
18196    }
18197
18198    fn on_buffer_event(
18199        &mut self,
18200        multibuffer: &Entity<MultiBuffer>,
18201        event: &multi_buffer::Event,
18202        window: &mut Window,
18203        cx: &mut Context<Self>,
18204    ) {
18205        match event {
18206            multi_buffer::Event::Edited {
18207                singleton_buffer_edited,
18208                edited_buffer: buffer_edited,
18209            } => {
18210                self.scrollbar_marker_state.dirty = true;
18211                self.active_indent_guides_state.dirty = true;
18212                self.refresh_active_diagnostics(cx);
18213                self.refresh_code_actions(window, cx);
18214                self.refresh_selected_text_highlights(true, window, cx);
18215                refresh_matching_bracket_highlights(self, window, cx);
18216                if self.has_active_inline_completion() {
18217                    self.update_visible_inline_completion(window, cx);
18218                }
18219                if let Some(buffer) = buffer_edited {
18220                    let buffer_id = buffer.read(cx).remote_id();
18221                    if !self.registered_buffers.contains_key(&buffer_id) {
18222                        if let Some(project) = self.project.as_ref() {
18223                            project.update(cx, |project, cx| {
18224                                self.registered_buffers.insert(
18225                                    buffer_id,
18226                                    project.register_buffer_with_language_servers(&buffer, cx),
18227                                );
18228                            })
18229                        }
18230                    }
18231                }
18232                cx.emit(EditorEvent::BufferEdited);
18233                cx.emit(SearchEvent::MatchesInvalidated);
18234                if *singleton_buffer_edited {
18235                    if let Some(project) = &self.project {
18236                        #[allow(clippy::mutable_key_type)]
18237                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18238                            multibuffer
18239                                .all_buffers()
18240                                .into_iter()
18241                                .filter_map(|buffer| {
18242                                    buffer.update(cx, |buffer, cx| {
18243                                        let language = buffer.language()?;
18244                                        let should_discard = project.update(cx, |project, cx| {
18245                                            project.is_local()
18246                                                && !project.has_language_servers_for(buffer, cx)
18247                                        });
18248                                        should_discard.not().then_some(language.clone())
18249                                    })
18250                                })
18251                                .collect::<HashSet<_>>()
18252                        });
18253                        if !languages_affected.is_empty() {
18254                            self.refresh_inlay_hints(
18255                                InlayHintRefreshReason::BufferEdited(languages_affected),
18256                                cx,
18257                            );
18258                        }
18259                    }
18260                }
18261
18262                let Some(project) = &self.project else { return };
18263                let (telemetry, is_via_ssh) = {
18264                    let project = project.read(cx);
18265                    let telemetry = project.client().telemetry().clone();
18266                    let is_via_ssh = project.is_via_ssh();
18267                    (telemetry, is_via_ssh)
18268                };
18269                refresh_linked_ranges(self, window, cx);
18270                telemetry.log_edit_event("editor", is_via_ssh);
18271            }
18272            multi_buffer::Event::ExcerptsAdded {
18273                buffer,
18274                predecessor,
18275                excerpts,
18276            } => {
18277                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18278                let buffer_id = buffer.read(cx).remote_id();
18279                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18280                    if let Some(project) = &self.project {
18281                        update_uncommitted_diff_for_buffer(
18282                            cx.entity(),
18283                            project,
18284                            [buffer.clone()],
18285                            self.buffer.clone(),
18286                            cx,
18287                        )
18288                        .detach();
18289                    }
18290                }
18291                cx.emit(EditorEvent::ExcerptsAdded {
18292                    buffer: buffer.clone(),
18293                    predecessor: *predecessor,
18294                    excerpts: excerpts.clone(),
18295                });
18296                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18297            }
18298            multi_buffer::Event::ExcerptsRemoved {
18299                ids,
18300                removed_buffer_ids,
18301            } => {
18302                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18303                let buffer = self.buffer.read(cx);
18304                self.registered_buffers
18305                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18306                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18307                cx.emit(EditorEvent::ExcerptsRemoved {
18308                    ids: ids.clone(),
18309                    removed_buffer_ids: removed_buffer_ids.clone(),
18310                })
18311            }
18312            multi_buffer::Event::ExcerptsEdited {
18313                excerpt_ids,
18314                buffer_ids,
18315            } => {
18316                self.display_map.update(cx, |map, cx| {
18317                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18318                });
18319                cx.emit(EditorEvent::ExcerptsEdited {
18320                    ids: excerpt_ids.clone(),
18321                })
18322            }
18323            multi_buffer::Event::ExcerptsExpanded { ids } => {
18324                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18325                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18326            }
18327            multi_buffer::Event::Reparsed(buffer_id) => {
18328                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18329                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18330
18331                cx.emit(EditorEvent::Reparsed(*buffer_id));
18332            }
18333            multi_buffer::Event::DiffHunksToggled => {
18334                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18335            }
18336            multi_buffer::Event::LanguageChanged(buffer_id) => {
18337                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18338                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18339                cx.emit(EditorEvent::Reparsed(*buffer_id));
18340                cx.notify();
18341            }
18342            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18343            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18344            multi_buffer::Event::FileHandleChanged
18345            | multi_buffer::Event::Reloaded
18346            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18347            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18348            multi_buffer::Event::DiagnosticsUpdated => {
18349                self.refresh_active_diagnostics(cx);
18350                self.refresh_inline_diagnostics(true, window, cx);
18351                self.scrollbar_marker_state.dirty = true;
18352                cx.notify();
18353            }
18354            _ => {}
18355        };
18356    }
18357
18358    pub fn start_temporary_diff_override(&mut self) {
18359        self.load_diff_task.take();
18360        self.temporary_diff_override = true;
18361    }
18362
18363    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18364        self.temporary_diff_override = false;
18365        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18366        self.buffer.update(cx, |buffer, cx| {
18367            buffer.set_all_diff_hunks_collapsed(cx);
18368        });
18369
18370        if let Some(project) = self.project.clone() {
18371            self.load_diff_task = Some(
18372                update_uncommitted_diff_for_buffer(
18373                    cx.entity(),
18374                    &project,
18375                    self.buffer.read(cx).all_buffers(),
18376                    self.buffer.clone(),
18377                    cx,
18378                )
18379                .shared(),
18380            );
18381        }
18382    }
18383
18384    fn on_display_map_changed(
18385        &mut self,
18386        _: Entity<DisplayMap>,
18387        _: &mut Window,
18388        cx: &mut Context<Self>,
18389    ) {
18390        cx.notify();
18391    }
18392
18393    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18394        let new_severity = if self.diagnostics_enabled() {
18395            EditorSettings::get_global(cx)
18396                .diagnostics_max_severity
18397                .unwrap_or(DiagnosticSeverity::Hint)
18398        } else {
18399            DiagnosticSeverity::Off
18400        };
18401        self.set_max_diagnostics_severity(new_severity, cx);
18402        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18403        self.update_edit_prediction_settings(cx);
18404        self.refresh_inline_completion(true, false, window, cx);
18405        self.refresh_inlay_hints(
18406            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18407                self.selections.newest_anchor().head(),
18408                &self.buffer.read(cx).snapshot(cx),
18409                cx,
18410            )),
18411            cx,
18412        );
18413
18414        let old_cursor_shape = self.cursor_shape;
18415
18416        {
18417            let editor_settings = EditorSettings::get_global(cx);
18418            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18419            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18420            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18421            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18422        }
18423
18424        if old_cursor_shape != self.cursor_shape {
18425            cx.emit(EditorEvent::CursorShapeChanged);
18426        }
18427
18428        let project_settings = ProjectSettings::get_global(cx);
18429        self.serialize_dirty_buffers =
18430            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18431
18432        if self.mode.is_full() {
18433            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18434            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18435            if self.show_inline_diagnostics != show_inline_diagnostics {
18436                self.show_inline_diagnostics = show_inline_diagnostics;
18437                self.refresh_inline_diagnostics(false, window, cx);
18438            }
18439
18440            if self.git_blame_inline_enabled != inline_blame_enabled {
18441                self.toggle_git_blame_inline_internal(false, window, cx);
18442            }
18443
18444            let minimap_settings = EditorSettings::get_global(cx).minimap;
18445            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18446                self.set_minimap_visibility(
18447                    self.minimap_visibility.toggle_visibility(),
18448                    window,
18449                    cx,
18450                );
18451            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18452                minimap_entity.update(cx, |minimap_editor, cx| {
18453                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18454                })
18455            }
18456        }
18457
18458        cx.notify();
18459    }
18460
18461    pub fn set_searchable(&mut self, searchable: bool) {
18462        self.searchable = searchable;
18463    }
18464
18465    pub fn searchable(&self) -> bool {
18466        self.searchable
18467    }
18468
18469    fn open_proposed_changes_editor(
18470        &mut self,
18471        _: &OpenProposedChangesEditor,
18472        window: &mut Window,
18473        cx: &mut Context<Self>,
18474    ) {
18475        let Some(workspace) = self.workspace() else {
18476            cx.propagate();
18477            return;
18478        };
18479
18480        let selections = self.selections.all::<usize>(cx);
18481        let multi_buffer = self.buffer.read(cx);
18482        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18483        let mut new_selections_by_buffer = HashMap::default();
18484        for selection in selections {
18485            for (buffer, range, _) in
18486                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18487            {
18488                let mut range = range.to_point(buffer);
18489                range.start.column = 0;
18490                range.end.column = buffer.line_len(range.end.row);
18491                new_selections_by_buffer
18492                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18493                    .or_insert(Vec::new())
18494                    .push(range)
18495            }
18496        }
18497
18498        let proposed_changes_buffers = new_selections_by_buffer
18499            .into_iter()
18500            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18501            .collect::<Vec<_>>();
18502        let proposed_changes_editor = cx.new(|cx| {
18503            ProposedChangesEditor::new(
18504                "Proposed changes",
18505                proposed_changes_buffers,
18506                self.project.clone(),
18507                window,
18508                cx,
18509            )
18510        });
18511
18512        window.defer(cx, move |window, cx| {
18513            workspace.update(cx, |workspace, cx| {
18514                workspace.active_pane().update(cx, |pane, cx| {
18515                    pane.add_item(
18516                        Box::new(proposed_changes_editor),
18517                        true,
18518                        true,
18519                        None,
18520                        window,
18521                        cx,
18522                    );
18523                });
18524            });
18525        });
18526    }
18527
18528    pub fn open_excerpts_in_split(
18529        &mut self,
18530        _: &OpenExcerptsSplit,
18531        window: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) {
18534        self.open_excerpts_common(None, true, window, cx)
18535    }
18536
18537    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18538        self.open_excerpts_common(None, false, window, cx)
18539    }
18540
18541    fn open_excerpts_common(
18542        &mut self,
18543        jump_data: Option<JumpData>,
18544        split: bool,
18545        window: &mut Window,
18546        cx: &mut Context<Self>,
18547    ) {
18548        let Some(workspace) = self.workspace() else {
18549            cx.propagate();
18550            return;
18551        };
18552
18553        if self.buffer.read(cx).is_singleton() {
18554            cx.propagate();
18555            return;
18556        }
18557
18558        let mut new_selections_by_buffer = HashMap::default();
18559        match &jump_data {
18560            Some(JumpData::MultiBufferPoint {
18561                excerpt_id,
18562                position,
18563                anchor,
18564                line_offset_from_top,
18565            }) => {
18566                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18567                if let Some(buffer) = multi_buffer_snapshot
18568                    .buffer_id_for_excerpt(*excerpt_id)
18569                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18570                {
18571                    let buffer_snapshot = buffer.read(cx).snapshot();
18572                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18573                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18574                    } else {
18575                        buffer_snapshot.clip_point(*position, Bias::Left)
18576                    };
18577                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18578                    new_selections_by_buffer.insert(
18579                        buffer,
18580                        (
18581                            vec![jump_to_offset..jump_to_offset],
18582                            Some(*line_offset_from_top),
18583                        ),
18584                    );
18585                }
18586            }
18587            Some(JumpData::MultiBufferRow {
18588                row,
18589                line_offset_from_top,
18590            }) => {
18591                let point = MultiBufferPoint::new(row.0, 0);
18592                if let Some((buffer, buffer_point, _)) =
18593                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18594                {
18595                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18596                    new_selections_by_buffer
18597                        .entry(buffer)
18598                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18599                        .0
18600                        .push(buffer_offset..buffer_offset)
18601                }
18602            }
18603            None => {
18604                let selections = self.selections.all::<usize>(cx);
18605                let multi_buffer = self.buffer.read(cx);
18606                for selection in selections {
18607                    for (snapshot, range, _, anchor) in multi_buffer
18608                        .snapshot(cx)
18609                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18610                    {
18611                        if let Some(anchor) = anchor {
18612                            // selection is in a deleted hunk
18613                            let Some(buffer_id) = anchor.buffer_id else {
18614                                continue;
18615                            };
18616                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18617                                continue;
18618                            };
18619                            let offset = text::ToOffset::to_offset(
18620                                &anchor.text_anchor,
18621                                &buffer_handle.read(cx).snapshot(),
18622                            );
18623                            let range = offset..offset;
18624                            new_selections_by_buffer
18625                                .entry(buffer_handle)
18626                                .or_insert((Vec::new(), None))
18627                                .0
18628                                .push(range)
18629                        } else {
18630                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18631                            else {
18632                                continue;
18633                            };
18634                            new_selections_by_buffer
18635                                .entry(buffer_handle)
18636                                .or_insert((Vec::new(), None))
18637                                .0
18638                                .push(range)
18639                        }
18640                    }
18641                }
18642            }
18643        }
18644
18645        new_selections_by_buffer
18646            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18647
18648        if new_selections_by_buffer.is_empty() {
18649            return;
18650        }
18651
18652        // We defer the pane interaction because we ourselves are a workspace item
18653        // and activating a new item causes the pane to call a method on us reentrantly,
18654        // which panics if we're on the stack.
18655        window.defer(cx, move |window, cx| {
18656            workspace.update(cx, |workspace, cx| {
18657                let pane = if split {
18658                    workspace.adjacent_pane(window, cx)
18659                } else {
18660                    workspace.active_pane().clone()
18661                };
18662
18663                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18664                    let editor = buffer
18665                        .read(cx)
18666                        .file()
18667                        .is_none()
18668                        .then(|| {
18669                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18670                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18671                            // Instead, we try to activate the existing editor in the pane first.
18672                            let (editor, pane_item_index) =
18673                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18674                                    let editor = item.downcast::<Editor>()?;
18675                                    let singleton_buffer =
18676                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18677                                    if singleton_buffer == buffer {
18678                                        Some((editor, i))
18679                                    } else {
18680                                        None
18681                                    }
18682                                })?;
18683                            pane.update(cx, |pane, cx| {
18684                                pane.activate_item(pane_item_index, true, true, window, cx)
18685                            });
18686                            Some(editor)
18687                        })
18688                        .flatten()
18689                        .unwrap_or_else(|| {
18690                            workspace.open_project_item::<Self>(
18691                                pane.clone(),
18692                                buffer,
18693                                true,
18694                                true,
18695                                window,
18696                                cx,
18697                            )
18698                        });
18699
18700                    editor.update(cx, |editor, cx| {
18701                        let autoscroll = match scroll_offset {
18702                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18703                            None => Autoscroll::newest(),
18704                        };
18705                        let nav_history = editor.nav_history.take();
18706                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18707                            s.select_ranges(ranges);
18708                        });
18709                        editor.nav_history = nav_history;
18710                    });
18711                }
18712            })
18713        });
18714    }
18715
18716    // For now, don't allow opening excerpts in buffers that aren't backed by
18717    // regular project files.
18718    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18719        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18720    }
18721
18722    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18723        let snapshot = self.buffer.read(cx).read(cx);
18724        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18725        Some(
18726            ranges
18727                .iter()
18728                .map(move |range| {
18729                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18730                })
18731                .collect(),
18732        )
18733    }
18734
18735    fn selection_replacement_ranges(
18736        &self,
18737        range: Range<OffsetUtf16>,
18738        cx: &mut App,
18739    ) -> Vec<Range<OffsetUtf16>> {
18740        let selections = self.selections.all::<OffsetUtf16>(cx);
18741        let newest_selection = selections
18742            .iter()
18743            .max_by_key(|selection| selection.id)
18744            .unwrap();
18745        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18746        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18747        let snapshot = self.buffer.read(cx).read(cx);
18748        selections
18749            .into_iter()
18750            .map(|mut selection| {
18751                selection.start.0 =
18752                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18753                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18754                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18755                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18756            })
18757            .collect()
18758    }
18759
18760    fn report_editor_event(
18761        &self,
18762        event_type: &'static str,
18763        file_extension: Option<String>,
18764        cx: &App,
18765    ) {
18766        if cfg!(any(test, feature = "test-support")) {
18767            return;
18768        }
18769
18770        let Some(project) = &self.project else { return };
18771
18772        // If None, we are in a file without an extension
18773        let file = self
18774            .buffer
18775            .read(cx)
18776            .as_singleton()
18777            .and_then(|b| b.read(cx).file());
18778        let file_extension = file_extension.or(file
18779            .as_ref()
18780            .and_then(|file| Path::new(file.file_name(cx)).extension())
18781            .and_then(|e| e.to_str())
18782            .map(|a| a.to_string()));
18783
18784        let vim_mode = vim_enabled(cx);
18785
18786        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18787        let copilot_enabled = edit_predictions_provider
18788            == language::language_settings::EditPredictionProvider::Copilot;
18789        let copilot_enabled_for_language = self
18790            .buffer
18791            .read(cx)
18792            .language_settings(cx)
18793            .show_edit_predictions;
18794
18795        let project = project.read(cx);
18796        telemetry::event!(
18797            event_type,
18798            file_extension,
18799            vim_mode,
18800            copilot_enabled,
18801            copilot_enabled_for_language,
18802            edit_predictions_provider,
18803            is_via_ssh = project.is_via_ssh(),
18804        );
18805    }
18806
18807    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18808    /// with each line being an array of {text, highlight} objects.
18809    fn copy_highlight_json(
18810        &mut self,
18811        _: &CopyHighlightJson,
18812        window: &mut Window,
18813        cx: &mut Context<Self>,
18814    ) {
18815        #[derive(Serialize)]
18816        struct Chunk<'a> {
18817            text: String,
18818            highlight: Option<&'a str>,
18819        }
18820
18821        let snapshot = self.buffer.read(cx).snapshot(cx);
18822        let range = self
18823            .selected_text_range(false, window, cx)
18824            .and_then(|selection| {
18825                if selection.range.is_empty() {
18826                    None
18827                } else {
18828                    Some(selection.range)
18829                }
18830            })
18831            .unwrap_or_else(|| 0..snapshot.len());
18832
18833        let chunks = snapshot.chunks(range, true);
18834        let mut lines = Vec::new();
18835        let mut line: VecDeque<Chunk> = VecDeque::new();
18836
18837        let Some(style) = self.style.as_ref() else {
18838            return;
18839        };
18840
18841        for chunk in chunks {
18842            let highlight = chunk
18843                .syntax_highlight_id
18844                .and_then(|id| id.name(&style.syntax));
18845            let mut chunk_lines = chunk.text.split('\n').peekable();
18846            while let Some(text) = chunk_lines.next() {
18847                let mut merged_with_last_token = false;
18848                if let Some(last_token) = line.back_mut() {
18849                    if last_token.highlight == highlight {
18850                        last_token.text.push_str(text);
18851                        merged_with_last_token = true;
18852                    }
18853                }
18854
18855                if !merged_with_last_token {
18856                    line.push_back(Chunk {
18857                        text: text.into(),
18858                        highlight,
18859                    });
18860                }
18861
18862                if chunk_lines.peek().is_some() {
18863                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18864                        line.pop_front();
18865                    }
18866                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18867                        line.pop_back();
18868                    }
18869
18870                    lines.push(mem::take(&mut line));
18871                }
18872            }
18873        }
18874
18875        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18876            return;
18877        };
18878        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18879    }
18880
18881    pub fn open_context_menu(
18882        &mut self,
18883        _: &OpenContextMenu,
18884        window: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) {
18887        self.request_autoscroll(Autoscroll::newest(), cx);
18888        let position = self.selections.newest_display(cx).start;
18889        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18890    }
18891
18892    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18893        &self.inlay_hint_cache
18894    }
18895
18896    pub fn replay_insert_event(
18897        &mut self,
18898        text: &str,
18899        relative_utf16_range: Option<Range<isize>>,
18900        window: &mut Window,
18901        cx: &mut Context<Self>,
18902    ) {
18903        if !self.input_enabled {
18904            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18905            return;
18906        }
18907        if let Some(relative_utf16_range) = relative_utf16_range {
18908            let selections = self.selections.all::<OffsetUtf16>(cx);
18909            self.change_selections(None, window, cx, |s| {
18910                let new_ranges = selections.into_iter().map(|range| {
18911                    let start = OffsetUtf16(
18912                        range
18913                            .head()
18914                            .0
18915                            .saturating_add_signed(relative_utf16_range.start),
18916                    );
18917                    let end = OffsetUtf16(
18918                        range
18919                            .head()
18920                            .0
18921                            .saturating_add_signed(relative_utf16_range.end),
18922                    );
18923                    start..end
18924                });
18925                s.select_ranges(new_ranges);
18926            });
18927        }
18928
18929        self.handle_input(text, window, cx);
18930    }
18931
18932    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18933        let Some(provider) = self.semantics_provider.as_ref() else {
18934            return false;
18935        };
18936
18937        let mut supports = false;
18938        self.buffer().update(cx, |this, cx| {
18939            this.for_each_buffer(|buffer| {
18940                supports |= provider.supports_inlay_hints(buffer, cx);
18941            });
18942        });
18943
18944        supports
18945    }
18946
18947    pub fn is_focused(&self, window: &Window) -> bool {
18948        self.focus_handle.is_focused(window)
18949    }
18950
18951    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18952        cx.emit(EditorEvent::Focused);
18953
18954        if let Some(descendant) = self
18955            .last_focused_descendant
18956            .take()
18957            .and_then(|descendant| descendant.upgrade())
18958        {
18959            window.focus(&descendant);
18960        } else {
18961            if let Some(blame) = self.blame.as_ref() {
18962                blame.update(cx, GitBlame::focus)
18963            }
18964
18965            self.blink_manager.update(cx, BlinkManager::enable);
18966            self.show_cursor_names(window, cx);
18967            self.buffer.update(cx, |buffer, cx| {
18968                buffer.finalize_last_transaction(cx);
18969                if self.leader_id.is_none() {
18970                    buffer.set_active_selections(
18971                        &self.selections.disjoint_anchors(),
18972                        self.selections.line_mode,
18973                        self.cursor_shape,
18974                        cx,
18975                    );
18976                }
18977            });
18978        }
18979    }
18980
18981    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18982        cx.emit(EditorEvent::FocusedIn)
18983    }
18984
18985    fn handle_focus_out(
18986        &mut self,
18987        event: FocusOutEvent,
18988        _window: &mut Window,
18989        cx: &mut Context<Self>,
18990    ) {
18991        if event.blurred != self.focus_handle {
18992            self.last_focused_descendant = Some(event.blurred);
18993        }
18994        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18995    }
18996
18997    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18998        self.blink_manager.update(cx, BlinkManager::disable);
18999        self.buffer
19000            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19001
19002        if let Some(blame) = self.blame.as_ref() {
19003            blame.update(cx, GitBlame::blur)
19004        }
19005        if !self.hover_state.focused(window, cx) {
19006            hide_hover(self, cx);
19007        }
19008        if !self
19009            .context_menu
19010            .borrow()
19011            .as_ref()
19012            .is_some_and(|context_menu| context_menu.focused(window, cx))
19013        {
19014            self.hide_context_menu(window, cx);
19015        }
19016        self.discard_inline_completion(false, cx);
19017        cx.emit(EditorEvent::Blurred);
19018        cx.notify();
19019    }
19020
19021    pub fn register_action<A: Action>(
19022        &mut self,
19023        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19024    ) -> Subscription {
19025        let id = self.next_editor_action_id.post_inc();
19026        let listener = Arc::new(listener);
19027        self.editor_actions.borrow_mut().insert(
19028            id,
19029            Box::new(move |window, _| {
19030                let listener = listener.clone();
19031                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19032                    let action = action.downcast_ref().unwrap();
19033                    if phase == DispatchPhase::Bubble {
19034                        listener(action, window, cx)
19035                    }
19036                })
19037            }),
19038        );
19039
19040        let editor_actions = self.editor_actions.clone();
19041        Subscription::new(move || {
19042            editor_actions.borrow_mut().remove(&id);
19043        })
19044    }
19045
19046    pub fn file_header_size(&self) -> u32 {
19047        FILE_HEADER_HEIGHT
19048    }
19049
19050    pub fn restore(
19051        &mut self,
19052        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19053        window: &mut Window,
19054        cx: &mut Context<Self>,
19055    ) {
19056        let workspace = self.workspace();
19057        let project = self.project.as_ref();
19058        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19059            let mut tasks = Vec::new();
19060            for (buffer_id, changes) in revert_changes {
19061                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19062                    buffer.update(cx, |buffer, cx| {
19063                        buffer.edit(
19064                            changes
19065                                .into_iter()
19066                                .map(|(range, text)| (range, text.to_string())),
19067                            None,
19068                            cx,
19069                        );
19070                    });
19071
19072                    if let Some(project) =
19073                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19074                    {
19075                        project.update(cx, |project, cx| {
19076                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19077                        })
19078                    }
19079                }
19080            }
19081            tasks
19082        });
19083        cx.spawn_in(window, async move |_, cx| {
19084            for (buffer, task) in save_tasks {
19085                let result = task.await;
19086                if result.is_err() {
19087                    let Some(path) = buffer
19088                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19089                        .ok()
19090                    else {
19091                        continue;
19092                    };
19093                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19094                        let Some(task) = cx
19095                            .update_window_entity(&workspace, |workspace, window, cx| {
19096                                workspace
19097                                    .open_path_preview(path, None, false, false, false, window, cx)
19098                            })
19099                            .ok()
19100                        else {
19101                            continue;
19102                        };
19103                        task.await.log_err();
19104                    }
19105                }
19106            }
19107        })
19108        .detach();
19109        self.change_selections(None, window, cx, |selections| selections.refresh());
19110    }
19111
19112    pub fn to_pixel_point(
19113        &self,
19114        source: multi_buffer::Anchor,
19115        editor_snapshot: &EditorSnapshot,
19116        window: &mut Window,
19117    ) -> Option<gpui::Point<Pixels>> {
19118        let source_point = source.to_display_point(editor_snapshot);
19119        self.display_to_pixel_point(source_point, editor_snapshot, window)
19120    }
19121
19122    pub fn display_to_pixel_point(
19123        &self,
19124        source: DisplayPoint,
19125        editor_snapshot: &EditorSnapshot,
19126        window: &mut Window,
19127    ) -> Option<gpui::Point<Pixels>> {
19128        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19129        let text_layout_details = self.text_layout_details(window);
19130        let scroll_top = text_layout_details
19131            .scroll_anchor
19132            .scroll_position(editor_snapshot)
19133            .y;
19134
19135        if source.row().as_f32() < scroll_top.floor() {
19136            return None;
19137        }
19138        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19139        let source_y = line_height * (source.row().as_f32() - scroll_top);
19140        Some(gpui::Point::new(source_x, source_y))
19141    }
19142
19143    pub fn has_visible_completions_menu(&self) -> bool {
19144        !self.edit_prediction_preview_is_active()
19145            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19146                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19147            })
19148    }
19149
19150    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19151        if self.mode.is_minimap() {
19152            return;
19153        }
19154        self.addons
19155            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19156    }
19157
19158    pub fn unregister_addon<T: Addon>(&mut self) {
19159        self.addons.remove(&std::any::TypeId::of::<T>());
19160    }
19161
19162    pub fn addon<T: Addon>(&self) -> Option<&T> {
19163        let type_id = std::any::TypeId::of::<T>();
19164        self.addons
19165            .get(&type_id)
19166            .and_then(|item| item.to_any().downcast_ref::<T>())
19167    }
19168
19169    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19170        let type_id = std::any::TypeId::of::<T>();
19171        self.addons
19172            .get_mut(&type_id)
19173            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19174    }
19175
19176    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19177        let text_layout_details = self.text_layout_details(window);
19178        let style = &text_layout_details.editor_style;
19179        let font_id = window.text_system().resolve_font(&style.text.font());
19180        let font_size = style.text.font_size.to_pixels(window.rem_size());
19181        let line_height = style.text.line_height_in_pixels(window.rem_size());
19182        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19183
19184        gpui::Size::new(em_width, line_height)
19185    }
19186
19187    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19188        self.load_diff_task.clone()
19189    }
19190
19191    fn read_metadata_from_db(
19192        &mut self,
19193        item_id: u64,
19194        workspace_id: WorkspaceId,
19195        window: &mut Window,
19196        cx: &mut Context<Editor>,
19197    ) {
19198        if self.is_singleton(cx)
19199            && !self.mode.is_minimap()
19200            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19201        {
19202            let buffer_snapshot = OnceCell::new();
19203
19204            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19205                if !folds.is_empty() {
19206                    let snapshot =
19207                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19208                    self.fold_ranges(
19209                        folds
19210                            .into_iter()
19211                            .map(|(start, end)| {
19212                                snapshot.clip_offset(start, Bias::Left)
19213                                    ..snapshot.clip_offset(end, Bias::Right)
19214                            })
19215                            .collect(),
19216                        false,
19217                        window,
19218                        cx,
19219                    );
19220                }
19221            }
19222
19223            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19224                if !selections.is_empty() {
19225                    let snapshot =
19226                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19227                    self.change_selections(None, window, cx, |s| {
19228                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19229                            snapshot.clip_offset(start, Bias::Left)
19230                                ..snapshot.clip_offset(end, Bias::Right)
19231                        }));
19232                    });
19233                }
19234            };
19235        }
19236
19237        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19238    }
19239}
19240
19241fn vim_enabled(cx: &App) -> bool {
19242    cx.global::<SettingsStore>()
19243        .raw_user_settings()
19244        .get("vim_mode")
19245        == Some(&serde_json::Value::Bool(true))
19246}
19247
19248// Consider user intent and default settings
19249fn choose_completion_range(
19250    completion: &Completion,
19251    intent: CompletionIntent,
19252    buffer: &Entity<Buffer>,
19253    cx: &mut Context<Editor>,
19254) -> Range<usize> {
19255    fn should_replace(
19256        completion: &Completion,
19257        insert_range: &Range<text::Anchor>,
19258        intent: CompletionIntent,
19259        completion_mode_setting: LspInsertMode,
19260        buffer: &Buffer,
19261    ) -> bool {
19262        // specific actions take precedence over settings
19263        match intent {
19264            CompletionIntent::CompleteWithInsert => return false,
19265            CompletionIntent::CompleteWithReplace => return true,
19266            CompletionIntent::Complete | CompletionIntent::Compose => {}
19267        }
19268
19269        match completion_mode_setting {
19270            LspInsertMode::Insert => false,
19271            LspInsertMode::Replace => true,
19272            LspInsertMode::ReplaceSubsequence => {
19273                let mut text_to_replace = buffer.chars_for_range(
19274                    buffer.anchor_before(completion.replace_range.start)
19275                        ..buffer.anchor_after(completion.replace_range.end),
19276                );
19277                let mut completion_text = completion.new_text.chars();
19278
19279                // is `text_to_replace` a subsequence of `completion_text`
19280                text_to_replace
19281                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19282            }
19283            LspInsertMode::ReplaceSuffix => {
19284                let range_after_cursor = insert_range.end..completion.replace_range.end;
19285
19286                let text_after_cursor = buffer
19287                    .text_for_range(
19288                        buffer.anchor_before(range_after_cursor.start)
19289                            ..buffer.anchor_after(range_after_cursor.end),
19290                    )
19291                    .collect::<String>();
19292                completion.new_text.ends_with(&text_after_cursor)
19293            }
19294        }
19295    }
19296
19297    let buffer = buffer.read(cx);
19298
19299    if let CompletionSource::Lsp {
19300        insert_range: Some(insert_range),
19301        ..
19302    } = &completion.source
19303    {
19304        let completion_mode_setting =
19305            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19306                .completions
19307                .lsp_insert_mode;
19308
19309        if !should_replace(
19310            completion,
19311            &insert_range,
19312            intent,
19313            completion_mode_setting,
19314            buffer,
19315        ) {
19316            return insert_range.to_offset(buffer);
19317        }
19318    }
19319
19320    completion.replace_range.to_offset(buffer)
19321}
19322
19323fn insert_extra_newline_brackets(
19324    buffer: &MultiBufferSnapshot,
19325    range: Range<usize>,
19326    language: &language::LanguageScope,
19327) -> bool {
19328    let leading_whitespace_len = buffer
19329        .reversed_chars_at(range.start)
19330        .take_while(|c| c.is_whitespace() && *c != '\n')
19331        .map(|c| c.len_utf8())
19332        .sum::<usize>();
19333    let trailing_whitespace_len = buffer
19334        .chars_at(range.end)
19335        .take_while(|c| c.is_whitespace() && *c != '\n')
19336        .map(|c| c.len_utf8())
19337        .sum::<usize>();
19338    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19339
19340    language.brackets().any(|(pair, enabled)| {
19341        let pair_start = pair.start.trim_end();
19342        let pair_end = pair.end.trim_start();
19343
19344        enabled
19345            && pair.newline
19346            && buffer.contains_str_at(range.end, pair_end)
19347            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19348    })
19349}
19350
19351fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19352    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19353        [(buffer, range, _)] => (*buffer, range.clone()),
19354        _ => return false,
19355    };
19356    let pair = {
19357        let mut result: Option<BracketMatch> = None;
19358
19359        for pair in buffer
19360            .all_bracket_ranges(range.clone())
19361            .filter(move |pair| {
19362                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19363            })
19364        {
19365            let len = pair.close_range.end - pair.open_range.start;
19366
19367            if let Some(existing) = &result {
19368                let existing_len = existing.close_range.end - existing.open_range.start;
19369                if len > existing_len {
19370                    continue;
19371                }
19372            }
19373
19374            result = Some(pair);
19375        }
19376
19377        result
19378    };
19379    let Some(pair) = pair else {
19380        return false;
19381    };
19382    pair.newline_only
19383        && buffer
19384            .chars_for_range(pair.open_range.end..range.start)
19385            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19386            .all(|c| c.is_whitespace() && c != '\n')
19387}
19388
19389fn update_uncommitted_diff_for_buffer(
19390    editor: Entity<Editor>,
19391    project: &Entity<Project>,
19392    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19393    buffer: Entity<MultiBuffer>,
19394    cx: &mut App,
19395) -> Task<()> {
19396    let mut tasks = Vec::new();
19397    project.update(cx, |project, cx| {
19398        for buffer in buffers {
19399            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19400                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19401            }
19402        }
19403    });
19404    cx.spawn(async move |cx| {
19405        let diffs = future::join_all(tasks).await;
19406        if editor
19407            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19408            .unwrap_or(false)
19409        {
19410            return;
19411        }
19412
19413        buffer
19414            .update(cx, |buffer, cx| {
19415                for diff in diffs.into_iter().flatten() {
19416                    buffer.add_diff(diff, cx);
19417                }
19418            })
19419            .ok();
19420    })
19421}
19422
19423fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19424    let tab_size = tab_size.get() as usize;
19425    let mut width = offset;
19426
19427    for ch in text.chars() {
19428        width += if ch == '\t' {
19429            tab_size - (width % tab_size)
19430        } else {
19431            1
19432        };
19433    }
19434
19435    width - offset
19436}
19437
19438#[cfg(test)]
19439mod tests {
19440    use super::*;
19441
19442    #[test]
19443    fn test_string_size_with_expanded_tabs() {
19444        let nz = |val| NonZeroU32::new(val).unwrap();
19445        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19446        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19447        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19448        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19449        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19450        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19451        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19452        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19453    }
19454}
19455
19456/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19457struct WordBreakingTokenizer<'a> {
19458    input: &'a str,
19459}
19460
19461impl<'a> WordBreakingTokenizer<'a> {
19462    fn new(input: &'a str) -> Self {
19463        Self { input }
19464    }
19465}
19466
19467fn is_char_ideographic(ch: char) -> bool {
19468    use unicode_script::Script::*;
19469    use unicode_script::UnicodeScript;
19470    matches!(ch.script(), Han | Tangut | Yi)
19471}
19472
19473fn is_grapheme_ideographic(text: &str) -> bool {
19474    text.chars().any(is_char_ideographic)
19475}
19476
19477fn is_grapheme_whitespace(text: &str) -> bool {
19478    text.chars().any(|x| x.is_whitespace())
19479}
19480
19481fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19482    text.chars().next().map_or(false, |ch| {
19483        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19484    })
19485}
19486
19487#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19488enum WordBreakToken<'a> {
19489    Word { token: &'a str, grapheme_len: usize },
19490    InlineWhitespace { token: &'a str, grapheme_len: usize },
19491    Newline,
19492}
19493
19494impl<'a> Iterator for WordBreakingTokenizer<'a> {
19495    /// Yields a span, the count of graphemes in the token, and whether it was
19496    /// whitespace. Note that it also breaks at word boundaries.
19497    type Item = WordBreakToken<'a>;
19498
19499    fn next(&mut self) -> Option<Self::Item> {
19500        use unicode_segmentation::UnicodeSegmentation;
19501        if self.input.is_empty() {
19502            return None;
19503        }
19504
19505        let mut iter = self.input.graphemes(true).peekable();
19506        let mut offset = 0;
19507        let mut grapheme_len = 0;
19508        if let Some(first_grapheme) = iter.next() {
19509            let is_newline = first_grapheme == "\n";
19510            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19511            offset += first_grapheme.len();
19512            grapheme_len += 1;
19513            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19514                if let Some(grapheme) = iter.peek().copied() {
19515                    if should_stay_with_preceding_ideograph(grapheme) {
19516                        offset += grapheme.len();
19517                        grapheme_len += 1;
19518                    }
19519                }
19520            } else {
19521                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19522                let mut next_word_bound = words.peek().copied();
19523                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19524                    next_word_bound = words.next();
19525                }
19526                while let Some(grapheme) = iter.peek().copied() {
19527                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19528                        break;
19529                    };
19530                    if is_grapheme_whitespace(grapheme) != is_whitespace
19531                        || (grapheme == "\n") != is_newline
19532                    {
19533                        break;
19534                    };
19535                    offset += grapheme.len();
19536                    grapheme_len += 1;
19537                    iter.next();
19538                }
19539            }
19540            let token = &self.input[..offset];
19541            self.input = &self.input[offset..];
19542            if token == "\n" {
19543                Some(WordBreakToken::Newline)
19544            } else if is_whitespace {
19545                Some(WordBreakToken::InlineWhitespace {
19546                    token,
19547                    grapheme_len,
19548                })
19549            } else {
19550                Some(WordBreakToken::Word {
19551                    token,
19552                    grapheme_len,
19553                })
19554            }
19555        } else {
19556            None
19557        }
19558    }
19559}
19560
19561#[test]
19562fn test_word_breaking_tokenizer() {
19563    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19564        ("", &[]),
19565        ("  ", &[whitespace("  ", 2)]),
19566        ("Ʒ", &[word("Ʒ", 1)]),
19567        ("Ǽ", &[word("Ǽ", 1)]),
19568        ("", &[word("", 1)]),
19569        ("⋑⋑", &[word("⋑⋑", 2)]),
19570        (
19571            "原理,进而",
19572            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19573        ),
19574        (
19575            "hello world",
19576            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19577        ),
19578        (
19579            "hello, world",
19580            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19581        ),
19582        (
19583            "  hello world",
19584            &[
19585                whitespace("  ", 2),
19586                word("hello", 5),
19587                whitespace(" ", 1),
19588                word("world", 5),
19589            ],
19590        ),
19591        (
19592            "这是什么 \n 钢笔",
19593            &[
19594                word("", 1),
19595                word("", 1),
19596                word("", 1),
19597                word("", 1),
19598                whitespace(" ", 1),
19599                newline(),
19600                whitespace(" ", 1),
19601                word("", 1),
19602                word("", 1),
19603            ],
19604        ),
19605        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19606    ];
19607
19608    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19609        WordBreakToken::Word {
19610            token,
19611            grapheme_len,
19612        }
19613    }
19614
19615    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19616        WordBreakToken::InlineWhitespace {
19617            token,
19618            grapheme_len,
19619        }
19620    }
19621
19622    fn newline() -> WordBreakToken<'static> {
19623        WordBreakToken::Newline
19624    }
19625
19626    for (input, result) in tests {
19627        assert_eq!(
19628            WordBreakingTokenizer::new(input)
19629                .collect::<Vec<_>>()
19630                .as_slice(),
19631            *result,
19632        );
19633    }
19634}
19635
19636fn wrap_with_prefix(
19637    line_prefix: String,
19638    unwrapped_text: String,
19639    wrap_column: usize,
19640    tab_size: NonZeroU32,
19641    preserve_existing_whitespace: bool,
19642) -> String {
19643    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19644    let mut wrapped_text = String::new();
19645    let mut current_line = line_prefix.clone();
19646
19647    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19648    let mut current_line_len = line_prefix_len;
19649    let mut in_whitespace = false;
19650    for token in tokenizer {
19651        let have_preceding_whitespace = in_whitespace;
19652        match token {
19653            WordBreakToken::Word {
19654                token,
19655                grapheme_len,
19656            } => {
19657                in_whitespace = false;
19658                if current_line_len + grapheme_len > wrap_column
19659                    && current_line_len != line_prefix_len
19660                {
19661                    wrapped_text.push_str(current_line.trim_end());
19662                    wrapped_text.push('\n');
19663                    current_line.truncate(line_prefix.len());
19664                    current_line_len = line_prefix_len;
19665                }
19666                current_line.push_str(token);
19667                current_line_len += grapheme_len;
19668            }
19669            WordBreakToken::InlineWhitespace {
19670                mut token,
19671                mut grapheme_len,
19672            } => {
19673                in_whitespace = true;
19674                if have_preceding_whitespace && !preserve_existing_whitespace {
19675                    continue;
19676                }
19677                if !preserve_existing_whitespace {
19678                    token = " ";
19679                    grapheme_len = 1;
19680                }
19681                if current_line_len + grapheme_len > wrap_column {
19682                    wrapped_text.push_str(current_line.trim_end());
19683                    wrapped_text.push('\n');
19684                    current_line.truncate(line_prefix.len());
19685                    current_line_len = line_prefix_len;
19686                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19687                    current_line.push_str(token);
19688                    current_line_len += grapheme_len;
19689                }
19690            }
19691            WordBreakToken::Newline => {
19692                in_whitespace = true;
19693                if preserve_existing_whitespace {
19694                    wrapped_text.push_str(current_line.trim_end());
19695                    wrapped_text.push('\n');
19696                    current_line.truncate(line_prefix.len());
19697                    current_line_len = line_prefix_len;
19698                } else if have_preceding_whitespace {
19699                    continue;
19700                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19701                {
19702                    wrapped_text.push_str(current_line.trim_end());
19703                    wrapped_text.push('\n');
19704                    current_line.truncate(line_prefix.len());
19705                    current_line_len = line_prefix_len;
19706                } else if current_line_len != line_prefix_len {
19707                    current_line.push(' ');
19708                    current_line_len += 1;
19709                }
19710            }
19711        }
19712    }
19713
19714    if !current_line.is_empty() {
19715        wrapped_text.push_str(&current_line);
19716    }
19717    wrapped_text
19718}
19719
19720#[test]
19721fn test_wrap_with_prefix() {
19722    assert_eq!(
19723        wrap_with_prefix(
19724            "# ".to_string(),
19725            "abcdefg".to_string(),
19726            4,
19727            NonZeroU32::new(4).unwrap(),
19728            false,
19729        ),
19730        "# abcdefg"
19731    );
19732    assert_eq!(
19733        wrap_with_prefix(
19734            "".to_string(),
19735            "\thello world".to_string(),
19736            8,
19737            NonZeroU32::new(4).unwrap(),
19738            false,
19739        ),
19740        "hello\nworld"
19741    );
19742    assert_eq!(
19743        wrap_with_prefix(
19744            "// ".to_string(),
19745            "xx \nyy zz aa bb cc".to_string(),
19746            12,
19747            NonZeroU32::new(4).unwrap(),
19748            false,
19749        ),
19750        "// xx yy zz\n// aa bb cc"
19751    );
19752    assert_eq!(
19753        wrap_with_prefix(
19754            String::new(),
19755            "这是什么 \n 钢笔".to_string(),
19756            3,
19757            NonZeroU32::new(4).unwrap(),
19758            false,
19759        ),
19760        "这是什\n么 钢\n"
19761    );
19762}
19763
19764pub trait CollaborationHub {
19765    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19766    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19767    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19768}
19769
19770impl CollaborationHub for Entity<Project> {
19771    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19772        self.read(cx).collaborators()
19773    }
19774
19775    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19776        self.read(cx).user_store().read(cx).participant_indices()
19777    }
19778
19779    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19780        let this = self.read(cx);
19781        let user_ids = this.collaborators().values().map(|c| c.user_id);
19782        this.user_store().read_with(cx, |user_store, cx| {
19783            user_store.participant_names(user_ids, cx)
19784        })
19785    }
19786}
19787
19788pub trait SemanticsProvider {
19789    fn hover(
19790        &self,
19791        buffer: &Entity<Buffer>,
19792        position: text::Anchor,
19793        cx: &mut App,
19794    ) -> Option<Task<Vec<project::Hover>>>;
19795
19796    fn inline_values(
19797        &self,
19798        buffer_handle: Entity<Buffer>,
19799        range: Range<text::Anchor>,
19800        cx: &mut App,
19801    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19802
19803    fn inlay_hints(
19804        &self,
19805        buffer_handle: Entity<Buffer>,
19806        range: Range<text::Anchor>,
19807        cx: &mut App,
19808    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19809
19810    fn resolve_inlay_hint(
19811        &self,
19812        hint: InlayHint,
19813        buffer_handle: Entity<Buffer>,
19814        server_id: LanguageServerId,
19815        cx: &mut App,
19816    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19817
19818    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19819
19820    fn document_highlights(
19821        &self,
19822        buffer: &Entity<Buffer>,
19823        position: text::Anchor,
19824        cx: &mut App,
19825    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19826
19827    fn definitions(
19828        &self,
19829        buffer: &Entity<Buffer>,
19830        position: text::Anchor,
19831        kind: GotoDefinitionKind,
19832        cx: &mut App,
19833    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19834
19835    fn range_for_rename(
19836        &self,
19837        buffer: &Entity<Buffer>,
19838        position: text::Anchor,
19839        cx: &mut App,
19840    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19841
19842    fn perform_rename(
19843        &self,
19844        buffer: &Entity<Buffer>,
19845        position: text::Anchor,
19846        new_name: String,
19847        cx: &mut App,
19848    ) -> Option<Task<Result<ProjectTransaction>>>;
19849}
19850
19851pub trait CompletionProvider {
19852    fn completions(
19853        &self,
19854        excerpt_id: ExcerptId,
19855        buffer: &Entity<Buffer>,
19856        buffer_position: text::Anchor,
19857        trigger: CompletionContext,
19858        window: &mut Window,
19859        cx: &mut Context<Editor>,
19860    ) -> Task<Result<Option<Vec<Completion>>>>;
19861
19862    fn resolve_completions(
19863        &self,
19864        buffer: Entity<Buffer>,
19865        completion_indices: Vec<usize>,
19866        completions: Rc<RefCell<Box<[Completion]>>>,
19867        cx: &mut Context<Editor>,
19868    ) -> Task<Result<bool>>;
19869
19870    fn apply_additional_edits_for_completion(
19871        &self,
19872        _buffer: Entity<Buffer>,
19873        _completions: Rc<RefCell<Box<[Completion]>>>,
19874        _completion_index: usize,
19875        _push_to_history: bool,
19876        _cx: &mut Context<Editor>,
19877    ) -> Task<Result<Option<language::Transaction>>> {
19878        Task::ready(Ok(None))
19879    }
19880
19881    fn is_completion_trigger(
19882        &self,
19883        buffer: &Entity<Buffer>,
19884        position: language::Anchor,
19885        text: &str,
19886        trigger_in_words: bool,
19887        cx: &mut Context<Editor>,
19888    ) -> bool;
19889
19890    fn sort_completions(&self) -> bool {
19891        true
19892    }
19893
19894    fn filter_completions(&self) -> bool {
19895        true
19896    }
19897}
19898
19899pub trait CodeActionProvider {
19900    fn id(&self) -> Arc<str>;
19901
19902    fn code_actions(
19903        &self,
19904        buffer: &Entity<Buffer>,
19905        range: Range<text::Anchor>,
19906        window: &mut Window,
19907        cx: &mut App,
19908    ) -> Task<Result<Vec<CodeAction>>>;
19909
19910    fn apply_code_action(
19911        &self,
19912        buffer_handle: Entity<Buffer>,
19913        action: CodeAction,
19914        excerpt_id: ExcerptId,
19915        push_to_history: bool,
19916        window: &mut Window,
19917        cx: &mut App,
19918    ) -> Task<Result<ProjectTransaction>>;
19919}
19920
19921impl CodeActionProvider for Entity<Project> {
19922    fn id(&self) -> Arc<str> {
19923        "project".into()
19924    }
19925
19926    fn code_actions(
19927        &self,
19928        buffer: &Entity<Buffer>,
19929        range: Range<text::Anchor>,
19930        _window: &mut Window,
19931        cx: &mut App,
19932    ) -> Task<Result<Vec<CodeAction>>> {
19933        self.update(cx, |project, cx| {
19934            let code_lens = project.code_lens(buffer, range.clone(), cx);
19935            let code_actions = project.code_actions(buffer, range, None, cx);
19936            cx.background_spawn(async move {
19937                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19938                Ok(code_lens
19939                    .context("code lens fetch")?
19940                    .into_iter()
19941                    .chain(code_actions.context("code action fetch")?)
19942                    .collect())
19943            })
19944        })
19945    }
19946
19947    fn apply_code_action(
19948        &self,
19949        buffer_handle: Entity<Buffer>,
19950        action: CodeAction,
19951        _excerpt_id: ExcerptId,
19952        push_to_history: bool,
19953        _window: &mut Window,
19954        cx: &mut App,
19955    ) -> Task<Result<ProjectTransaction>> {
19956        self.update(cx, |project, cx| {
19957            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19958        })
19959    }
19960}
19961
19962fn snippet_completions(
19963    project: &Project,
19964    buffer: &Entity<Buffer>,
19965    buffer_position: text::Anchor,
19966    cx: &mut App,
19967) -> Task<Result<Vec<Completion>>> {
19968    let languages = buffer.read(cx).languages_at(buffer_position);
19969    let snippet_store = project.snippets().read(cx);
19970
19971    let scopes: Vec<_> = languages
19972        .iter()
19973        .filter_map(|language| {
19974            let language_name = language.lsp_id();
19975            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19976
19977            if snippets.is_empty() {
19978                None
19979            } else {
19980                Some((language.default_scope(), snippets))
19981            }
19982        })
19983        .collect();
19984
19985    if scopes.is_empty() {
19986        return Task::ready(Ok(vec![]));
19987    }
19988
19989    let snapshot = buffer.read(cx).text_snapshot();
19990    let chars: String = snapshot
19991        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19992        .collect();
19993    let executor = cx.background_executor().clone();
19994
19995    cx.background_spawn(async move {
19996        let mut all_results: Vec<Completion> = Vec::new();
19997        for (scope, snippets) in scopes.into_iter() {
19998            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19999            let mut last_word = chars
20000                .chars()
20001                .take_while(|c| classifier.is_word(*c))
20002                .collect::<String>();
20003            last_word = last_word.chars().rev().collect();
20004
20005            if last_word.is_empty() {
20006                return Ok(vec![]);
20007            }
20008
20009            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20010            let to_lsp = |point: &text::Anchor| {
20011                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20012                point_to_lsp(end)
20013            };
20014            let lsp_end = to_lsp(&buffer_position);
20015
20016            let candidates = snippets
20017                .iter()
20018                .enumerate()
20019                .flat_map(|(ix, snippet)| {
20020                    snippet
20021                        .prefix
20022                        .iter()
20023                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20024                })
20025                .collect::<Vec<StringMatchCandidate>>();
20026
20027            let mut matches = fuzzy::match_strings(
20028                &candidates,
20029                &last_word,
20030                last_word.chars().any(|c| c.is_uppercase()),
20031                100,
20032                &Default::default(),
20033                executor.clone(),
20034            )
20035            .await;
20036
20037            // Remove all candidates where the query's start does not match the start of any word in the candidate
20038            if let Some(query_start) = last_word.chars().next() {
20039                matches.retain(|string_match| {
20040                    split_words(&string_match.string).any(|word| {
20041                        // Check that the first codepoint of the word as lowercase matches the first
20042                        // codepoint of the query as lowercase
20043                        word.chars()
20044                            .flat_map(|codepoint| codepoint.to_lowercase())
20045                            .zip(query_start.to_lowercase())
20046                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20047                    })
20048                });
20049            }
20050
20051            let matched_strings = matches
20052                .into_iter()
20053                .map(|m| m.string)
20054                .collect::<HashSet<_>>();
20055
20056            let mut result: Vec<Completion> = snippets
20057                .iter()
20058                .filter_map(|snippet| {
20059                    let matching_prefix = snippet
20060                        .prefix
20061                        .iter()
20062                        .find(|prefix| matched_strings.contains(*prefix))?;
20063                    let start = as_offset - last_word.len();
20064                    let start = snapshot.anchor_before(start);
20065                    let range = start..buffer_position;
20066                    let lsp_start = to_lsp(&start);
20067                    let lsp_range = lsp::Range {
20068                        start: lsp_start,
20069                        end: lsp_end,
20070                    };
20071                    Some(Completion {
20072                        replace_range: range,
20073                        new_text: snippet.body.clone(),
20074                        source: CompletionSource::Lsp {
20075                            insert_range: None,
20076                            server_id: LanguageServerId(usize::MAX),
20077                            resolved: true,
20078                            lsp_completion: Box::new(lsp::CompletionItem {
20079                                label: snippet.prefix.first().unwrap().clone(),
20080                                kind: Some(CompletionItemKind::SNIPPET),
20081                                label_details: snippet.description.as_ref().map(|description| {
20082                                    lsp::CompletionItemLabelDetails {
20083                                        detail: Some(description.clone()),
20084                                        description: None,
20085                                    }
20086                                }),
20087                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20088                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20089                                    lsp::InsertReplaceEdit {
20090                                        new_text: snippet.body.clone(),
20091                                        insert: lsp_range,
20092                                        replace: lsp_range,
20093                                    },
20094                                )),
20095                                filter_text: Some(snippet.body.clone()),
20096                                sort_text: Some(char::MAX.to_string()),
20097                                ..lsp::CompletionItem::default()
20098                            }),
20099                            lsp_defaults: None,
20100                        },
20101                        label: CodeLabel {
20102                            text: matching_prefix.clone(),
20103                            runs: Vec::new(),
20104                            filter_range: 0..matching_prefix.len(),
20105                        },
20106                        icon_path: None,
20107                        documentation: Some(
20108                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20109                                single_line: snippet.name.clone().into(),
20110                                plain_text: snippet
20111                                    .description
20112                                    .clone()
20113                                    .map(|description| description.into()),
20114                            },
20115                        ),
20116                        insert_text_mode: None,
20117                        confirm: None,
20118                    })
20119                })
20120                .collect();
20121
20122            all_results.append(&mut result);
20123        }
20124
20125        Ok(all_results)
20126    })
20127}
20128
20129impl CompletionProvider for Entity<Project> {
20130    fn completions(
20131        &self,
20132        _excerpt_id: ExcerptId,
20133        buffer: &Entity<Buffer>,
20134        buffer_position: text::Anchor,
20135        options: CompletionContext,
20136        _window: &mut Window,
20137        cx: &mut Context<Editor>,
20138    ) -> Task<Result<Option<Vec<Completion>>>> {
20139        self.update(cx, |project, cx| {
20140            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20141            let project_completions = project.completions(buffer, buffer_position, options, cx);
20142            cx.background_spawn(async move {
20143                let snippets_completions = snippets.await?;
20144                match project_completions.await? {
20145                    Some(mut completions) => {
20146                        completions.extend(snippets_completions);
20147                        Ok(Some(completions))
20148                    }
20149                    None => {
20150                        if snippets_completions.is_empty() {
20151                            Ok(None)
20152                        } else {
20153                            Ok(Some(snippets_completions))
20154                        }
20155                    }
20156                }
20157            })
20158        })
20159    }
20160
20161    fn resolve_completions(
20162        &self,
20163        buffer: Entity<Buffer>,
20164        completion_indices: Vec<usize>,
20165        completions: Rc<RefCell<Box<[Completion]>>>,
20166        cx: &mut Context<Editor>,
20167    ) -> Task<Result<bool>> {
20168        self.update(cx, |project, cx| {
20169            project.lsp_store().update(cx, |lsp_store, cx| {
20170                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20171            })
20172        })
20173    }
20174
20175    fn apply_additional_edits_for_completion(
20176        &self,
20177        buffer: Entity<Buffer>,
20178        completions: Rc<RefCell<Box<[Completion]>>>,
20179        completion_index: usize,
20180        push_to_history: bool,
20181        cx: &mut Context<Editor>,
20182    ) -> Task<Result<Option<language::Transaction>>> {
20183        self.update(cx, |project, cx| {
20184            project.lsp_store().update(cx, |lsp_store, cx| {
20185                lsp_store.apply_additional_edits_for_completion(
20186                    buffer,
20187                    completions,
20188                    completion_index,
20189                    push_to_history,
20190                    cx,
20191                )
20192            })
20193        })
20194    }
20195
20196    fn is_completion_trigger(
20197        &self,
20198        buffer: &Entity<Buffer>,
20199        position: language::Anchor,
20200        text: &str,
20201        trigger_in_words: bool,
20202        cx: &mut Context<Editor>,
20203    ) -> bool {
20204        let mut chars = text.chars();
20205        let char = if let Some(char) = chars.next() {
20206            char
20207        } else {
20208            return false;
20209        };
20210        if chars.next().is_some() {
20211            return false;
20212        }
20213
20214        let buffer = buffer.read(cx);
20215        let snapshot = buffer.snapshot();
20216        if !snapshot.settings_at(position, cx).show_completions_on_input {
20217            return false;
20218        }
20219        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20220        if trigger_in_words && classifier.is_word(char) {
20221            return true;
20222        }
20223
20224        buffer.completion_triggers().contains(text)
20225    }
20226}
20227
20228impl SemanticsProvider for Entity<Project> {
20229    fn hover(
20230        &self,
20231        buffer: &Entity<Buffer>,
20232        position: text::Anchor,
20233        cx: &mut App,
20234    ) -> Option<Task<Vec<project::Hover>>> {
20235        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20236    }
20237
20238    fn document_highlights(
20239        &self,
20240        buffer: &Entity<Buffer>,
20241        position: text::Anchor,
20242        cx: &mut App,
20243    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20244        Some(self.update(cx, |project, cx| {
20245            project.document_highlights(buffer, position, cx)
20246        }))
20247    }
20248
20249    fn definitions(
20250        &self,
20251        buffer: &Entity<Buffer>,
20252        position: text::Anchor,
20253        kind: GotoDefinitionKind,
20254        cx: &mut App,
20255    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20256        Some(self.update(cx, |project, cx| match kind {
20257            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20258            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20259            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20260            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20261        }))
20262    }
20263
20264    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20265        // TODO: make this work for remote projects
20266        self.update(cx, |project, cx| {
20267            if project
20268                .active_debug_session(cx)
20269                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20270            {
20271                return true;
20272            }
20273
20274            buffer.update(cx, |buffer, cx| {
20275                project.any_language_server_supports_inlay_hints(buffer, cx)
20276            })
20277        })
20278    }
20279
20280    fn inline_values(
20281        &self,
20282        buffer_handle: Entity<Buffer>,
20283
20284        range: Range<text::Anchor>,
20285        cx: &mut App,
20286    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20287        self.update(cx, |project, cx| {
20288            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20289
20290            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20291        })
20292    }
20293
20294    fn inlay_hints(
20295        &self,
20296        buffer_handle: Entity<Buffer>,
20297        range: Range<text::Anchor>,
20298        cx: &mut App,
20299    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20300        Some(self.update(cx, |project, cx| {
20301            project.inlay_hints(buffer_handle, range, cx)
20302        }))
20303    }
20304
20305    fn resolve_inlay_hint(
20306        &self,
20307        hint: InlayHint,
20308        buffer_handle: Entity<Buffer>,
20309        server_id: LanguageServerId,
20310        cx: &mut App,
20311    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20312        Some(self.update(cx, |project, cx| {
20313            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20314        }))
20315    }
20316
20317    fn range_for_rename(
20318        &self,
20319        buffer: &Entity<Buffer>,
20320        position: text::Anchor,
20321        cx: &mut App,
20322    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20323        Some(self.update(cx, |project, cx| {
20324            let buffer = buffer.clone();
20325            let task = project.prepare_rename(buffer.clone(), position, cx);
20326            cx.spawn(async move |_, cx| {
20327                Ok(match task.await? {
20328                    PrepareRenameResponse::Success(range) => Some(range),
20329                    PrepareRenameResponse::InvalidPosition => None,
20330                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20331                        // Fallback on using TreeSitter info to determine identifier range
20332                        buffer.update(cx, |buffer, _| {
20333                            let snapshot = buffer.snapshot();
20334                            let (range, kind) = snapshot.surrounding_word(position);
20335                            if kind != Some(CharKind::Word) {
20336                                return None;
20337                            }
20338                            Some(
20339                                snapshot.anchor_before(range.start)
20340                                    ..snapshot.anchor_after(range.end),
20341                            )
20342                        })?
20343                    }
20344                })
20345            })
20346        }))
20347    }
20348
20349    fn perform_rename(
20350        &self,
20351        buffer: &Entity<Buffer>,
20352        position: text::Anchor,
20353        new_name: String,
20354        cx: &mut App,
20355    ) -> Option<Task<Result<ProjectTransaction>>> {
20356        Some(self.update(cx, |project, cx| {
20357            project.perform_rename(buffer.clone(), position, new_name, cx)
20358        }))
20359    }
20360}
20361
20362fn inlay_hint_settings(
20363    location: Anchor,
20364    snapshot: &MultiBufferSnapshot,
20365    cx: &mut Context<Editor>,
20366) -> InlayHintSettings {
20367    let file = snapshot.file_at(location);
20368    let language = snapshot.language_at(location).map(|l| l.name());
20369    language_settings(language, file, cx).inlay_hints
20370}
20371
20372fn consume_contiguous_rows(
20373    contiguous_row_selections: &mut Vec<Selection<Point>>,
20374    selection: &Selection<Point>,
20375    display_map: &DisplaySnapshot,
20376    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20377) -> (MultiBufferRow, MultiBufferRow) {
20378    contiguous_row_selections.push(selection.clone());
20379    let start_row = MultiBufferRow(selection.start.row);
20380    let mut end_row = ending_row(selection, display_map);
20381
20382    while let Some(next_selection) = selections.peek() {
20383        if next_selection.start.row <= end_row.0 {
20384            end_row = ending_row(next_selection, display_map);
20385            contiguous_row_selections.push(selections.next().unwrap().clone());
20386        } else {
20387            break;
20388        }
20389    }
20390    (start_row, end_row)
20391}
20392
20393fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20394    if next_selection.end.column > 0 || next_selection.is_empty() {
20395        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20396    } else {
20397        MultiBufferRow(next_selection.end.row)
20398    }
20399}
20400
20401impl EditorSnapshot {
20402    pub fn remote_selections_in_range<'a>(
20403        &'a self,
20404        range: &'a Range<Anchor>,
20405        collaboration_hub: &dyn CollaborationHub,
20406        cx: &'a App,
20407    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20408        let participant_names = collaboration_hub.user_names(cx);
20409        let participant_indices = collaboration_hub.user_participant_indices(cx);
20410        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20411        let collaborators_by_replica_id = collaborators_by_peer_id
20412            .values()
20413            .map(|collaborator| (collaborator.replica_id, collaborator))
20414            .collect::<HashMap<_, _>>();
20415        self.buffer_snapshot
20416            .selections_in_range(range, false)
20417            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20418                if replica_id == AGENT_REPLICA_ID {
20419                    Some(RemoteSelection {
20420                        replica_id,
20421                        selection,
20422                        cursor_shape,
20423                        line_mode,
20424                        collaborator_id: CollaboratorId::Agent,
20425                        user_name: Some("Agent".into()),
20426                        color: cx.theme().players().agent(),
20427                    })
20428                } else {
20429                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20430                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20431                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20432                    Some(RemoteSelection {
20433                        replica_id,
20434                        selection,
20435                        cursor_shape,
20436                        line_mode,
20437                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20438                        user_name,
20439                        color: if let Some(index) = participant_index {
20440                            cx.theme().players().color_for_participant(index.0)
20441                        } else {
20442                            cx.theme().players().absent()
20443                        },
20444                    })
20445                }
20446            })
20447    }
20448
20449    pub fn hunks_for_ranges(
20450        &self,
20451        ranges: impl IntoIterator<Item = Range<Point>>,
20452    ) -> Vec<MultiBufferDiffHunk> {
20453        let mut hunks = Vec::new();
20454        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20455            HashMap::default();
20456        for query_range in ranges {
20457            let query_rows =
20458                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20459            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20460                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20461            ) {
20462                // Include deleted hunks that are adjacent to the query range, because
20463                // otherwise they would be missed.
20464                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20465                if hunk.status().is_deleted() {
20466                    intersects_range |= hunk.row_range.start == query_rows.end;
20467                    intersects_range |= hunk.row_range.end == query_rows.start;
20468                }
20469                if intersects_range {
20470                    if !processed_buffer_rows
20471                        .entry(hunk.buffer_id)
20472                        .or_default()
20473                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20474                    {
20475                        continue;
20476                    }
20477                    hunks.push(hunk);
20478                }
20479            }
20480        }
20481
20482        hunks
20483    }
20484
20485    fn display_diff_hunks_for_rows<'a>(
20486        &'a self,
20487        display_rows: Range<DisplayRow>,
20488        folded_buffers: &'a HashSet<BufferId>,
20489    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20490        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20491        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20492
20493        self.buffer_snapshot
20494            .diff_hunks_in_range(buffer_start..buffer_end)
20495            .filter_map(|hunk| {
20496                if folded_buffers.contains(&hunk.buffer_id) {
20497                    return None;
20498                }
20499
20500                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20501                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20502
20503                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20504                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20505
20506                let display_hunk = if hunk_display_start.column() != 0 {
20507                    DisplayDiffHunk::Folded {
20508                        display_row: hunk_display_start.row(),
20509                    }
20510                } else {
20511                    let mut end_row = hunk_display_end.row();
20512                    if hunk_display_end.column() > 0 {
20513                        end_row.0 += 1;
20514                    }
20515                    let is_created_file = hunk.is_created_file();
20516                    DisplayDiffHunk::Unfolded {
20517                        status: hunk.status(),
20518                        diff_base_byte_range: hunk.diff_base_byte_range,
20519                        display_row_range: hunk_display_start.row()..end_row,
20520                        multi_buffer_range: Anchor::range_in_buffer(
20521                            hunk.excerpt_id,
20522                            hunk.buffer_id,
20523                            hunk.buffer_range,
20524                        ),
20525                        is_created_file,
20526                    }
20527                };
20528
20529                Some(display_hunk)
20530            })
20531    }
20532
20533    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20534        self.display_snapshot.buffer_snapshot.language_at(position)
20535    }
20536
20537    pub fn is_focused(&self) -> bool {
20538        self.is_focused
20539    }
20540
20541    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20542        self.placeholder_text.as_ref()
20543    }
20544
20545    pub fn scroll_position(&self) -> gpui::Point<f32> {
20546        self.scroll_anchor.scroll_position(&self.display_snapshot)
20547    }
20548
20549    fn gutter_dimensions(
20550        &self,
20551        font_id: FontId,
20552        font_size: Pixels,
20553        max_line_number_width: Pixels,
20554        cx: &App,
20555    ) -> Option<GutterDimensions> {
20556        if !self.show_gutter {
20557            return None;
20558        }
20559
20560        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20561        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20562
20563        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20564            matches!(
20565                ProjectSettings::get_global(cx).git.git_gutter,
20566                Some(GitGutterSetting::TrackedFiles)
20567            )
20568        });
20569        let gutter_settings = EditorSettings::get_global(cx).gutter;
20570        let show_line_numbers = self
20571            .show_line_numbers
20572            .unwrap_or(gutter_settings.line_numbers);
20573        let line_gutter_width = if show_line_numbers {
20574            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20575            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20576            max_line_number_width.max(min_width_for_number_on_gutter)
20577        } else {
20578            0.0.into()
20579        };
20580
20581        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20582        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20583
20584        let git_blame_entries_width =
20585            self.git_blame_gutter_max_author_length
20586                .map(|max_author_length| {
20587                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20588                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20589
20590                    /// The number of characters to dedicate to gaps and margins.
20591                    const SPACING_WIDTH: usize = 4;
20592
20593                    let max_char_count = max_author_length.min(renderer.max_author_length())
20594                        + ::git::SHORT_SHA_LENGTH
20595                        + MAX_RELATIVE_TIMESTAMP.len()
20596                        + SPACING_WIDTH;
20597
20598                    em_advance * max_char_count
20599                });
20600
20601        let is_singleton = self.buffer_snapshot.is_singleton();
20602
20603        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20604        left_padding += if !is_singleton {
20605            em_width * 4.0
20606        } else if show_runnables || show_breakpoints {
20607            em_width * 3.0
20608        } else if show_git_gutter && show_line_numbers {
20609            em_width * 2.0
20610        } else if show_git_gutter || show_line_numbers {
20611            em_width
20612        } else {
20613            px(0.)
20614        };
20615
20616        let shows_folds = is_singleton && gutter_settings.folds;
20617
20618        let right_padding = if shows_folds && show_line_numbers {
20619            em_width * 4.0
20620        } else if shows_folds || (!is_singleton && show_line_numbers) {
20621            em_width * 3.0
20622        } else if show_line_numbers {
20623            em_width
20624        } else {
20625            px(0.)
20626        };
20627
20628        Some(GutterDimensions {
20629            left_padding,
20630            right_padding,
20631            width: line_gutter_width + left_padding + right_padding,
20632            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20633            git_blame_entries_width,
20634        })
20635    }
20636
20637    pub fn render_crease_toggle(
20638        &self,
20639        buffer_row: MultiBufferRow,
20640        row_contains_cursor: bool,
20641        editor: Entity<Editor>,
20642        window: &mut Window,
20643        cx: &mut App,
20644    ) -> Option<AnyElement> {
20645        let folded = self.is_line_folded(buffer_row);
20646        let mut is_foldable = false;
20647
20648        if let Some(crease) = self
20649            .crease_snapshot
20650            .query_row(buffer_row, &self.buffer_snapshot)
20651        {
20652            is_foldable = true;
20653            match crease {
20654                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20655                    if let Some(render_toggle) = render_toggle {
20656                        let toggle_callback =
20657                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20658                                if folded {
20659                                    editor.update(cx, |editor, cx| {
20660                                        editor.fold_at(buffer_row, window, cx)
20661                                    });
20662                                } else {
20663                                    editor.update(cx, |editor, cx| {
20664                                        editor.unfold_at(buffer_row, window, cx)
20665                                    });
20666                                }
20667                            });
20668                        return Some((render_toggle)(
20669                            buffer_row,
20670                            folded,
20671                            toggle_callback,
20672                            window,
20673                            cx,
20674                        ));
20675                    }
20676                }
20677            }
20678        }
20679
20680        is_foldable |= self.starts_indent(buffer_row);
20681
20682        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20683            Some(
20684                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20685                    .toggle_state(folded)
20686                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20687                        if folded {
20688                            this.unfold_at(buffer_row, window, cx);
20689                        } else {
20690                            this.fold_at(buffer_row, window, cx);
20691                        }
20692                    }))
20693                    .into_any_element(),
20694            )
20695        } else {
20696            None
20697        }
20698    }
20699
20700    pub fn render_crease_trailer(
20701        &self,
20702        buffer_row: MultiBufferRow,
20703        window: &mut Window,
20704        cx: &mut App,
20705    ) -> Option<AnyElement> {
20706        let folded = self.is_line_folded(buffer_row);
20707        if let Crease::Inline { render_trailer, .. } = self
20708            .crease_snapshot
20709            .query_row(buffer_row, &self.buffer_snapshot)?
20710        {
20711            let render_trailer = render_trailer.as_ref()?;
20712            Some(render_trailer(buffer_row, folded, window, cx))
20713        } else {
20714            None
20715        }
20716    }
20717}
20718
20719impl Deref for EditorSnapshot {
20720    type Target = DisplaySnapshot;
20721
20722    fn deref(&self) -> &Self::Target {
20723        &self.display_snapshot
20724    }
20725}
20726
20727#[derive(Clone, Debug, PartialEq, Eq)]
20728pub enum EditorEvent {
20729    InputIgnored {
20730        text: Arc<str>,
20731    },
20732    InputHandled {
20733        utf16_range_to_replace: Option<Range<isize>>,
20734        text: Arc<str>,
20735    },
20736    ExcerptsAdded {
20737        buffer: Entity<Buffer>,
20738        predecessor: ExcerptId,
20739        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20740    },
20741    ExcerptsRemoved {
20742        ids: Vec<ExcerptId>,
20743        removed_buffer_ids: Vec<BufferId>,
20744    },
20745    BufferFoldToggled {
20746        ids: Vec<ExcerptId>,
20747        folded: bool,
20748    },
20749    ExcerptsEdited {
20750        ids: Vec<ExcerptId>,
20751    },
20752    ExcerptsExpanded {
20753        ids: Vec<ExcerptId>,
20754    },
20755    BufferEdited,
20756    Edited {
20757        transaction_id: clock::Lamport,
20758    },
20759    Reparsed(BufferId),
20760    Focused,
20761    FocusedIn,
20762    Blurred,
20763    DirtyChanged,
20764    Saved,
20765    TitleChanged,
20766    DiffBaseChanged,
20767    SelectionsChanged {
20768        local: bool,
20769    },
20770    ScrollPositionChanged {
20771        local: bool,
20772        autoscroll: bool,
20773    },
20774    Closed,
20775    TransactionUndone {
20776        transaction_id: clock::Lamport,
20777    },
20778    TransactionBegun {
20779        transaction_id: clock::Lamport,
20780    },
20781    Reloaded,
20782    CursorShapeChanged,
20783    PushedToNavHistory {
20784        anchor: Anchor,
20785        is_deactivate: bool,
20786    },
20787}
20788
20789impl EventEmitter<EditorEvent> for Editor {}
20790
20791impl Focusable for Editor {
20792    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20793        self.focus_handle.clone()
20794    }
20795}
20796
20797impl Render for Editor {
20798    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20799        let settings = ThemeSettings::get_global(cx);
20800
20801        let mut text_style = match self.mode {
20802            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20803                color: cx.theme().colors().editor_foreground,
20804                font_family: settings.ui_font.family.clone(),
20805                font_features: settings.ui_font.features.clone(),
20806                font_fallbacks: settings.ui_font.fallbacks.clone(),
20807                font_size: rems(0.875).into(),
20808                font_weight: settings.ui_font.weight,
20809                line_height: relative(settings.buffer_line_height.value()),
20810                ..Default::default()
20811            },
20812            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20813                color: cx.theme().colors().editor_foreground,
20814                font_family: settings.buffer_font.family.clone(),
20815                font_features: settings.buffer_font.features.clone(),
20816                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20817                font_size: settings.buffer_font_size(cx).into(),
20818                font_weight: settings.buffer_font.weight,
20819                line_height: relative(settings.buffer_line_height.value()),
20820                ..Default::default()
20821            },
20822        };
20823        if let Some(text_style_refinement) = &self.text_style_refinement {
20824            text_style.refine(text_style_refinement)
20825        }
20826
20827        let background = match self.mode {
20828            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20829            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20830            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20831            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20832        };
20833
20834        EditorElement::new(
20835            &cx.entity(),
20836            EditorStyle {
20837                background,
20838                local_player: cx.theme().players().local(),
20839                text: text_style,
20840                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20841                syntax: cx.theme().syntax().clone(),
20842                status: cx.theme().status().clone(),
20843                inlay_hints_style: make_inlay_hints_style(cx),
20844                inline_completion_styles: make_suggestion_styles(cx),
20845                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20846                show_underlines: !self.mode.is_minimap(),
20847            },
20848        )
20849    }
20850}
20851
20852impl EntityInputHandler for Editor {
20853    fn text_for_range(
20854        &mut self,
20855        range_utf16: Range<usize>,
20856        adjusted_range: &mut Option<Range<usize>>,
20857        _: &mut Window,
20858        cx: &mut Context<Self>,
20859    ) -> Option<String> {
20860        let snapshot = self.buffer.read(cx).read(cx);
20861        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20862        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20863        if (start.0..end.0) != range_utf16 {
20864            adjusted_range.replace(start.0..end.0);
20865        }
20866        Some(snapshot.text_for_range(start..end).collect())
20867    }
20868
20869    fn selected_text_range(
20870        &mut self,
20871        ignore_disabled_input: bool,
20872        _: &mut Window,
20873        cx: &mut Context<Self>,
20874    ) -> Option<UTF16Selection> {
20875        // Prevent the IME menu from appearing when holding down an alphabetic key
20876        // while input is disabled.
20877        if !ignore_disabled_input && !self.input_enabled {
20878            return None;
20879        }
20880
20881        let selection = self.selections.newest::<OffsetUtf16>(cx);
20882        let range = selection.range();
20883
20884        Some(UTF16Selection {
20885            range: range.start.0..range.end.0,
20886            reversed: selection.reversed,
20887        })
20888    }
20889
20890    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20891        let snapshot = self.buffer.read(cx).read(cx);
20892        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20893        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20894    }
20895
20896    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20897        self.clear_highlights::<InputComposition>(cx);
20898        self.ime_transaction.take();
20899    }
20900
20901    fn replace_text_in_range(
20902        &mut self,
20903        range_utf16: Option<Range<usize>>,
20904        text: &str,
20905        window: &mut Window,
20906        cx: &mut Context<Self>,
20907    ) {
20908        if !self.input_enabled {
20909            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20910            return;
20911        }
20912
20913        self.transact(window, cx, |this, window, cx| {
20914            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20915                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20916                Some(this.selection_replacement_ranges(range_utf16, cx))
20917            } else {
20918                this.marked_text_ranges(cx)
20919            };
20920
20921            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20922                let newest_selection_id = this.selections.newest_anchor().id;
20923                this.selections
20924                    .all::<OffsetUtf16>(cx)
20925                    .iter()
20926                    .zip(ranges_to_replace.iter())
20927                    .find_map(|(selection, range)| {
20928                        if selection.id == newest_selection_id {
20929                            Some(
20930                                (range.start.0 as isize - selection.head().0 as isize)
20931                                    ..(range.end.0 as isize - selection.head().0 as isize),
20932                            )
20933                        } else {
20934                            None
20935                        }
20936                    })
20937            });
20938
20939            cx.emit(EditorEvent::InputHandled {
20940                utf16_range_to_replace: range_to_replace,
20941                text: text.into(),
20942            });
20943
20944            if let Some(new_selected_ranges) = new_selected_ranges {
20945                this.change_selections(None, window, cx, |selections| {
20946                    selections.select_ranges(new_selected_ranges)
20947                });
20948                this.backspace(&Default::default(), window, cx);
20949            }
20950
20951            this.handle_input(text, window, cx);
20952        });
20953
20954        if let Some(transaction) = self.ime_transaction {
20955            self.buffer.update(cx, |buffer, cx| {
20956                buffer.group_until_transaction(transaction, cx);
20957            });
20958        }
20959
20960        self.unmark_text(window, cx);
20961    }
20962
20963    fn replace_and_mark_text_in_range(
20964        &mut self,
20965        range_utf16: Option<Range<usize>>,
20966        text: &str,
20967        new_selected_range_utf16: Option<Range<usize>>,
20968        window: &mut Window,
20969        cx: &mut Context<Self>,
20970    ) {
20971        if !self.input_enabled {
20972            return;
20973        }
20974
20975        let transaction = self.transact(window, cx, |this, window, cx| {
20976            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20977                let snapshot = this.buffer.read(cx).read(cx);
20978                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20979                    for marked_range in &mut marked_ranges {
20980                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20981                        marked_range.start.0 += relative_range_utf16.start;
20982                        marked_range.start =
20983                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20984                        marked_range.end =
20985                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20986                    }
20987                }
20988                Some(marked_ranges)
20989            } else if let Some(range_utf16) = range_utf16 {
20990                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20991                Some(this.selection_replacement_ranges(range_utf16, cx))
20992            } else {
20993                None
20994            };
20995
20996            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20997                let newest_selection_id = this.selections.newest_anchor().id;
20998                this.selections
20999                    .all::<OffsetUtf16>(cx)
21000                    .iter()
21001                    .zip(ranges_to_replace.iter())
21002                    .find_map(|(selection, range)| {
21003                        if selection.id == newest_selection_id {
21004                            Some(
21005                                (range.start.0 as isize - selection.head().0 as isize)
21006                                    ..(range.end.0 as isize - selection.head().0 as isize),
21007                            )
21008                        } else {
21009                            None
21010                        }
21011                    })
21012            });
21013
21014            cx.emit(EditorEvent::InputHandled {
21015                utf16_range_to_replace: range_to_replace,
21016                text: text.into(),
21017            });
21018
21019            if let Some(ranges) = ranges_to_replace {
21020                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21021            }
21022
21023            let marked_ranges = {
21024                let snapshot = this.buffer.read(cx).read(cx);
21025                this.selections
21026                    .disjoint_anchors()
21027                    .iter()
21028                    .map(|selection| {
21029                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21030                    })
21031                    .collect::<Vec<_>>()
21032            };
21033
21034            if text.is_empty() {
21035                this.unmark_text(window, cx);
21036            } else {
21037                this.highlight_text::<InputComposition>(
21038                    marked_ranges.clone(),
21039                    HighlightStyle {
21040                        underline: Some(UnderlineStyle {
21041                            thickness: px(1.),
21042                            color: None,
21043                            wavy: false,
21044                        }),
21045                        ..Default::default()
21046                    },
21047                    cx,
21048                );
21049            }
21050
21051            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21052            let use_autoclose = this.use_autoclose;
21053            let use_auto_surround = this.use_auto_surround;
21054            this.set_use_autoclose(false);
21055            this.set_use_auto_surround(false);
21056            this.handle_input(text, window, cx);
21057            this.set_use_autoclose(use_autoclose);
21058            this.set_use_auto_surround(use_auto_surround);
21059
21060            if let Some(new_selected_range) = new_selected_range_utf16 {
21061                let snapshot = this.buffer.read(cx).read(cx);
21062                let new_selected_ranges = marked_ranges
21063                    .into_iter()
21064                    .map(|marked_range| {
21065                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21066                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21067                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21068                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21069                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21070                    })
21071                    .collect::<Vec<_>>();
21072
21073                drop(snapshot);
21074                this.change_selections(None, window, cx, |selections| {
21075                    selections.select_ranges(new_selected_ranges)
21076                });
21077            }
21078        });
21079
21080        self.ime_transaction = self.ime_transaction.or(transaction);
21081        if let Some(transaction) = self.ime_transaction {
21082            self.buffer.update(cx, |buffer, cx| {
21083                buffer.group_until_transaction(transaction, cx);
21084            });
21085        }
21086
21087        if self.text_highlights::<InputComposition>(cx).is_none() {
21088            self.ime_transaction.take();
21089        }
21090    }
21091
21092    fn bounds_for_range(
21093        &mut self,
21094        range_utf16: Range<usize>,
21095        element_bounds: gpui::Bounds<Pixels>,
21096        window: &mut Window,
21097        cx: &mut Context<Self>,
21098    ) -> Option<gpui::Bounds<Pixels>> {
21099        let text_layout_details = self.text_layout_details(window);
21100        let gpui::Size {
21101            width: em_width,
21102            height: line_height,
21103        } = self.character_size(window);
21104
21105        let snapshot = self.snapshot(window, cx);
21106        let scroll_position = snapshot.scroll_position();
21107        let scroll_left = scroll_position.x * em_width;
21108
21109        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21110        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21111            + self.gutter_dimensions.width
21112            + self.gutter_dimensions.margin;
21113        let y = line_height * (start.row().as_f32() - scroll_position.y);
21114
21115        Some(Bounds {
21116            origin: element_bounds.origin + point(x, y),
21117            size: size(em_width, line_height),
21118        })
21119    }
21120
21121    fn character_index_for_point(
21122        &mut self,
21123        point: gpui::Point<Pixels>,
21124        _window: &mut Window,
21125        _cx: &mut Context<Self>,
21126    ) -> Option<usize> {
21127        let position_map = self.last_position_map.as_ref()?;
21128        if !position_map.text_hitbox.contains(&point) {
21129            return None;
21130        }
21131        let display_point = position_map.point_for_position(point).previous_valid;
21132        let anchor = position_map
21133            .snapshot
21134            .display_point_to_anchor(display_point, Bias::Left);
21135        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21136        Some(utf16_offset.0)
21137    }
21138}
21139
21140trait SelectionExt {
21141    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21142    fn spanned_rows(
21143        &self,
21144        include_end_if_at_line_start: bool,
21145        map: &DisplaySnapshot,
21146    ) -> Range<MultiBufferRow>;
21147}
21148
21149impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21150    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21151        let start = self
21152            .start
21153            .to_point(&map.buffer_snapshot)
21154            .to_display_point(map);
21155        let end = self
21156            .end
21157            .to_point(&map.buffer_snapshot)
21158            .to_display_point(map);
21159        if self.reversed {
21160            end..start
21161        } else {
21162            start..end
21163        }
21164    }
21165
21166    fn spanned_rows(
21167        &self,
21168        include_end_if_at_line_start: bool,
21169        map: &DisplaySnapshot,
21170    ) -> Range<MultiBufferRow> {
21171        let start = self.start.to_point(&map.buffer_snapshot);
21172        let mut end = self.end.to_point(&map.buffer_snapshot);
21173        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21174            end.row -= 1;
21175        }
21176
21177        let buffer_start = map.prev_line_boundary(start).0;
21178        let buffer_end = map.next_line_boundary(end).0;
21179        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21180    }
21181}
21182
21183impl<T: InvalidationRegion> InvalidationStack<T> {
21184    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21185    where
21186        S: Clone + ToOffset,
21187    {
21188        while let Some(region) = self.last() {
21189            let all_selections_inside_invalidation_ranges =
21190                if selections.len() == region.ranges().len() {
21191                    selections
21192                        .iter()
21193                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21194                        .all(|(selection, invalidation_range)| {
21195                            let head = selection.head().to_offset(buffer);
21196                            invalidation_range.start <= head && invalidation_range.end >= head
21197                        })
21198                } else {
21199                    false
21200                };
21201
21202            if all_selections_inside_invalidation_ranges {
21203                break;
21204            } else {
21205                self.pop();
21206            }
21207        }
21208    }
21209}
21210
21211impl<T> Default for InvalidationStack<T> {
21212    fn default() -> Self {
21213        Self(Default::default())
21214    }
21215}
21216
21217impl<T> Deref for InvalidationStack<T> {
21218    type Target = Vec<T>;
21219
21220    fn deref(&self) -> &Self::Target {
21221        &self.0
21222    }
21223}
21224
21225impl<T> DerefMut for InvalidationStack<T> {
21226    fn deref_mut(&mut self) -> &mut Self::Target {
21227        &mut self.0
21228    }
21229}
21230
21231impl InvalidationRegion for SnippetState {
21232    fn ranges(&self) -> &[Range<Anchor>] {
21233        &self.ranges[self.active_index]
21234    }
21235}
21236
21237fn inline_completion_edit_text(
21238    current_snapshot: &BufferSnapshot,
21239    edits: &[(Range<Anchor>, String)],
21240    edit_preview: &EditPreview,
21241    include_deletions: bool,
21242    cx: &App,
21243) -> HighlightedText {
21244    let edits = edits
21245        .iter()
21246        .map(|(anchor, text)| {
21247            (
21248                anchor.start.text_anchor..anchor.end.text_anchor,
21249                text.clone(),
21250            )
21251        })
21252        .collect::<Vec<_>>();
21253
21254    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21255}
21256
21257pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21258    match severity {
21259        lsp::DiagnosticSeverity::ERROR => colors.error,
21260        lsp::DiagnosticSeverity::WARNING => colors.warning,
21261        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21262        lsp::DiagnosticSeverity::HINT => colors.info,
21263        _ => colors.ignored,
21264    }
21265}
21266
21267pub fn styled_runs_for_code_label<'a>(
21268    label: &'a CodeLabel,
21269    syntax_theme: &'a theme::SyntaxTheme,
21270) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21271    let fade_out = HighlightStyle {
21272        fade_out: Some(0.35),
21273        ..Default::default()
21274    };
21275
21276    let mut prev_end = label.filter_range.end;
21277    label
21278        .runs
21279        .iter()
21280        .enumerate()
21281        .flat_map(move |(ix, (range, highlight_id))| {
21282            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21283                style
21284            } else {
21285                return Default::default();
21286            };
21287            let mut muted_style = style;
21288            muted_style.highlight(fade_out);
21289
21290            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21291            if range.start >= label.filter_range.end {
21292                if range.start > prev_end {
21293                    runs.push((prev_end..range.start, fade_out));
21294                }
21295                runs.push((range.clone(), muted_style));
21296            } else if range.end <= label.filter_range.end {
21297                runs.push((range.clone(), style));
21298            } else {
21299                runs.push((range.start..label.filter_range.end, style));
21300                runs.push((label.filter_range.end..range.end, muted_style));
21301            }
21302            prev_end = cmp::max(prev_end, range.end);
21303
21304            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21305                runs.push((prev_end..label.text.len(), fade_out));
21306            }
21307
21308            runs
21309        })
21310}
21311
21312pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21313    let mut prev_index = 0;
21314    let mut prev_codepoint: Option<char> = None;
21315    text.char_indices()
21316        .chain([(text.len(), '\0')])
21317        .filter_map(move |(index, codepoint)| {
21318            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21319            let is_boundary = index == text.len()
21320                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21321                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21322            if is_boundary {
21323                let chunk = &text[prev_index..index];
21324                prev_index = index;
21325                Some(chunk)
21326            } else {
21327                None
21328            }
21329        })
21330}
21331
21332pub trait RangeToAnchorExt: Sized {
21333    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21334
21335    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21336        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21337        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21338    }
21339}
21340
21341impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21342    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21343        let start_offset = self.start.to_offset(snapshot);
21344        let end_offset = self.end.to_offset(snapshot);
21345        if start_offset == end_offset {
21346            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21347        } else {
21348            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21349        }
21350    }
21351}
21352
21353pub trait RowExt {
21354    fn as_f32(&self) -> f32;
21355
21356    fn next_row(&self) -> Self;
21357
21358    fn previous_row(&self) -> Self;
21359
21360    fn minus(&self, other: Self) -> u32;
21361}
21362
21363impl RowExt for DisplayRow {
21364    fn as_f32(&self) -> f32 {
21365        self.0 as f32
21366    }
21367
21368    fn next_row(&self) -> Self {
21369        Self(self.0 + 1)
21370    }
21371
21372    fn previous_row(&self) -> Self {
21373        Self(self.0.saturating_sub(1))
21374    }
21375
21376    fn minus(&self, other: Self) -> u32 {
21377        self.0 - other.0
21378    }
21379}
21380
21381impl RowExt for MultiBufferRow {
21382    fn as_f32(&self) -> f32 {
21383        self.0 as f32
21384    }
21385
21386    fn next_row(&self) -> Self {
21387        Self(self.0 + 1)
21388    }
21389
21390    fn previous_row(&self) -> Self {
21391        Self(self.0.saturating_sub(1))
21392    }
21393
21394    fn minus(&self, other: Self) -> u32 {
21395        self.0 - other.0
21396    }
21397}
21398
21399trait RowRangeExt {
21400    type Row;
21401
21402    fn len(&self) -> usize;
21403
21404    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21405}
21406
21407impl RowRangeExt for Range<MultiBufferRow> {
21408    type Row = MultiBufferRow;
21409
21410    fn len(&self) -> usize {
21411        (self.end.0 - self.start.0) as usize
21412    }
21413
21414    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21415        (self.start.0..self.end.0).map(MultiBufferRow)
21416    }
21417}
21418
21419impl RowRangeExt for Range<DisplayRow> {
21420    type Row = DisplayRow;
21421
21422    fn len(&self) -> usize {
21423        (self.end.0 - self.start.0) as usize
21424    }
21425
21426    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21427        (self.start.0..self.end.0).map(DisplayRow)
21428    }
21429}
21430
21431/// If select range has more than one line, we
21432/// just point the cursor to range.start.
21433fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21434    if range.start.row == range.end.row {
21435        range
21436    } else {
21437        range.start..range.start
21438    }
21439}
21440pub struct KillRing(ClipboardItem);
21441impl Global for KillRing {}
21442
21443const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21444
21445enum BreakpointPromptEditAction {
21446    Log,
21447    Condition,
21448    HitCondition,
21449}
21450
21451struct BreakpointPromptEditor {
21452    pub(crate) prompt: Entity<Editor>,
21453    editor: WeakEntity<Editor>,
21454    breakpoint_anchor: Anchor,
21455    breakpoint: Breakpoint,
21456    edit_action: BreakpointPromptEditAction,
21457    block_ids: HashSet<CustomBlockId>,
21458    editor_margins: Arc<Mutex<EditorMargins>>,
21459    _subscriptions: Vec<Subscription>,
21460}
21461
21462impl BreakpointPromptEditor {
21463    const MAX_LINES: u8 = 4;
21464
21465    fn new(
21466        editor: WeakEntity<Editor>,
21467        breakpoint_anchor: Anchor,
21468        breakpoint: Breakpoint,
21469        edit_action: BreakpointPromptEditAction,
21470        window: &mut Window,
21471        cx: &mut Context<Self>,
21472    ) -> Self {
21473        let base_text = match edit_action {
21474            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21475            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21476            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21477        }
21478        .map(|msg| msg.to_string())
21479        .unwrap_or_default();
21480
21481        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21482        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21483
21484        let prompt = cx.new(|cx| {
21485            let mut prompt = Editor::new(
21486                EditorMode::AutoHeight {
21487                    max_lines: Self::MAX_LINES as usize,
21488                },
21489                buffer,
21490                None,
21491                window,
21492                cx,
21493            );
21494            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21495            prompt.set_show_cursor_when_unfocused(false, cx);
21496            prompt.set_placeholder_text(
21497                match edit_action {
21498                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21499                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21500                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21501                },
21502                cx,
21503            );
21504
21505            prompt
21506        });
21507
21508        Self {
21509            prompt,
21510            editor,
21511            breakpoint_anchor,
21512            breakpoint,
21513            edit_action,
21514            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21515            block_ids: Default::default(),
21516            _subscriptions: vec![],
21517        }
21518    }
21519
21520    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21521        self.block_ids.extend(block_ids)
21522    }
21523
21524    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21525        if let Some(editor) = self.editor.upgrade() {
21526            let message = self
21527                .prompt
21528                .read(cx)
21529                .buffer
21530                .read(cx)
21531                .as_singleton()
21532                .expect("A multi buffer in breakpoint prompt isn't possible")
21533                .read(cx)
21534                .as_rope()
21535                .to_string();
21536
21537            editor.update(cx, |editor, cx| {
21538                editor.edit_breakpoint_at_anchor(
21539                    self.breakpoint_anchor,
21540                    self.breakpoint.clone(),
21541                    match self.edit_action {
21542                        BreakpointPromptEditAction::Log => {
21543                            BreakpointEditAction::EditLogMessage(message.into())
21544                        }
21545                        BreakpointPromptEditAction::Condition => {
21546                            BreakpointEditAction::EditCondition(message.into())
21547                        }
21548                        BreakpointPromptEditAction::HitCondition => {
21549                            BreakpointEditAction::EditHitCondition(message.into())
21550                        }
21551                    },
21552                    cx,
21553                );
21554
21555                editor.remove_blocks(self.block_ids.clone(), None, cx);
21556                cx.focus_self(window);
21557            });
21558        }
21559    }
21560
21561    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21562        self.editor
21563            .update(cx, |editor, cx| {
21564                editor.remove_blocks(self.block_ids.clone(), None, cx);
21565                window.focus(&editor.focus_handle);
21566            })
21567            .log_err();
21568    }
21569
21570    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21571        let settings = ThemeSettings::get_global(cx);
21572        let text_style = TextStyle {
21573            color: if self.prompt.read(cx).read_only(cx) {
21574                cx.theme().colors().text_disabled
21575            } else {
21576                cx.theme().colors().text
21577            },
21578            font_family: settings.buffer_font.family.clone(),
21579            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21580            font_size: settings.buffer_font_size(cx).into(),
21581            font_weight: settings.buffer_font.weight,
21582            line_height: relative(settings.buffer_line_height.value()),
21583            ..Default::default()
21584        };
21585        EditorElement::new(
21586            &self.prompt,
21587            EditorStyle {
21588                background: cx.theme().colors().editor_background,
21589                local_player: cx.theme().players().local(),
21590                text: text_style,
21591                ..Default::default()
21592            },
21593        )
21594    }
21595}
21596
21597impl Render for BreakpointPromptEditor {
21598    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21599        let editor_margins = *self.editor_margins.lock();
21600        let gutter_dimensions = editor_margins.gutter;
21601        h_flex()
21602            .key_context("Editor")
21603            .bg(cx.theme().colors().editor_background)
21604            .border_y_1()
21605            .border_color(cx.theme().status().info_border)
21606            .size_full()
21607            .py(window.line_height() / 2.5)
21608            .on_action(cx.listener(Self::confirm))
21609            .on_action(cx.listener(Self::cancel))
21610            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21611            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21612    }
21613}
21614
21615impl Focusable for BreakpointPromptEditor {
21616    fn focus_handle(&self, cx: &App) -> FocusHandle {
21617        self.prompt.focus_handle(cx)
21618    }
21619}
21620
21621fn all_edits_insertions_or_deletions(
21622    edits: &Vec<(Range<Anchor>, String)>,
21623    snapshot: &MultiBufferSnapshot,
21624) -> bool {
21625    let mut all_insertions = true;
21626    let mut all_deletions = true;
21627
21628    for (range, new_text) in edits.iter() {
21629        let range_is_empty = range.to_offset(&snapshot).is_empty();
21630        let text_is_empty = new_text.is_empty();
21631
21632        if range_is_empty != text_is_empty {
21633            if range_is_empty {
21634                all_deletions = false;
21635            } else {
21636                all_insertions = false;
21637            }
21638        } else {
21639            return false;
21640        }
21641
21642        if !all_insertions && !all_deletions {
21643            return false;
21644        }
21645    }
21646    all_insertions || all_deletions
21647}
21648
21649struct MissingEditPredictionKeybindingTooltip;
21650
21651impl Render for MissingEditPredictionKeybindingTooltip {
21652    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21653        ui::tooltip_container(window, cx, |container, _, cx| {
21654            container
21655                .flex_shrink_0()
21656                .max_w_80()
21657                .min_h(rems_from_px(124.))
21658                .justify_between()
21659                .child(
21660                    v_flex()
21661                        .flex_1()
21662                        .text_ui_sm(cx)
21663                        .child(Label::new("Conflict with Accept Keybinding"))
21664                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21665                )
21666                .child(
21667                    h_flex()
21668                        .pb_1()
21669                        .gap_1()
21670                        .items_end()
21671                        .w_full()
21672                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21673                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21674                        }))
21675                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21676                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21677                        })),
21678                )
21679        })
21680    }
21681}
21682
21683#[derive(Debug, Clone, Copy, PartialEq)]
21684pub struct LineHighlight {
21685    pub background: Background,
21686    pub border: Option<gpui::Hsla>,
21687    pub include_gutter: bool,
21688    pub type_id: Option<TypeId>,
21689}
21690
21691fn render_diff_hunk_controls(
21692    row: u32,
21693    status: &DiffHunkStatus,
21694    hunk_range: Range<Anchor>,
21695    is_created_file: bool,
21696    line_height: Pixels,
21697    editor: &Entity<Editor>,
21698    _window: &mut Window,
21699    cx: &mut App,
21700) -> AnyElement {
21701    h_flex()
21702        .h(line_height)
21703        .mr_1()
21704        .gap_1()
21705        .px_0p5()
21706        .pb_1()
21707        .border_x_1()
21708        .border_b_1()
21709        .border_color(cx.theme().colors().border_variant)
21710        .rounded_b_lg()
21711        .bg(cx.theme().colors().editor_background)
21712        .gap_1()
21713        .occlude()
21714        .shadow_md()
21715        .child(if status.has_secondary_hunk() {
21716            Button::new(("stage", row as u64), "Stage")
21717                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21718                .tooltip({
21719                    let focus_handle = editor.focus_handle(cx);
21720                    move |window, cx| {
21721                        Tooltip::for_action_in(
21722                            "Stage Hunk",
21723                            &::git::ToggleStaged,
21724                            &focus_handle,
21725                            window,
21726                            cx,
21727                        )
21728                    }
21729                })
21730                .on_click({
21731                    let editor = editor.clone();
21732                    move |_event, _window, cx| {
21733                        editor.update(cx, |editor, cx| {
21734                            editor.stage_or_unstage_diff_hunks(
21735                                true,
21736                                vec![hunk_range.start..hunk_range.start],
21737                                cx,
21738                            );
21739                        });
21740                    }
21741                })
21742        } else {
21743            Button::new(("unstage", row as u64), "Unstage")
21744                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21745                .tooltip({
21746                    let focus_handle = editor.focus_handle(cx);
21747                    move |window, cx| {
21748                        Tooltip::for_action_in(
21749                            "Unstage Hunk",
21750                            &::git::ToggleStaged,
21751                            &focus_handle,
21752                            window,
21753                            cx,
21754                        )
21755                    }
21756                })
21757                .on_click({
21758                    let editor = editor.clone();
21759                    move |_event, _window, cx| {
21760                        editor.update(cx, |editor, cx| {
21761                            editor.stage_or_unstage_diff_hunks(
21762                                false,
21763                                vec![hunk_range.start..hunk_range.start],
21764                                cx,
21765                            );
21766                        });
21767                    }
21768                })
21769        })
21770        .child(
21771            Button::new(("restore", row as u64), "Restore")
21772                .tooltip({
21773                    let focus_handle = editor.focus_handle(cx);
21774                    move |window, cx| {
21775                        Tooltip::for_action_in(
21776                            "Restore Hunk",
21777                            &::git::Restore,
21778                            &focus_handle,
21779                            window,
21780                            cx,
21781                        )
21782                    }
21783                })
21784                .on_click({
21785                    let editor = editor.clone();
21786                    move |_event, window, cx| {
21787                        editor.update(cx, |editor, cx| {
21788                            let snapshot = editor.snapshot(window, cx);
21789                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21790                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21791                        });
21792                    }
21793                })
21794                .disabled(is_created_file),
21795        )
21796        .when(
21797            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21798            |el| {
21799                el.child(
21800                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21801                        .shape(IconButtonShape::Square)
21802                        .icon_size(IconSize::Small)
21803                        // .disabled(!has_multiple_hunks)
21804                        .tooltip({
21805                            let focus_handle = editor.focus_handle(cx);
21806                            move |window, cx| {
21807                                Tooltip::for_action_in(
21808                                    "Next Hunk",
21809                                    &GoToHunk,
21810                                    &focus_handle,
21811                                    window,
21812                                    cx,
21813                                )
21814                            }
21815                        })
21816                        .on_click({
21817                            let editor = editor.clone();
21818                            move |_event, window, cx| {
21819                                editor.update(cx, |editor, cx| {
21820                                    let snapshot = editor.snapshot(window, cx);
21821                                    let position =
21822                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21823                                    editor.go_to_hunk_before_or_after_position(
21824                                        &snapshot,
21825                                        position,
21826                                        Direction::Next,
21827                                        window,
21828                                        cx,
21829                                    );
21830                                    editor.expand_selected_diff_hunks(cx);
21831                                });
21832                            }
21833                        }),
21834                )
21835                .child(
21836                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21837                        .shape(IconButtonShape::Square)
21838                        .icon_size(IconSize::Small)
21839                        // .disabled(!has_multiple_hunks)
21840                        .tooltip({
21841                            let focus_handle = editor.focus_handle(cx);
21842                            move |window, cx| {
21843                                Tooltip::for_action_in(
21844                                    "Previous Hunk",
21845                                    &GoToPreviousHunk,
21846                                    &focus_handle,
21847                                    window,
21848                                    cx,
21849                                )
21850                            }
21851                        })
21852                        .on_click({
21853                            let editor = editor.clone();
21854                            move |_event, window, cx| {
21855                                editor.update(cx, |editor, cx| {
21856                                    let snapshot = editor.snapshot(window, cx);
21857                                    let point =
21858                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21859                                    editor.go_to_hunk_before_or_after_position(
21860                                        &snapshot,
21861                                        point,
21862                                        Direction::Prev,
21863                                        window,
21864                                        cx,
21865                                    );
21866                                    editor.expand_selected_diff_hunks(cx);
21867                                });
21868                            }
21869                        }),
21870                )
21871            },
21872        )
21873        .into_any_element()
21874}