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::{StringMatch, StringMatchCandidate};
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc, wrap_with_prefix};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  257};
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled(bool),
  720}
  721
  722impl MinimapVisibility {
  723    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  724        if mode.is_full() {
  725            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  726        } else {
  727            Self::Disabled
  728        }
  729    }
  730
  731    fn disabled(&self) -> bool {
  732        match *self {
  733            Self::Disabled => true,
  734            _ => false,
  735        }
  736    }
  737
  738    fn visible(&self) -> bool {
  739        match *self {
  740            Self::Enabled(visible) => visible,
  741            _ => false,
  742        }
  743    }
  744
  745    fn toggle_visibility(&self) -> Self {
  746        match *self {
  747            Self::Enabled(visible) => Self::Enabled(!visible),
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751}
  752
  753#[derive(Clone, Debug)]
  754struct RunnableTasks {
  755    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  756    offset: multi_buffer::Anchor,
  757    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  758    column: u32,
  759    // Values of all named captures, including those starting with '_'
  760    extra_variables: HashMap<String, String>,
  761    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  762    context_range: Range<BufferOffset>,
  763}
  764
  765impl RunnableTasks {
  766    fn resolve<'a>(
  767        &'a self,
  768        cx: &'a task::TaskContext,
  769    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  770        self.templates.iter().filter_map(|(kind, template)| {
  771            template
  772                .resolve_task(&kind.to_id_base(), cx)
  773                .map(|task| (kind.clone(), task))
  774        })
  775    }
  776}
  777
  778#[derive(Clone)]
  779pub struct ResolvedTasks {
  780    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  781    position: Anchor,
  782}
  783
  784#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  785struct BufferOffset(usize);
  786
  787// Addons allow storing per-editor state in other crates (e.g. Vim)
  788pub trait Addon: 'static {
  789    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  790
  791    fn render_buffer_header_controls(
  792        &self,
  793        _: &ExcerptInfo,
  794        _: &Window,
  795        _: &App,
  796    ) -> Option<AnyElement> {
  797        None
  798    }
  799
  800    fn to_any(&self) -> &dyn std::any::Any;
  801
  802    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  803        None
  804    }
  805}
  806
  807/// A set of caret positions, registered when the editor was edited.
  808pub struct ChangeList {
  809    changes: Vec<Vec<Anchor>>,
  810    /// Currently "selected" change.
  811    position: Option<usize>,
  812}
  813
  814impl ChangeList {
  815    pub fn new() -> Self {
  816        Self {
  817            changes: Vec::new(),
  818            position: None,
  819        }
  820    }
  821
  822    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  823    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  824    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  825        if self.changes.is_empty() {
  826            return None;
  827        }
  828
  829        let prev = self.position.unwrap_or(self.changes.len());
  830        let next = if direction == Direction::Prev {
  831            prev.saturating_sub(count)
  832        } else {
  833            (prev + count).min(self.changes.len() - 1)
  834        };
  835        self.position = Some(next);
  836        self.changes.get(next).map(|anchors| anchors.as_slice())
  837    }
  838
  839    /// Adds a new change to the list, resetting the change list position.
  840    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  841        self.position.take();
  842        if pop_state {
  843            self.changes.pop();
  844        }
  845        self.changes.push(new_positions.clone());
  846    }
  847
  848    pub fn last(&self) -> Option<&[Anchor]> {
  849        self.changes.last().map(|anchors| anchors.as_slice())
  850    }
  851}
  852
  853#[derive(Clone)]
  854struct InlineBlamePopoverState {
  855    scroll_handle: ScrollHandle,
  856    commit_message: Option<ParsedCommitMessage>,
  857    markdown: Entity<Markdown>,
  858}
  859
  860struct InlineBlamePopover {
  861    position: gpui::Point<Pixels>,
  862    show_task: Option<Task<()>>,
  863    hide_task: Option<Task<()>>,
  864    popover_bounds: Option<Bounds<Pixels>>,
  865    popover_state: InlineBlamePopoverState,
  866}
  867
  868/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  869/// a breakpoint on them.
  870#[derive(Clone, Copy, Debug)]
  871struct PhantomBreakpointIndicator {
  872    display_row: DisplayRow,
  873    /// There's a small debounce between hovering over the line and showing the indicator.
  874    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  875    is_active: bool,
  876    collides_with_existing_breakpoint: bool,
  877}
  878/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  879///
  880/// See the [module level documentation](self) for more information.
  881pub struct Editor {
  882    focus_handle: FocusHandle,
  883    last_focused_descendant: Option<WeakFocusHandle>,
  884    /// The text buffer being edited
  885    buffer: Entity<MultiBuffer>,
  886    /// Map of how text in the buffer should be displayed.
  887    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  888    pub display_map: Entity<DisplayMap>,
  889    pub selections: SelectionsCollection,
  890    pub scroll_manager: ScrollManager,
  891    /// When inline assist editors are linked, they all render cursors because
  892    /// typing enters text into each of them, even the ones that aren't focused.
  893    pub(crate) show_cursor_when_unfocused: bool,
  894    columnar_selection_tail: Option<Anchor>,
  895    add_selections_state: Option<AddSelectionsState>,
  896    select_next_state: Option<SelectNextState>,
  897    select_prev_state: Option<SelectNextState>,
  898    selection_history: SelectionHistory,
  899    autoclose_regions: Vec<AutocloseRegion>,
  900    snippet_stack: InvalidationStack<SnippetState>,
  901    select_syntax_node_history: SelectSyntaxNodeHistory,
  902    ime_transaction: Option<TransactionId>,
  903    pub diagnostics_max_severity: DiagnosticSeverity,
  904    active_diagnostics: ActiveDiagnostic,
  905    show_inline_diagnostics: bool,
  906    inline_diagnostics_update: Task<()>,
  907    inline_diagnostics_enabled: bool,
  908    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  909    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  910    hard_wrap: Option<usize>,
  911
  912    // TODO: make this a access method
  913    pub project: Option<Entity<Project>>,
  914    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  915    completion_provider: Option<Rc<dyn CompletionProvider>>,
  916    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  917    blink_manager: Entity<BlinkManager>,
  918    show_cursor_names: bool,
  919    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  920    pub show_local_selections: bool,
  921    mode: EditorMode,
  922    show_breadcrumbs: bool,
  923    show_gutter: bool,
  924    show_scrollbars: bool,
  925    minimap_visibility: MinimapVisibility,
  926    offset_content: bool,
  927    disable_expand_excerpt_buttons: bool,
  928    show_line_numbers: Option<bool>,
  929    use_relative_line_numbers: Option<bool>,
  930    show_git_diff_gutter: Option<bool>,
  931    show_code_actions: Option<bool>,
  932    show_runnables: Option<bool>,
  933    show_breakpoints: Option<bool>,
  934    show_wrap_guides: Option<bool>,
  935    show_indent_guides: Option<bool>,
  936    placeholder_text: Option<Arc<str>>,
  937    highlight_order: usize,
  938    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  939    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  940    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  941    scrollbar_marker_state: ScrollbarMarkerState,
  942    active_indent_guides_state: ActiveIndentGuidesState,
  943    nav_history: Option<ItemNavHistory>,
  944    context_menu: RefCell<Option<CodeContextMenu>>,
  945    context_menu_options: Option<ContextMenuOptions>,
  946    mouse_context_menu: Option<MouseContextMenu>,
  947    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  948    inline_blame_popover: Option<InlineBlamePopover>,
  949    signature_help_state: SignatureHelpState,
  950    auto_signature_help: Option<bool>,
  951    find_all_references_task_sources: Vec<Anchor>,
  952    next_completion_id: CompletionId,
  953    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  954    code_actions_task: Option<Task<Result<()>>>,
  955    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  957    document_highlights_task: Option<Task<()>>,
  958    linked_editing_range_task: Option<Task<Option<()>>>,
  959    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  960    pending_rename: Option<RenameState>,
  961    searchable: bool,
  962    cursor_shape: CursorShape,
  963    current_line_highlight: Option<CurrentLineHighlight>,
  964    collapse_matches: bool,
  965    autoindent_mode: Option<AutoindentMode>,
  966    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  967    input_enabled: bool,
  968    use_modal_editing: bool,
  969    read_only: bool,
  970    leader_id: Option<CollaboratorId>,
  971    remote_id: Option<ViewId>,
  972    pub hover_state: HoverState,
  973    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  974    gutter_hovered: bool,
  975    hovered_link_state: Option<HoveredLinkState>,
  976    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  977    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  978    active_inline_completion: Option<InlineCompletionState>,
  979    /// Used to prevent flickering as the user types while the menu is open
  980    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  981    edit_prediction_settings: EditPredictionSettings,
  982    inline_completions_hidden_for_vim_mode: bool,
  983    show_inline_completions_override: Option<bool>,
  984    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  985    edit_prediction_preview: EditPredictionPreview,
  986    edit_prediction_indent_conflict: bool,
  987    edit_prediction_requires_modifier_in_indent_conflict: bool,
  988    inlay_hint_cache: InlayHintCache,
  989    next_inlay_id: usize,
  990    _subscriptions: Vec<Subscription>,
  991    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  992    gutter_dimensions: GutterDimensions,
  993    style: Option<EditorStyle>,
  994    text_style_refinement: Option<TextStyleRefinement>,
  995    next_editor_action_id: EditorActionId,
  996    editor_actions:
  997        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  998    use_autoclose: bool,
  999    use_auto_surround: bool,
 1000    auto_replace_emoji_shortcode: bool,
 1001    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1002    show_git_blame_gutter: bool,
 1003    show_git_blame_inline: bool,
 1004    show_git_blame_inline_delay_task: Option<Task<()>>,
 1005    git_blame_inline_enabled: bool,
 1006    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1007    serialize_dirty_buffers: bool,
 1008    show_selection_menu: Option<bool>,
 1009    blame: Option<Entity<GitBlame>>,
 1010    blame_subscription: Option<Subscription>,
 1011    custom_context_menu: Option<
 1012        Box<
 1013            dyn 'static
 1014                + Fn(
 1015                    &mut Self,
 1016                    DisplayPoint,
 1017                    &mut Window,
 1018                    &mut Context<Self>,
 1019                ) -> Option<Entity<ui::ContextMenu>>,
 1020        >,
 1021    >,
 1022    last_bounds: Option<Bounds<Pixels>>,
 1023    last_position_map: Option<Rc<PositionMap>>,
 1024    expect_bounds_change: Option<Bounds<Pixels>>,
 1025    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1026    tasks_update_task: Option<Task<()>>,
 1027    breakpoint_store: Option<Entity<BreakpointStore>>,
 1028    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1029    in_project_search: bool,
 1030    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1031    breadcrumb_header: Option<String>,
 1032    focused_block: Option<FocusedBlock>,
 1033    next_scroll_position: NextScrollCursorCenterTopBottom,
 1034    addons: HashMap<TypeId, Box<dyn Addon>>,
 1035    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1036    load_diff_task: Option<Shared<Task<()>>>,
 1037    /// Whether we are temporarily displaying a diff other than git's
 1038    temporary_diff_override: bool,
 1039    selection_mark_mode: bool,
 1040    toggle_fold_multiple_buffers: Task<()>,
 1041    _scroll_cursor_center_top_bottom_task: Task<()>,
 1042    serialize_selections: Task<()>,
 1043    serialize_folds: Task<()>,
 1044    mouse_cursor_hidden: bool,
 1045    minimap: Option<Entity<Self>>,
 1046    hide_mouse_mode: HideMouseMode,
 1047    pub change_list: ChangeList,
 1048    inline_value_cache: InlineValueCache,
 1049}
 1050
 1051#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1052enum NextScrollCursorCenterTopBottom {
 1053    #[default]
 1054    Center,
 1055    Top,
 1056    Bottom,
 1057}
 1058
 1059impl NextScrollCursorCenterTopBottom {
 1060    fn next(&self) -> Self {
 1061        match self {
 1062            Self::Center => Self::Top,
 1063            Self::Top => Self::Bottom,
 1064            Self::Bottom => Self::Center,
 1065        }
 1066    }
 1067}
 1068
 1069#[derive(Clone)]
 1070pub struct EditorSnapshot {
 1071    pub mode: EditorMode,
 1072    show_gutter: bool,
 1073    show_line_numbers: Option<bool>,
 1074    show_git_diff_gutter: Option<bool>,
 1075    show_code_actions: Option<bool>,
 1076    show_runnables: Option<bool>,
 1077    show_breakpoints: Option<bool>,
 1078    git_blame_gutter_max_author_length: Option<usize>,
 1079    pub display_snapshot: DisplaySnapshot,
 1080    pub placeholder_text: Option<Arc<str>>,
 1081    is_focused: bool,
 1082    scroll_anchor: ScrollAnchor,
 1083    ongoing_scroll: OngoingScroll,
 1084    current_line_highlight: CurrentLineHighlight,
 1085    gutter_hovered: bool,
 1086}
 1087
 1088#[derive(Default, Debug, Clone, Copy)]
 1089pub struct GutterDimensions {
 1090    pub left_padding: Pixels,
 1091    pub right_padding: Pixels,
 1092    pub width: Pixels,
 1093    pub margin: Pixels,
 1094    pub git_blame_entries_width: Option<Pixels>,
 1095}
 1096
 1097impl GutterDimensions {
 1098    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1099        Self {
 1100            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1101            ..Default::default()
 1102        }
 1103    }
 1104
 1105    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1106        -cx.text_system().descent(font_id, font_size)
 1107    }
 1108    /// The full width of the space taken up by the gutter.
 1109    pub fn full_width(&self) -> Pixels {
 1110        self.margin + self.width
 1111    }
 1112
 1113    /// The width of the space reserved for the fold indicators,
 1114    /// use alongside 'justify_end' and `gutter_width` to
 1115    /// right align content with the line numbers
 1116    pub fn fold_area_width(&self) -> Pixels {
 1117        self.margin + self.right_padding
 1118    }
 1119}
 1120
 1121#[derive(Debug)]
 1122pub struct RemoteSelection {
 1123    pub replica_id: ReplicaId,
 1124    pub selection: Selection<Anchor>,
 1125    pub cursor_shape: CursorShape,
 1126    pub collaborator_id: CollaboratorId,
 1127    pub line_mode: bool,
 1128    pub user_name: Option<SharedString>,
 1129    pub color: PlayerColor,
 1130}
 1131
 1132#[derive(Clone, Debug)]
 1133struct SelectionHistoryEntry {
 1134    selections: Arc<[Selection<Anchor>]>,
 1135    select_next_state: Option<SelectNextState>,
 1136    select_prev_state: Option<SelectNextState>,
 1137    add_selections_state: Option<AddSelectionsState>,
 1138}
 1139
 1140enum SelectionHistoryMode {
 1141    Normal,
 1142    Undoing,
 1143    Redoing,
 1144}
 1145
 1146#[derive(Clone, PartialEq, Eq, Hash)]
 1147struct HoveredCursor {
 1148    replica_id: u16,
 1149    selection_id: usize,
 1150}
 1151
 1152impl Default for SelectionHistoryMode {
 1153    fn default() -> Self {
 1154        Self::Normal
 1155    }
 1156}
 1157
 1158#[derive(Default)]
 1159struct SelectionHistory {
 1160    #[allow(clippy::type_complexity)]
 1161    selections_by_transaction:
 1162        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1163    mode: SelectionHistoryMode,
 1164    undo_stack: VecDeque<SelectionHistoryEntry>,
 1165    redo_stack: VecDeque<SelectionHistoryEntry>,
 1166}
 1167
 1168impl SelectionHistory {
 1169    fn insert_transaction(
 1170        &mut self,
 1171        transaction_id: TransactionId,
 1172        selections: Arc<[Selection<Anchor>]>,
 1173    ) {
 1174        self.selections_by_transaction
 1175            .insert(transaction_id, (selections, None));
 1176    }
 1177
 1178    #[allow(clippy::type_complexity)]
 1179    fn transaction(
 1180        &self,
 1181        transaction_id: TransactionId,
 1182    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1183        self.selections_by_transaction.get(&transaction_id)
 1184    }
 1185
 1186    #[allow(clippy::type_complexity)]
 1187    fn transaction_mut(
 1188        &mut self,
 1189        transaction_id: TransactionId,
 1190    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1191        self.selections_by_transaction.get_mut(&transaction_id)
 1192    }
 1193
 1194    fn push(&mut self, entry: SelectionHistoryEntry) {
 1195        if !entry.selections.is_empty() {
 1196            match self.mode {
 1197                SelectionHistoryMode::Normal => {
 1198                    self.push_undo(entry);
 1199                    self.redo_stack.clear();
 1200                }
 1201                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1202                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1203            }
 1204        }
 1205    }
 1206
 1207    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1208        if self
 1209            .undo_stack
 1210            .back()
 1211            .map_or(true, |e| e.selections != entry.selections)
 1212        {
 1213            self.undo_stack.push_back(entry);
 1214            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1215                self.undo_stack.pop_front();
 1216            }
 1217        }
 1218    }
 1219
 1220    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1221        if self
 1222            .redo_stack
 1223            .back()
 1224            .map_or(true, |e| e.selections != entry.selections)
 1225        {
 1226            self.redo_stack.push_back(entry);
 1227            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1228                self.redo_stack.pop_front();
 1229            }
 1230        }
 1231    }
 1232}
 1233
 1234#[derive(Clone, Copy)]
 1235pub struct RowHighlightOptions {
 1236    pub autoscroll: bool,
 1237    pub include_gutter: bool,
 1238}
 1239
 1240impl Default for RowHighlightOptions {
 1241    fn default() -> Self {
 1242        Self {
 1243            autoscroll: Default::default(),
 1244            include_gutter: true,
 1245        }
 1246    }
 1247}
 1248
 1249struct RowHighlight {
 1250    index: usize,
 1251    range: Range<Anchor>,
 1252    color: Hsla,
 1253    options: RowHighlightOptions,
 1254    type_id: TypeId,
 1255}
 1256
 1257#[derive(Clone, Debug)]
 1258struct AddSelectionsState {
 1259    above: bool,
 1260    stack: Vec<usize>,
 1261}
 1262
 1263#[derive(Clone)]
 1264struct SelectNextState {
 1265    query: AhoCorasick,
 1266    wordwise: bool,
 1267    done: bool,
 1268}
 1269
 1270impl std::fmt::Debug for SelectNextState {
 1271    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1272        f.debug_struct(std::any::type_name::<Self>())
 1273            .field("wordwise", &self.wordwise)
 1274            .field("done", &self.done)
 1275            .finish()
 1276    }
 1277}
 1278
 1279#[derive(Debug)]
 1280struct AutocloseRegion {
 1281    selection_id: usize,
 1282    range: Range<Anchor>,
 1283    pair: BracketPair,
 1284}
 1285
 1286#[derive(Debug)]
 1287struct SnippetState {
 1288    ranges: Vec<Vec<Range<Anchor>>>,
 1289    active_index: usize,
 1290    choices: Vec<Option<Vec<String>>>,
 1291}
 1292
 1293#[doc(hidden)]
 1294pub struct RenameState {
 1295    pub range: Range<Anchor>,
 1296    pub old_name: Arc<str>,
 1297    pub editor: Entity<Editor>,
 1298    block_id: CustomBlockId,
 1299}
 1300
 1301struct InvalidationStack<T>(Vec<T>);
 1302
 1303struct RegisteredInlineCompletionProvider {
 1304    provider: Arc<dyn InlineCompletionProviderHandle>,
 1305    _subscription: Subscription,
 1306}
 1307
 1308#[derive(Debug, PartialEq, Eq)]
 1309pub struct ActiveDiagnosticGroup {
 1310    pub active_range: Range<Anchor>,
 1311    pub active_message: String,
 1312    pub group_id: usize,
 1313    pub blocks: HashSet<CustomBlockId>,
 1314}
 1315
 1316#[derive(Debug, PartialEq, Eq)]
 1317
 1318pub(crate) enum ActiveDiagnostic {
 1319    None,
 1320    All,
 1321    Group(ActiveDiagnosticGroup),
 1322}
 1323
 1324#[derive(Serialize, Deserialize, Clone, Debug)]
 1325pub struct ClipboardSelection {
 1326    /// The number of bytes in this selection.
 1327    pub len: usize,
 1328    /// Whether this was a full-line selection.
 1329    pub is_entire_line: bool,
 1330    /// The indentation of the first line when this content was originally copied.
 1331    pub first_line_indent: u32,
 1332}
 1333
 1334// selections, scroll behavior, was newest selection reversed
 1335type SelectSyntaxNodeHistoryState = (
 1336    Box<[Selection<usize>]>,
 1337    SelectSyntaxNodeScrollBehavior,
 1338    bool,
 1339);
 1340
 1341#[derive(Default)]
 1342struct SelectSyntaxNodeHistory {
 1343    stack: Vec<SelectSyntaxNodeHistoryState>,
 1344    // disable temporarily to allow changing selections without losing the stack
 1345    pub disable_clearing: bool,
 1346}
 1347
 1348impl SelectSyntaxNodeHistory {
 1349    pub fn try_clear(&mut self) {
 1350        if !self.disable_clearing {
 1351            self.stack.clear();
 1352        }
 1353    }
 1354
 1355    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1356        self.stack.push(selection);
 1357    }
 1358
 1359    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1360        self.stack.pop()
 1361    }
 1362}
 1363
 1364enum SelectSyntaxNodeScrollBehavior {
 1365    CursorTop,
 1366    FitSelection,
 1367    CursorBottom,
 1368}
 1369
 1370#[derive(Debug)]
 1371pub(crate) struct NavigationData {
 1372    cursor_anchor: Anchor,
 1373    cursor_position: Point,
 1374    scroll_anchor: ScrollAnchor,
 1375    scroll_top_row: u32,
 1376}
 1377
 1378#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1379pub enum GotoDefinitionKind {
 1380    Symbol,
 1381    Declaration,
 1382    Type,
 1383    Implementation,
 1384}
 1385
 1386#[derive(Debug, Clone)]
 1387enum InlayHintRefreshReason {
 1388    ModifiersChanged(bool),
 1389    Toggle(bool),
 1390    SettingsChange(InlayHintSettings),
 1391    NewLinesShown,
 1392    BufferEdited(HashSet<Arc<Language>>),
 1393    RefreshRequested,
 1394    ExcerptsRemoved(Vec<ExcerptId>),
 1395}
 1396
 1397impl InlayHintRefreshReason {
 1398    fn description(&self) -> &'static str {
 1399        match self {
 1400            Self::ModifiersChanged(_) => "modifiers changed",
 1401            Self::Toggle(_) => "toggle",
 1402            Self::SettingsChange(_) => "settings change",
 1403            Self::NewLinesShown => "new lines shown",
 1404            Self::BufferEdited(_) => "buffer edited",
 1405            Self::RefreshRequested => "refresh requested",
 1406            Self::ExcerptsRemoved(_) => "excerpts removed",
 1407        }
 1408    }
 1409}
 1410
 1411pub enum FormatTarget {
 1412    Buffers,
 1413    Ranges(Vec<Range<MultiBufferPoint>>),
 1414}
 1415
 1416pub(crate) struct FocusedBlock {
 1417    id: BlockId,
 1418    focus_handle: WeakFocusHandle,
 1419}
 1420
 1421#[derive(Clone)]
 1422enum JumpData {
 1423    MultiBufferRow {
 1424        row: MultiBufferRow,
 1425        line_offset_from_top: u32,
 1426    },
 1427    MultiBufferPoint {
 1428        excerpt_id: ExcerptId,
 1429        position: Point,
 1430        anchor: text::Anchor,
 1431        line_offset_from_top: u32,
 1432    },
 1433}
 1434
 1435pub enum MultibufferSelectionMode {
 1436    First,
 1437    All,
 1438}
 1439
 1440#[derive(Clone, Copy, Debug, Default)]
 1441pub struct RewrapOptions {
 1442    pub override_language_settings: bool,
 1443    pub preserve_existing_whitespace: bool,
 1444}
 1445
 1446impl Editor {
 1447    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1448        let buffer = cx.new(|cx| Buffer::local("", cx));
 1449        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1450        Self::new(
 1451            EditorMode::SingleLine { auto_width: false },
 1452            buffer,
 1453            None,
 1454            window,
 1455            cx,
 1456        )
 1457    }
 1458
 1459    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1460        let buffer = cx.new(|cx| Buffer::local("", cx));
 1461        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1462        Self::new(EditorMode::full(), buffer, None, window, cx)
 1463    }
 1464
 1465    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1466        let buffer = cx.new(|cx| Buffer::local("", cx));
 1467        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1468        Self::new(
 1469            EditorMode::SingleLine { auto_width: true },
 1470            buffer,
 1471            None,
 1472            window,
 1473            cx,
 1474        )
 1475    }
 1476
 1477    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1478        let buffer = cx.new(|cx| Buffer::local("", cx));
 1479        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1480        Self::new(
 1481            EditorMode::AutoHeight { max_lines },
 1482            buffer,
 1483            None,
 1484            window,
 1485            cx,
 1486        )
 1487    }
 1488
 1489    pub fn for_buffer(
 1490        buffer: Entity<Buffer>,
 1491        project: Option<Entity<Project>>,
 1492        window: &mut Window,
 1493        cx: &mut Context<Self>,
 1494    ) -> Self {
 1495        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1496        Self::new(EditorMode::full(), buffer, project, window, cx)
 1497    }
 1498
 1499    pub fn for_multibuffer(
 1500        buffer: Entity<MultiBuffer>,
 1501        project: Option<Entity<Project>>,
 1502        window: &mut Window,
 1503        cx: &mut Context<Self>,
 1504    ) -> Self {
 1505        Self::new(EditorMode::full(), buffer, project, window, cx)
 1506    }
 1507
 1508    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1509        let mut clone = Self::new(
 1510            self.mode.clone(),
 1511            self.buffer.clone(),
 1512            self.project.clone(),
 1513            window,
 1514            cx,
 1515        );
 1516        self.display_map.update(cx, |display_map, cx| {
 1517            let snapshot = display_map.snapshot(cx);
 1518            clone.display_map.update(cx, |display_map, cx| {
 1519                display_map.set_state(&snapshot, cx);
 1520            });
 1521        });
 1522        clone.folds_did_change(cx);
 1523        clone.selections.clone_state(&self.selections);
 1524        clone.scroll_manager.clone_state(&self.scroll_manager);
 1525        clone.searchable = self.searchable;
 1526        clone.read_only = self.read_only;
 1527        clone
 1528    }
 1529
 1530    pub fn new(
 1531        mode: EditorMode,
 1532        buffer: Entity<MultiBuffer>,
 1533        project: Option<Entity<Project>>,
 1534        window: &mut Window,
 1535        cx: &mut Context<Self>,
 1536    ) -> Self {
 1537        Editor::new_internal(mode, buffer, project, None, window, cx)
 1538    }
 1539
 1540    fn new_internal(
 1541        mode: EditorMode,
 1542        buffer: Entity<MultiBuffer>,
 1543        project: Option<Entity<Project>>,
 1544        display_map: Option<Entity<DisplayMap>>,
 1545        window: &mut Window,
 1546        cx: &mut Context<Self>,
 1547    ) -> Self {
 1548        debug_assert!(
 1549            display_map.is_none() || mode.is_minimap(),
 1550            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1551        );
 1552
 1553        let full_mode = mode.is_full();
 1554        let diagnostics_max_severity = if full_mode {
 1555            EditorSettings::get_global(cx)
 1556                .diagnostics_max_severity
 1557                .unwrap_or(DiagnosticSeverity::Hint)
 1558        } else {
 1559            DiagnosticSeverity::Off
 1560        };
 1561        let style = window.text_style();
 1562        let font_size = style.font_size.to_pixels(window.rem_size());
 1563        let editor = cx.entity().downgrade();
 1564        let fold_placeholder = FoldPlaceholder {
 1565            constrain_width: true,
 1566            render: Arc::new(move |fold_id, fold_range, cx| {
 1567                let editor = editor.clone();
 1568                div()
 1569                    .id(fold_id)
 1570                    .bg(cx.theme().colors().ghost_element_background)
 1571                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1572                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1573                    .rounded_xs()
 1574                    .size_full()
 1575                    .cursor_pointer()
 1576                    .child("")
 1577                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1578                    .on_click(move |_, _window, cx| {
 1579                        editor
 1580                            .update(cx, |editor, cx| {
 1581                                editor.unfold_ranges(
 1582                                    &[fold_range.start..fold_range.end],
 1583                                    true,
 1584                                    false,
 1585                                    cx,
 1586                                );
 1587                                cx.stop_propagation();
 1588                            })
 1589                            .ok();
 1590                    })
 1591                    .into_any()
 1592            }),
 1593            merge_adjacent: true,
 1594            ..FoldPlaceholder::default()
 1595        };
 1596        let display_map = display_map.unwrap_or_else(|| {
 1597            cx.new(|cx| {
 1598                DisplayMap::new(
 1599                    buffer.clone(),
 1600                    style.font(),
 1601                    font_size,
 1602                    None,
 1603                    FILE_HEADER_HEIGHT,
 1604                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1605                    fold_placeholder,
 1606                    diagnostics_max_severity,
 1607                    cx,
 1608                )
 1609            })
 1610        });
 1611
 1612        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1613
 1614        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1615
 1616        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1617            .then(|| language_settings::SoftWrap::None);
 1618
 1619        let mut project_subscriptions = Vec::new();
 1620        if mode.is_full() {
 1621            if let Some(project) = project.as_ref() {
 1622                project_subscriptions.push(cx.subscribe_in(
 1623                    project,
 1624                    window,
 1625                    |editor, _, event, window, cx| match event {
 1626                        project::Event::RefreshCodeLens => {
 1627                            // we always query lens with actions, without storing them, always refreshing them
 1628                        }
 1629                        project::Event::RefreshInlayHints => {
 1630                            editor
 1631                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1632                        }
 1633                        project::Event::SnippetEdit(id, snippet_edits) => {
 1634                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1635                                let focus_handle = editor.focus_handle(cx);
 1636                                if focus_handle.is_focused(window) {
 1637                                    let snapshot = buffer.read(cx).snapshot();
 1638                                    for (range, snippet) in snippet_edits {
 1639                                        let editor_range =
 1640                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1641                                        editor
 1642                                            .insert_snippet(
 1643                                                &[editor_range],
 1644                                                snippet.clone(),
 1645                                                window,
 1646                                                cx,
 1647                                            )
 1648                                            .ok();
 1649                                    }
 1650                                }
 1651                            }
 1652                        }
 1653                        _ => {}
 1654                    },
 1655                ));
 1656                if let Some(task_inventory) = project
 1657                    .read(cx)
 1658                    .task_store()
 1659                    .read(cx)
 1660                    .task_inventory()
 1661                    .cloned()
 1662                {
 1663                    project_subscriptions.push(cx.observe_in(
 1664                        &task_inventory,
 1665                        window,
 1666                        |editor, _, window, cx| {
 1667                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1668                        },
 1669                    ));
 1670                };
 1671
 1672                project_subscriptions.push(cx.subscribe_in(
 1673                    &project.read(cx).breakpoint_store(),
 1674                    window,
 1675                    |editor, _, event, window, cx| match event {
 1676                        BreakpointStoreEvent::ClearDebugLines => {
 1677                            editor.clear_row_highlights::<ActiveDebugLine>();
 1678                            editor.refresh_inline_values(cx);
 1679                        }
 1680                        BreakpointStoreEvent::SetDebugLine => {
 1681                            if editor.go_to_active_debug_line(window, cx) {
 1682                                cx.stop_propagation();
 1683                            }
 1684
 1685                            editor.refresh_inline_values(cx);
 1686                        }
 1687                        _ => {}
 1688                    },
 1689                ));
 1690            }
 1691        }
 1692
 1693        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1694
 1695        let inlay_hint_settings =
 1696            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1697        let focus_handle = cx.focus_handle();
 1698        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1699            .detach();
 1700        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1701            .detach();
 1702        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1703            .detach();
 1704        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1705            .detach();
 1706
 1707        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1708            Some(false)
 1709        } else {
 1710            None
 1711        };
 1712
 1713        let breakpoint_store = match (&mode, project.as_ref()) {
 1714            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1715            _ => None,
 1716        };
 1717
 1718        let mut code_action_providers = Vec::new();
 1719        let mut load_uncommitted_diff = None;
 1720        if let Some(project) = project.clone() {
 1721            load_uncommitted_diff = Some(
 1722                update_uncommitted_diff_for_buffer(
 1723                    cx.entity(),
 1724                    &project,
 1725                    buffer.read(cx).all_buffers(),
 1726                    buffer.clone(),
 1727                    cx,
 1728                )
 1729                .shared(),
 1730            );
 1731            code_action_providers.push(Rc::new(project) as Rc<_>);
 1732        }
 1733
 1734        let mut this = Self {
 1735            focus_handle,
 1736            show_cursor_when_unfocused: false,
 1737            last_focused_descendant: None,
 1738            buffer: buffer.clone(),
 1739            display_map: display_map.clone(),
 1740            selections,
 1741            scroll_manager: ScrollManager::new(cx),
 1742            columnar_selection_tail: None,
 1743            add_selections_state: None,
 1744            select_next_state: None,
 1745            select_prev_state: None,
 1746            selection_history: SelectionHistory::default(),
 1747            autoclose_regions: Vec::new(),
 1748            snippet_stack: InvalidationStack::default(),
 1749            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1750            ime_transaction: None,
 1751            active_diagnostics: ActiveDiagnostic::None,
 1752            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1753            inline_diagnostics_update: Task::ready(()),
 1754            inline_diagnostics: Vec::new(),
 1755            soft_wrap_mode_override,
 1756            diagnostics_max_severity,
 1757            hard_wrap: None,
 1758            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1759            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1760            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1761            project,
 1762            blink_manager: blink_manager.clone(),
 1763            show_local_selections: true,
 1764            show_scrollbars: full_mode,
 1765            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1766            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1767            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1768            show_gutter: mode.is_full(),
 1769            show_line_numbers: None,
 1770            use_relative_line_numbers: None,
 1771            disable_expand_excerpt_buttons: false,
 1772            show_git_diff_gutter: None,
 1773            show_code_actions: None,
 1774            show_runnables: None,
 1775            show_breakpoints: None,
 1776            show_wrap_guides: None,
 1777            show_indent_guides,
 1778            placeholder_text: None,
 1779            highlight_order: 0,
 1780            highlighted_rows: HashMap::default(),
 1781            background_highlights: TreeMap::default(),
 1782            gutter_highlights: TreeMap::default(),
 1783            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1784            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1785            nav_history: None,
 1786            context_menu: RefCell::new(None),
 1787            context_menu_options: None,
 1788            mouse_context_menu: None,
 1789            completion_tasks: Vec::new(),
 1790            inline_blame_popover: None,
 1791            signature_help_state: SignatureHelpState::default(),
 1792            auto_signature_help: None,
 1793            find_all_references_task_sources: Vec::new(),
 1794            next_completion_id: 0,
 1795            next_inlay_id: 0,
 1796            code_action_providers,
 1797            available_code_actions: None,
 1798            code_actions_task: None,
 1799            quick_selection_highlight_task: None,
 1800            debounced_selection_highlight_task: None,
 1801            document_highlights_task: None,
 1802            linked_editing_range_task: None,
 1803            pending_rename: None,
 1804            searchable: true,
 1805            cursor_shape: EditorSettings::get_global(cx)
 1806                .cursor_shape
 1807                .unwrap_or_default(),
 1808            current_line_highlight: None,
 1809            autoindent_mode: Some(AutoindentMode::EachLine),
 1810            collapse_matches: false,
 1811            workspace: None,
 1812            input_enabled: true,
 1813            use_modal_editing: mode.is_full(),
 1814            read_only: mode.is_minimap(),
 1815            use_autoclose: true,
 1816            use_auto_surround: true,
 1817            auto_replace_emoji_shortcode: false,
 1818            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1819            leader_id: None,
 1820            remote_id: None,
 1821            hover_state: HoverState::default(),
 1822            pending_mouse_down: None,
 1823            hovered_link_state: None,
 1824            edit_prediction_provider: None,
 1825            active_inline_completion: None,
 1826            stale_inline_completion_in_menu: None,
 1827            edit_prediction_preview: EditPredictionPreview::Inactive {
 1828                released_too_fast: false,
 1829            },
 1830            inline_diagnostics_enabled: mode.is_full(),
 1831            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1832            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1833
 1834            gutter_hovered: false,
 1835            pixel_position_of_newest_cursor: None,
 1836            last_bounds: None,
 1837            last_position_map: None,
 1838            expect_bounds_change: None,
 1839            gutter_dimensions: GutterDimensions::default(),
 1840            style: None,
 1841            show_cursor_names: false,
 1842            hovered_cursors: HashMap::default(),
 1843            next_editor_action_id: EditorActionId::default(),
 1844            editor_actions: Rc::default(),
 1845            inline_completions_hidden_for_vim_mode: false,
 1846            show_inline_completions_override: None,
 1847            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1848            edit_prediction_settings: EditPredictionSettings::Disabled,
 1849            edit_prediction_indent_conflict: false,
 1850            edit_prediction_requires_modifier_in_indent_conflict: true,
 1851            custom_context_menu: None,
 1852            show_git_blame_gutter: false,
 1853            show_git_blame_inline: false,
 1854            show_selection_menu: None,
 1855            show_git_blame_inline_delay_task: None,
 1856            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1857            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1858            serialize_dirty_buffers: !mode.is_minimap()
 1859                && ProjectSettings::get_global(cx)
 1860                    .session
 1861                    .restore_unsaved_buffers,
 1862            blame: None,
 1863            blame_subscription: None,
 1864            tasks: BTreeMap::default(),
 1865
 1866            breakpoint_store,
 1867            gutter_breakpoint_indicator: (None, None),
 1868            _subscriptions: vec![
 1869                cx.observe(&buffer, Self::on_buffer_changed),
 1870                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1871                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1872                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1873                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1874                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1875                cx.observe_window_activation(window, |editor, window, cx| {
 1876                    let active = window.is_window_active();
 1877                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1878                        if active {
 1879                            blink_manager.enable(cx);
 1880                        } else {
 1881                            blink_manager.disable(cx);
 1882                        }
 1883                    });
 1884                }),
 1885            ],
 1886            tasks_update_task: None,
 1887            linked_edit_ranges: Default::default(),
 1888            in_project_search: false,
 1889            previous_search_ranges: None,
 1890            breadcrumb_header: None,
 1891            focused_block: None,
 1892            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1893            addons: HashMap::default(),
 1894            registered_buffers: HashMap::default(),
 1895            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1896            selection_mark_mode: false,
 1897            toggle_fold_multiple_buffers: Task::ready(()),
 1898            serialize_selections: Task::ready(()),
 1899            serialize_folds: Task::ready(()),
 1900            text_style_refinement: None,
 1901            load_diff_task: load_uncommitted_diff,
 1902            temporary_diff_override: false,
 1903            mouse_cursor_hidden: false,
 1904            minimap: None,
 1905            hide_mouse_mode: EditorSettings::get_global(cx)
 1906                .hide_mouse
 1907                .unwrap_or_default(),
 1908            change_list: ChangeList::new(),
 1909            mode,
 1910        };
 1911        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1912            this._subscriptions
 1913                .push(cx.observe(breakpoints, |_, _, cx| {
 1914                    cx.notify();
 1915                }));
 1916        }
 1917        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1918        this._subscriptions.extend(project_subscriptions);
 1919
 1920        this._subscriptions.push(cx.subscribe_in(
 1921            &cx.entity(),
 1922            window,
 1923            |editor, _, e: &EditorEvent, window, cx| match e {
 1924                EditorEvent::ScrollPositionChanged { local, .. } => {
 1925                    if *local {
 1926                        let new_anchor = editor.scroll_manager.anchor();
 1927                        let snapshot = editor.snapshot(window, cx);
 1928                        editor.update_restoration_data(cx, move |data| {
 1929                            data.scroll_position = (
 1930                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1931                                new_anchor.offset,
 1932                            );
 1933                        });
 1934                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1935                        editor.inline_blame_popover.take();
 1936                    }
 1937                }
 1938                EditorEvent::Edited { .. } => {
 1939                    if !vim_enabled(cx) {
 1940                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1941                        let pop_state = editor
 1942                            .change_list
 1943                            .last()
 1944                            .map(|previous| {
 1945                                previous.len() == selections.len()
 1946                                    && previous.iter().enumerate().all(|(ix, p)| {
 1947                                        p.to_display_point(&map).row()
 1948                                            == selections[ix].head().row()
 1949                                    })
 1950                            })
 1951                            .unwrap_or(false);
 1952                        let new_positions = selections
 1953                            .into_iter()
 1954                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1955                            .collect();
 1956                        editor
 1957                            .change_list
 1958                            .push_to_change_list(pop_state, new_positions);
 1959                    }
 1960                }
 1961                _ => (),
 1962            },
 1963        ));
 1964
 1965        if let Some(dap_store) = this
 1966            .project
 1967            .as_ref()
 1968            .map(|project| project.read(cx).dap_store())
 1969        {
 1970            let weak_editor = cx.weak_entity();
 1971
 1972            this._subscriptions
 1973                .push(
 1974                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1975                        let session_entity = cx.entity();
 1976                        weak_editor
 1977                            .update(cx, |editor, cx| {
 1978                                editor._subscriptions.push(
 1979                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1980                                );
 1981                            })
 1982                            .ok();
 1983                    }),
 1984                );
 1985
 1986            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1987                this._subscriptions
 1988                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1989            }
 1990        }
 1991
 1992        this.end_selection(window, cx);
 1993        this.scroll_manager.show_scrollbars(window, cx);
 1994        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1995
 1996        if full_mode {
 1997            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1998            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1999
 2000            if this.git_blame_inline_enabled {
 2001                this.start_git_blame_inline(false, window, cx);
 2002            }
 2003
 2004            this.go_to_active_debug_line(window, cx);
 2005
 2006            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2007                if let Some(project) = this.project.as_ref() {
 2008                    let handle = project.update(cx, |project, cx| {
 2009                        project.register_buffer_with_language_servers(&buffer, cx)
 2010                    });
 2011                    this.registered_buffers
 2012                        .insert(buffer.read(cx).remote_id(), handle);
 2013                }
 2014            }
 2015
 2016            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2017        }
 2018
 2019        this.report_editor_event("Editor Opened", None, cx);
 2020        this
 2021    }
 2022
 2023    pub fn deploy_mouse_context_menu(
 2024        &mut self,
 2025        position: gpui::Point<Pixels>,
 2026        context_menu: Entity<ContextMenu>,
 2027        window: &mut Window,
 2028        cx: &mut Context<Self>,
 2029    ) {
 2030        self.mouse_context_menu = Some(MouseContextMenu::new(
 2031            self,
 2032            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2033            context_menu,
 2034            window,
 2035            cx,
 2036        ));
 2037    }
 2038
 2039    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2040        self.mouse_context_menu
 2041            .as_ref()
 2042            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2043    }
 2044
 2045    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2046        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2047    }
 2048
 2049    fn key_context_internal(
 2050        &self,
 2051        has_active_edit_prediction: bool,
 2052        window: &Window,
 2053        cx: &App,
 2054    ) -> KeyContext {
 2055        let mut key_context = KeyContext::new_with_defaults();
 2056        key_context.add("Editor");
 2057        let mode = match self.mode {
 2058            EditorMode::SingleLine { .. } => "single_line",
 2059            EditorMode::AutoHeight { .. } => "auto_height",
 2060            EditorMode::Minimap { .. } => "minimap",
 2061            EditorMode::Full { .. } => "full",
 2062        };
 2063
 2064        if EditorSettings::jupyter_enabled(cx) {
 2065            key_context.add("jupyter");
 2066        }
 2067
 2068        key_context.set("mode", mode);
 2069        if self.pending_rename.is_some() {
 2070            key_context.add("renaming");
 2071        }
 2072
 2073        match self.context_menu.borrow().as_ref() {
 2074            Some(CodeContextMenu::Completions(_)) => {
 2075                key_context.add("menu");
 2076                key_context.add("showing_completions");
 2077            }
 2078            Some(CodeContextMenu::CodeActions(_)) => {
 2079                key_context.add("menu");
 2080                key_context.add("showing_code_actions")
 2081            }
 2082            None => {}
 2083        }
 2084
 2085        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2086        if !self.focus_handle(cx).contains_focused(window, cx)
 2087            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2088        {
 2089            for addon in self.addons.values() {
 2090                addon.extend_key_context(&mut key_context, cx)
 2091            }
 2092        }
 2093
 2094        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2095            if let Some(extension) = singleton_buffer
 2096                .read(cx)
 2097                .file()
 2098                .and_then(|file| file.path().extension()?.to_str())
 2099            {
 2100                key_context.set("extension", extension.to_string());
 2101            }
 2102        } else {
 2103            key_context.add("multibuffer");
 2104        }
 2105
 2106        if has_active_edit_prediction {
 2107            if self.edit_prediction_in_conflict() {
 2108                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2109            } else {
 2110                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2111                key_context.add("copilot_suggestion");
 2112            }
 2113        }
 2114
 2115        if self.selection_mark_mode {
 2116            key_context.add("selection_mode");
 2117        }
 2118
 2119        key_context
 2120    }
 2121
 2122    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2123        self.mouse_cursor_hidden = match origin {
 2124            HideMouseCursorOrigin::TypingAction => {
 2125                matches!(
 2126                    self.hide_mouse_mode,
 2127                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2128                )
 2129            }
 2130            HideMouseCursorOrigin::MovementAction => {
 2131                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2132            }
 2133        };
 2134    }
 2135
 2136    pub fn edit_prediction_in_conflict(&self) -> bool {
 2137        if !self.show_edit_predictions_in_menu() {
 2138            return false;
 2139        }
 2140
 2141        let showing_completions = self
 2142            .context_menu
 2143            .borrow()
 2144            .as_ref()
 2145            .map_or(false, |context| {
 2146                matches!(context, CodeContextMenu::Completions(_))
 2147            });
 2148
 2149        showing_completions
 2150            || self.edit_prediction_requires_modifier()
 2151            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2152            // bindings to insert tab characters.
 2153            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2154    }
 2155
 2156    pub fn accept_edit_prediction_keybind(
 2157        &self,
 2158        window: &Window,
 2159        cx: &App,
 2160    ) -> AcceptEditPredictionBinding {
 2161        let key_context = self.key_context_internal(true, window, cx);
 2162        let in_conflict = self.edit_prediction_in_conflict();
 2163
 2164        AcceptEditPredictionBinding(
 2165            window
 2166                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2167                .into_iter()
 2168                .filter(|binding| {
 2169                    !in_conflict
 2170                        || binding
 2171                            .keystrokes()
 2172                            .first()
 2173                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2174                })
 2175                .rev()
 2176                .min_by_key(|binding| {
 2177                    binding
 2178                        .keystrokes()
 2179                        .first()
 2180                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2181                }),
 2182        )
 2183    }
 2184
 2185    pub fn new_file(
 2186        workspace: &mut Workspace,
 2187        _: &workspace::NewFile,
 2188        window: &mut Window,
 2189        cx: &mut Context<Workspace>,
 2190    ) {
 2191        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2192            "Failed to create buffer",
 2193            window,
 2194            cx,
 2195            |e, _, _| match e.error_code() {
 2196                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2197                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2198                e.error_tag("required").unwrap_or("the latest version")
 2199            )),
 2200                _ => None,
 2201            },
 2202        );
 2203    }
 2204
 2205    pub fn new_in_workspace(
 2206        workspace: &mut Workspace,
 2207        window: &mut Window,
 2208        cx: &mut Context<Workspace>,
 2209    ) -> Task<Result<Entity<Editor>>> {
 2210        let project = workspace.project().clone();
 2211        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2212
 2213        cx.spawn_in(window, async move |workspace, cx| {
 2214            let buffer = create.await?;
 2215            workspace.update_in(cx, |workspace, window, cx| {
 2216                let editor =
 2217                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2218                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2219                editor
 2220            })
 2221        })
 2222    }
 2223
 2224    fn new_file_vertical(
 2225        workspace: &mut Workspace,
 2226        _: &workspace::NewFileSplitVertical,
 2227        window: &mut Window,
 2228        cx: &mut Context<Workspace>,
 2229    ) {
 2230        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2231    }
 2232
 2233    fn new_file_horizontal(
 2234        workspace: &mut Workspace,
 2235        _: &workspace::NewFileSplitHorizontal,
 2236        window: &mut Window,
 2237        cx: &mut Context<Workspace>,
 2238    ) {
 2239        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2240    }
 2241
 2242    fn new_file_in_direction(
 2243        workspace: &mut Workspace,
 2244        direction: SplitDirection,
 2245        window: &mut Window,
 2246        cx: &mut Context<Workspace>,
 2247    ) {
 2248        let project = workspace.project().clone();
 2249        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2250
 2251        cx.spawn_in(window, async move |workspace, cx| {
 2252            let buffer = create.await?;
 2253            workspace.update_in(cx, move |workspace, window, cx| {
 2254                workspace.split_item(
 2255                    direction,
 2256                    Box::new(
 2257                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2258                    ),
 2259                    window,
 2260                    cx,
 2261                )
 2262            })?;
 2263            anyhow::Ok(())
 2264        })
 2265        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2266            match e.error_code() {
 2267                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2268                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2269                e.error_tag("required").unwrap_or("the latest version")
 2270            )),
 2271                _ => None,
 2272            }
 2273        });
 2274    }
 2275
 2276    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2277        self.leader_id
 2278    }
 2279
 2280    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2281        &self.buffer
 2282    }
 2283
 2284    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2285        self.workspace.as_ref()?.0.upgrade()
 2286    }
 2287
 2288    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2289        self.buffer().read(cx).title(cx)
 2290    }
 2291
 2292    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2293        let git_blame_gutter_max_author_length = self
 2294            .render_git_blame_gutter(cx)
 2295            .then(|| {
 2296                if let Some(blame) = self.blame.as_ref() {
 2297                    let max_author_length =
 2298                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2299                    Some(max_author_length)
 2300                } else {
 2301                    None
 2302                }
 2303            })
 2304            .flatten();
 2305
 2306        EditorSnapshot {
 2307            mode: self.mode.clone(),
 2308            show_gutter: self.show_gutter,
 2309            show_line_numbers: self.show_line_numbers,
 2310            show_git_diff_gutter: self.show_git_diff_gutter,
 2311            show_code_actions: self.show_code_actions,
 2312            show_runnables: self.show_runnables,
 2313            show_breakpoints: self.show_breakpoints,
 2314            git_blame_gutter_max_author_length,
 2315            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2316            scroll_anchor: self.scroll_manager.anchor(),
 2317            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2318            placeholder_text: self.placeholder_text.clone(),
 2319            is_focused: self.focus_handle.is_focused(window),
 2320            current_line_highlight: self
 2321                .current_line_highlight
 2322                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2323            gutter_hovered: self.gutter_hovered,
 2324        }
 2325    }
 2326
 2327    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2328        self.buffer.read(cx).language_at(point, cx)
 2329    }
 2330
 2331    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2332        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2333    }
 2334
 2335    pub fn active_excerpt(
 2336        &self,
 2337        cx: &App,
 2338    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2339        self.buffer
 2340            .read(cx)
 2341            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2342    }
 2343
 2344    pub fn mode(&self) -> &EditorMode {
 2345        &self.mode
 2346    }
 2347
 2348    pub fn set_mode(&mut self, mode: EditorMode) {
 2349        self.mode = mode;
 2350    }
 2351
 2352    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2353        self.collaboration_hub.as_deref()
 2354    }
 2355
 2356    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2357        self.collaboration_hub = Some(hub);
 2358    }
 2359
 2360    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2361        self.in_project_search = in_project_search;
 2362    }
 2363
 2364    pub fn set_custom_context_menu(
 2365        &mut self,
 2366        f: impl 'static
 2367        + Fn(
 2368            &mut Self,
 2369            DisplayPoint,
 2370            &mut Window,
 2371            &mut Context<Self>,
 2372        ) -> Option<Entity<ui::ContextMenu>>,
 2373    ) {
 2374        self.custom_context_menu = Some(Box::new(f))
 2375    }
 2376
 2377    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2378        self.completion_provider = provider;
 2379    }
 2380
 2381    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2382        self.semantics_provider.clone()
 2383    }
 2384
 2385    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2386        self.semantics_provider = provider;
 2387    }
 2388
 2389    pub fn set_edit_prediction_provider<T>(
 2390        &mut self,
 2391        provider: Option<Entity<T>>,
 2392        window: &mut Window,
 2393        cx: &mut Context<Self>,
 2394    ) where
 2395        T: EditPredictionProvider,
 2396    {
 2397        self.edit_prediction_provider =
 2398            provider.map(|provider| RegisteredInlineCompletionProvider {
 2399                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2400                    if this.focus_handle.is_focused(window) {
 2401                        this.update_visible_inline_completion(window, cx);
 2402                    }
 2403                }),
 2404                provider: Arc::new(provider),
 2405            });
 2406        self.update_edit_prediction_settings(cx);
 2407        self.refresh_inline_completion(false, false, window, cx);
 2408    }
 2409
 2410    pub fn placeholder_text(&self) -> Option<&str> {
 2411        self.placeholder_text.as_deref()
 2412    }
 2413
 2414    pub fn set_placeholder_text(
 2415        &mut self,
 2416        placeholder_text: impl Into<Arc<str>>,
 2417        cx: &mut Context<Self>,
 2418    ) {
 2419        let placeholder_text = Some(placeholder_text.into());
 2420        if self.placeholder_text != placeholder_text {
 2421            self.placeholder_text = placeholder_text;
 2422            cx.notify();
 2423        }
 2424    }
 2425
 2426    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2427        self.cursor_shape = cursor_shape;
 2428
 2429        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2430        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2431
 2432        cx.notify();
 2433    }
 2434
 2435    pub fn set_current_line_highlight(
 2436        &mut self,
 2437        current_line_highlight: Option<CurrentLineHighlight>,
 2438    ) {
 2439        self.current_line_highlight = current_line_highlight;
 2440    }
 2441
 2442    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2443        self.collapse_matches = collapse_matches;
 2444    }
 2445
 2446    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2447        let buffers = self.buffer.read(cx).all_buffers();
 2448        let Some(project) = self.project.as_ref() else {
 2449            return;
 2450        };
 2451        project.update(cx, |project, cx| {
 2452            for buffer in buffers {
 2453                self.registered_buffers
 2454                    .entry(buffer.read(cx).remote_id())
 2455                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2456            }
 2457        })
 2458    }
 2459
 2460    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2461        if self.collapse_matches {
 2462            return range.start..range.start;
 2463        }
 2464        range.clone()
 2465    }
 2466
 2467    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2468        if self.display_map.read(cx).clip_at_line_ends != clip {
 2469            self.display_map
 2470                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2471        }
 2472    }
 2473
 2474    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2475        self.input_enabled = input_enabled;
 2476    }
 2477
 2478    pub fn set_inline_completions_hidden_for_vim_mode(
 2479        &mut self,
 2480        hidden: bool,
 2481        window: &mut Window,
 2482        cx: &mut Context<Self>,
 2483    ) {
 2484        if hidden != self.inline_completions_hidden_for_vim_mode {
 2485            self.inline_completions_hidden_for_vim_mode = hidden;
 2486            if hidden {
 2487                self.update_visible_inline_completion(window, cx);
 2488            } else {
 2489                self.refresh_inline_completion(true, false, window, cx);
 2490            }
 2491        }
 2492    }
 2493
 2494    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2495        self.menu_inline_completions_policy = value;
 2496    }
 2497
 2498    pub fn set_autoindent(&mut self, autoindent: bool) {
 2499        if autoindent {
 2500            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2501        } else {
 2502            self.autoindent_mode = None;
 2503        }
 2504    }
 2505
 2506    pub fn read_only(&self, cx: &App) -> bool {
 2507        self.read_only || self.buffer.read(cx).read_only()
 2508    }
 2509
 2510    pub fn set_read_only(&mut self, read_only: bool) {
 2511        self.read_only = read_only;
 2512    }
 2513
 2514    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2515        self.use_autoclose = autoclose;
 2516    }
 2517
 2518    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2519        self.use_auto_surround = auto_surround;
 2520    }
 2521
 2522    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2523        self.auto_replace_emoji_shortcode = auto_replace;
 2524    }
 2525
 2526    pub fn toggle_edit_predictions(
 2527        &mut self,
 2528        _: &ToggleEditPrediction,
 2529        window: &mut Window,
 2530        cx: &mut Context<Self>,
 2531    ) {
 2532        if self.show_inline_completions_override.is_some() {
 2533            self.set_show_edit_predictions(None, window, cx);
 2534        } else {
 2535            let show_edit_predictions = !self.edit_predictions_enabled();
 2536            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2537        }
 2538    }
 2539
 2540    pub fn set_show_edit_predictions(
 2541        &mut self,
 2542        show_edit_predictions: Option<bool>,
 2543        window: &mut Window,
 2544        cx: &mut Context<Self>,
 2545    ) {
 2546        self.show_inline_completions_override = show_edit_predictions;
 2547        self.update_edit_prediction_settings(cx);
 2548
 2549        if let Some(false) = show_edit_predictions {
 2550            self.discard_inline_completion(false, cx);
 2551        } else {
 2552            self.refresh_inline_completion(false, true, window, cx);
 2553        }
 2554    }
 2555
 2556    fn inline_completions_disabled_in_scope(
 2557        &self,
 2558        buffer: &Entity<Buffer>,
 2559        buffer_position: language::Anchor,
 2560        cx: &App,
 2561    ) -> bool {
 2562        let snapshot = buffer.read(cx).snapshot();
 2563        let settings = snapshot.settings_at(buffer_position, cx);
 2564
 2565        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2566            return false;
 2567        };
 2568
 2569        scope.override_name().map_or(false, |scope_name| {
 2570            settings
 2571                .edit_predictions_disabled_in
 2572                .iter()
 2573                .any(|s| s == scope_name)
 2574        })
 2575    }
 2576
 2577    pub fn set_use_modal_editing(&mut self, to: bool) {
 2578        self.use_modal_editing = to;
 2579    }
 2580
 2581    pub fn use_modal_editing(&self) -> bool {
 2582        self.use_modal_editing
 2583    }
 2584
 2585    fn selections_did_change(
 2586        &mut self,
 2587        local: bool,
 2588        old_cursor_position: &Anchor,
 2589        show_completions: bool,
 2590        window: &mut Window,
 2591        cx: &mut Context<Self>,
 2592    ) {
 2593        window.invalidate_character_coordinates();
 2594
 2595        // Copy selections to primary selection buffer
 2596        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2597        if local {
 2598            let selections = self.selections.all::<usize>(cx);
 2599            let buffer_handle = self.buffer.read(cx).read(cx);
 2600
 2601            let mut text = String::new();
 2602            for (index, selection) in selections.iter().enumerate() {
 2603                let text_for_selection = buffer_handle
 2604                    .text_for_range(selection.start..selection.end)
 2605                    .collect::<String>();
 2606
 2607                text.push_str(&text_for_selection);
 2608                if index != selections.len() - 1 {
 2609                    text.push('\n');
 2610                }
 2611            }
 2612
 2613            if !text.is_empty() {
 2614                cx.write_to_primary(ClipboardItem::new_string(text));
 2615            }
 2616        }
 2617
 2618        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2619            self.buffer.update(cx, |buffer, cx| {
 2620                buffer.set_active_selections(
 2621                    &self.selections.disjoint_anchors(),
 2622                    self.selections.line_mode,
 2623                    self.cursor_shape,
 2624                    cx,
 2625                )
 2626            });
 2627        }
 2628        let display_map = self
 2629            .display_map
 2630            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2631        let buffer = &display_map.buffer_snapshot;
 2632        self.add_selections_state = None;
 2633        self.select_next_state = None;
 2634        self.select_prev_state = None;
 2635        self.select_syntax_node_history.try_clear();
 2636        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2637        self.snippet_stack
 2638            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2639        self.take_rename(false, window, cx);
 2640
 2641        let new_cursor_position = self.selections.newest_anchor().head();
 2642
 2643        self.push_to_nav_history(
 2644            *old_cursor_position,
 2645            Some(new_cursor_position.to_point(buffer)),
 2646            false,
 2647            cx,
 2648        );
 2649
 2650        if local {
 2651            let new_cursor_position = self.selections.newest_anchor().head();
 2652            let mut context_menu = self.context_menu.borrow_mut();
 2653            let completion_menu = match context_menu.as_ref() {
 2654                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2655                _ => {
 2656                    *context_menu = None;
 2657                    None
 2658                }
 2659            };
 2660            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2661                if !self.registered_buffers.contains_key(&buffer_id) {
 2662                    if let Some(project) = self.project.as_ref() {
 2663                        project.update(cx, |project, cx| {
 2664                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2665                                return;
 2666                            };
 2667                            self.registered_buffers.insert(
 2668                                buffer_id,
 2669                                project.register_buffer_with_language_servers(&buffer, cx),
 2670                            );
 2671                        })
 2672                    }
 2673                }
 2674            }
 2675
 2676            if let Some(completion_menu) = completion_menu {
 2677                let cursor_position = new_cursor_position.to_offset(buffer);
 2678                let (word_range, kind) =
 2679                    buffer.surrounding_word(completion_menu.initial_position, true);
 2680                if kind == Some(CharKind::Word)
 2681                    && word_range.to_inclusive().contains(&cursor_position)
 2682                {
 2683                    let mut completion_menu = completion_menu.clone();
 2684                    drop(context_menu);
 2685
 2686                    let query = Self::completion_query(buffer, cursor_position);
 2687                    let completion_provider = self.completion_provider.clone();
 2688                    cx.spawn_in(window, async move |this, cx| {
 2689                        completion_menu
 2690                            .filter(query.as_deref(), completion_provider, this.clone(), cx)
 2691                            .await;
 2692
 2693                        this.update(cx, |this, cx| {
 2694                            let mut context_menu = this.context_menu.borrow_mut();
 2695                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2696                            else {
 2697                                return;
 2698                            };
 2699
 2700                            if menu.id > completion_menu.id {
 2701                                return;
 2702                            }
 2703
 2704                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2705                            drop(context_menu);
 2706                            cx.notify();
 2707                        })
 2708                    })
 2709                    .detach();
 2710
 2711                    if show_completions {
 2712                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2713                    }
 2714                } else {
 2715                    drop(context_menu);
 2716                    self.hide_context_menu(window, cx);
 2717                }
 2718            } else {
 2719                drop(context_menu);
 2720            }
 2721
 2722            hide_hover(self, cx);
 2723
 2724            if old_cursor_position.to_display_point(&display_map).row()
 2725                != new_cursor_position.to_display_point(&display_map).row()
 2726            {
 2727                self.available_code_actions.take();
 2728            }
 2729            self.refresh_code_actions(window, cx);
 2730            self.refresh_document_highlights(cx);
 2731            self.refresh_selected_text_highlights(false, window, cx);
 2732            refresh_matching_bracket_highlights(self, window, cx);
 2733            self.update_visible_inline_completion(window, cx);
 2734            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2735            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2736            self.inline_blame_popover.take();
 2737            if self.git_blame_inline_enabled {
 2738                self.start_inline_blame_timer(window, cx);
 2739            }
 2740        }
 2741
 2742        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2743        cx.emit(EditorEvent::SelectionsChanged { local });
 2744
 2745        let selections = &self.selections.disjoint;
 2746        if selections.len() == 1 {
 2747            cx.emit(SearchEvent::ActiveMatchChanged)
 2748        }
 2749        if local {
 2750            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2751                let inmemory_selections = selections
 2752                    .iter()
 2753                    .map(|s| {
 2754                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2755                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2756                    })
 2757                    .collect();
 2758                self.update_restoration_data(cx, |data| {
 2759                    data.selections = inmemory_selections;
 2760                });
 2761
 2762                if WorkspaceSettings::get(None, cx).restore_on_startup
 2763                    != RestoreOnStartupBehavior::None
 2764                {
 2765                    if let Some(workspace_id) =
 2766                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2767                    {
 2768                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2769                        let selections = selections.clone();
 2770                        let background_executor = cx.background_executor().clone();
 2771                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2772                        self.serialize_selections = cx.background_spawn(async move {
 2773                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2774                    let db_selections = selections
 2775                        .iter()
 2776                        .map(|selection| {
 2777                            (
 2778                                selection.start.to_offset(&snapshot),
 2779                                selection.end.to_offset(&snapshot),
 2780                            )
 2781                        })
 2782                        .collect();
 2783
 2784                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2785                        .await
 2786                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2787                        .log_err();
 2788                });
 2789                    }
 2790                }
 2791            }
 2792        }
 2793
 2794        cx.notify();
 2795    }
 2796
 2797    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2798        use text::ToOffset as _;
 2799        use text::ToPoint as _;
 2800
 2801        if self.mode.is_minimap()
 2802            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2803        {
 2804            return;
 2805        }
 2806
 2807        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2808            return;
 2809        };
 2810
 2811        let snapshot = singleton.read(cx).snapshot();
 2812        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2813            let display_snapshot = display_map.snapshot(cx);
 2814
 2815            display_snapshot
 2816                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2817                .map(|fold| {
 2818                    fold.range.start.text_anchor.to_point(&snapshot)
 2819                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2820                })
 2821                .collect()
 2822        });
 2823        self.update_restoration_data(cx, |data| {
 2824            data.folds = inmemory_folds;
 2825        });
 2826
 2827        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2828            return;
 2829        };
 2830        let background_executor = cx.background_executor().clone();
 2831        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2832        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2833            display_map
 2834                .snapshot(cx)
 2835                .folds_in_range(0..snapshot.len())
 2836                .map(|fold| {
 2837                    (
 2838                        fold.range.start.text_anchor.to_offset(&snapshot),
 2839                        fold.range.end.text_anchor.to_offset(&snapshot),
 2840                    )
 2841                })
 2842                .collect()
 2843        });
 2844        self.serialize_folds = cx.background_spawn(async move {
 2845            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2846            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2847                .await
 2848                .with_context(|| {
 2849                    format!(
 2850                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2851                    )
 2852                })
 2853                .log_err();
 2854        });
 2855    }
 2856
 2857    pub fn sync_selections(
 2858        &mut self,
 2859        other: Entity<Editor>,
 2860        cx: &mut Context<Self>,
 2861    ) -> gpui::Subscription {
 2862        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2863        self.selections.change_with(cx, |selections| {
 2864            selections.select_anchors(other_selections);
 2865        });
 2866
 2867        let other_subscription =
 2868            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2869                EditorEvent::SelectionsChanged { local: true } => {
 2870                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2871                    if other_selections.is_empty() {
 2872                        return;
 2873                    }
 2874                    this.selections.change_with(cx, |selections| {
 2875                        selections.select_anchors(other_selections);
 2876                    });
 2877                }
 2878                _ => {}
 2879            });
 2880
 2881        let this_subscription =
 2882            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2883                EditorEvent::SelectionsChanged { local: true } => {
 2884                    let these_selections = this.selections.disjoint.to_vec();
 2885                    if these_selections.is_empty() {
 2886                        return;
 2887                    }
 2888                    other.update(cx, |other_editor, cx| {
 2889                        other_editor.selections.change_with(cx, |selections| {
 2890                            selections.select_anchors(these_selections);
 2891                        })
 2892                    });
 2893                }
 2894                _ => {}
 2895            });
 2896
 2897        Subscription::join(other_subscription, this_subscription)
 2898    }
 2899
 2900    pub fn change_selections<R>(
 2901        &mut self,
 2902        autoscroll: Option<Autoscroll>,
 2903        window: &mut Window,
 2904        cx: &mut Context<Self>,
 2905        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2906    ) -> R {
 2907        self.change_selections_inner(autoscroll, true, window, cx, change)
 2908    }
 2909
 2910    fn change_selections_inner<R>(
 2911        &mut self,
 2912        autoscroll: Option<Autoscroll>,
 2913        request_completions: bool,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2917    ) -> R {
 2918        let old_cursor_position = self.selections.newest_anchor().head();
 2919        self.push_to_selection_history();
 2920
 2921        let (changed, result) = self.selections.change_with(cx, change);
 2922
 2923        if changed {
 2924            if let Some(autoscroll) = autoscroll {
 2925                self.request_autoscroll(autoscroll, cx);
 2926            }
 2927            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2928
 2929            if self.should_open_signature_help_automatically(
 2930                &old_cursor_position,
 2931                self.signature_help_state.backspace_pressed(),
 2932                cx,
 2933            ) {
 2934                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2935            }
 2936            self.signature_help_state.set_backspace_pressed(false);
 2937        }
 2938
 2939        result
 2940    }
 2941
 2942    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2943    where
 2944        I: IntoIterator<Item = (Range<S>, T)>,
 2945        S: ToOffset,
 2946        T: Into<Arc<str>>,
 2947    {
 2948        if self.read_only(cx) {
 2949            return;
 2950        }
 2951
 2952        self.buffer
 2953            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2954    }
 2955
 2956    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2957    where
 2958        I: IntoIterator<Item = (Range<S>, T)>,
 2959        S: ToOffset,
 2960        T: Into<Arc<str>>,
 2961    {
 2962        if self.read_only(cx) {
 2963            return;
 2964        }
 2965
 2966        self.buffer.update(cx, |buffer, cx| {
 2967            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2968        });
 2969    }
 2970
 2971    pub fn edit_with_block_indent<I, S, T>(
 2972        &mut self,
 2973        edits: I,
 2974        original_indent_columns: Vec<Option<u32>>,
 2975        cx: &mut Context<Self>,
 2976    ) where
 2977        I: IntoIterator<Item = (Range<S>, T)>,
 2978        S: ToOffset,
 2979        T: Into<Arc<str>>,
 2980    {
 2981        if self.read_only(cx) {
 2982            return;
 2983        }
 2984
 2985        self.buffer.update(cx, |buffer, cx| {
 2986            buffer.edit(
 2987                edits,
 2988                Some(AutoindentMode::Block {
 2989                    original_indent_columns,
 2990                }),
 2991                cx,
 2992            )
 2993        });
 2994    }
 2995
 2996    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2997        self.hide_context_menu(window, cx);
 2998
 2999        match phase {
 3000            SelectPhase::Begin {
 3001                position,
 3002                add,
 3003                click_count,
 3004            } => self.begin_selection(position, add, click_count, window, cx),
 3005            SelectPhase::BeginColumnar {
 3006                position,
 3007                goal_column,
 3008                reset,
 3009            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3010            SelectPhase::Extend {
 3011                position,
 3012                click_count,
 3013            } => self.extend_selection(position, click_count, window, cx),
 3014            SelectPhase::Update {
 3015                position,
 3016                goal_column,
 3017                scroll_delta,
 3018            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3019            SelectPhase::End => self.end_selection(window, cx),
 3020        }
 3021    }
 3022
 3023    fn extend_selection(
 3024        &mut self,
 3025        position: DisplayPoint,
 3026        click_count: usize,
 3027        window: &mut Window,
 3028        cx: &mut Context<Self>,
 3029    ) {
 3030        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3031        let tail = self.selections.newest::<usize>(cx).tail();
 3032        self.begin_selection(position, false, click_count, window, cx);
 3033
 3034        let position = position.to_offset(&display_map, Bias::Left);
 3035        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3036
 3037        let mut pending_selection = self
 3038            .selections
 3039            .pending_anchor()
 3040            .expect("extend_selection not called with pending selection");
 3041        if position >= tail {
 3042            pending_selection.start = tail_anchor;
 3043        } else {
 3044            pending_selection.end = tail_anchor;
 3045            pending_selection.reversed = true;
 3046        }
 3047
 3048        let mut pending_mode = self.selections.pending_mode().unwrap();
 3049        match &mut pending_mode {
 3050            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3051            _ => {}
 3052        }
 3053
 3054        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3055
 3056        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3057            s.set_pending(pending_selection, pending_mode)
 3058        });
 3059    }
 3060
 3061    fn begin_selection(
 3062        &mut self,
 3063        position: DisplayPoint,
 3064        add: bool,
 3065        click_count: usize,
 3066        window: &mut Window,
 3067        cx: &mut Context<Self>,
 3068    ) {
 3069        if !self.focus_handle.is_focused(window) {
 3070            self.last_focused_descendant = None;
 3071            window.focus(&self.focus_handle);
 3072        }
 3073
 3074        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3075        let buffer = &display_map.buffer_snapshot;
 3076        let position = display_map.clip_point(position, Bias::Left);
 3077
 3078        let start;
 3079        let end;
 3080        let mode;
 3081        let mut auto_scroll;
 3082        match click_count {
 3083            1 => {
 3084                start = buffer.anchor_before(position.to_point(&display_map));
 3085                end = start;
 3086                mode = SelectMode::Character;
 3087                auto_scroll = true;
 3088            }
 3089            2 => {
 3090                let range = movement::surrounding_word(&display_map, position);
 3091                start = buffer.anchor_before(range.start.to_point(&display_map));
 3092                end = buffer.anchor_before(range.end.to_point(&display_map));
 3093                mode = SelectMode::Word(start..end);
 3094                auto_scroll = true;
 3095            }
 3096            3 => {
 3097                let position = display_map
 3098                    .clip_point(position, Bias::Left)
 3099                    .to_point(&display_map);
 3100                let line_start = display_map.prev_line_boundary(position).0;
 3101                let next_line_start = buffer.clip_point(
 3102                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3103                    Bias::Left,
 3104                );
 3105                start = buffer.anchor_before(line_start);
 3106                end = buffer.anchor_before(next_line_start);
 3107                mode = SelectMode::Line(start..end);
 3108                auto_scroll = true;
 3109            }
 3110            _ => {
 3111                start = buffer.anchor_before(0);
 3112                end = buffer.anchor_before(buffer.len());
 3113                mode = SelectMode::All;
 3114                auto_scroll = false;
 3115            }
 3116        }
 3117        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3118
 3119        let point_to_delete: Option<usize> = {
 3120            let selected_points: Vec<Selection<Point>> =
 3121                self.selections.disjoint_in_range(start..end, cx);
 3122
 3123            if !add || click_count > 1 {
 3124                None
 3125            } else if !selected_points.is_empty() {
 3126                Some(selected_points[0].id)
 3127            } else {
 3128                let clicked_point_already_selected =
 3129                    self.selections.disjoint.iter().find(|selection| {
 3130                        selection.start.to_point(buffer) == start.to_point(buffer)
 3131                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3132                    });
 3133
 3134                clicked_point_already_selected.map(|selection| selection.id)
 3135            }
 3136        };
 3137
 3138        let selections_count = self.selections.count();
 3139
 3140        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3141            if let Some(point_to_delete) = point_to_delete {
 3142                s.delete(point_to_delete);
 3143
 3144                if selections_count == 1 {
 3145                    s.set_pending_anchor_range(start..end, mode);
 3146                }
 3147            } else {
 3148                if !add {
 3149                    s.clear_disjoint();
 3150                }
 3151
 3152                s.set_pending_anchor_range(start..end, mode);
 3153            }
 3154        });
 3155    }
 3156
 3157    fn begin_columnar_selection(
 3158        &mut self,
 3159        position: DisplayPoint,
 3160        goal_column: u32,
 3161        reset: bool,
 3162        window: &mut Window,
 3163        cx: &mut Context<Self>,
 3164    ) {
 3165        if !self.focus_handle.is_focused(window) {
 3166            self.last_focused_descendant = None;
 3167            window.focus(&self.focus_handle);
 3168        }
 3169
 3170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3171
 3172        if reset {
 3173            let pointer_position = display_map
 3174                .buffer_snapshot
 3175                .anchor_before(position.to_point(&display_map));
 3176
 3177            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3178                s.clear_disjoint();
 3179                s.set_pending_anchor_range(
 3180                    pointer_position..pointer_position,
 3181                    SelectMode::Character,
 3182                );
 3183            });
 3184        }
 3185
 3186        let tail = self.selections.newest::<Point>(cx).tail();
 3187        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3188
 3189        if !reset {
 3190            self.select_columns(
 3191                tail.to_display_point(&display_map),
 3192                position,
 3193                goal_column,
 3194                &display_map,
 3195                window,
 3196                cx,
 3197            );
 3198        }
 3199    }
 3200
 3201    fn update_selection(
 3202        &mut self,
 3203        position: DisplayPoint,
 3204        goal_column: u32,
 3205        scroll_delta: gpui::Point<f32>,
 3206        window: &mut Window,
 3207        cx: &mut Context<Self>,
 3208    ) {
 3209        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3210
 3211        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3212            let tail = tail.to_display_point(&display_map);
 3213            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3214        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3215            let buffer = self.buffer.read(cx).snapshot(cx);
 3216            let head;
 3217            let tail;
 3218            let mode = self.selections.pending_mode().unwrap();
 3219            match &mode {
 3220                SelectMode::Character => {
 3221                    head = position.to_point(&display_map);
 3222                    tail = pending.tail().to_point(&buffer);
 3223                }
 3224                SelectMode::Word(original_range) => {
 3225                    let original_display_range = original_range.start.to_display_point(&display_map)
 3226                        ..original_range.end.to_display_point(&display_map);
 3227                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3228                        ..original_display_range.end.to_point(&display_map);
 3229                    if movement::is_inside_word(&display_map, position)
 3230                        || original_display_range.contains(&position)
 3231                    {
 3232                        let word_range = movement::surrounding_word(&display_map, position);
 3233                        if word_range.start < original_display_range.start {
 3234                            head = word_range.start.to_point(&display_map);
 3235                        } else {
 3236                            head = word_range.end.to_point(&display_map);
 3237                        }
 3238                    } else {
 3239                        head = position.to_point(&display_map);
 3240                    }
 3241
 3242                    if head <= original_buffer_range.start {
 3243                        tail = original_buffer_range.end;
 3244                    } else {
 3245                        tail = original_buffer_range.start;
 3246                    }
 3247                }
 3248                SelectMode::Line(original_range) => {
 3249                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3250
 3251                    let position = display_map
 3252                        .clip_point(position, Bias::Left)
 3253                        .to_point(&display_map);
 3254                    let line_start = display_map.prev_line_boundary(position).0;
 3255                    let next_line_start = buffer.clip_point(
 3256                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3257                        Bias::Left,
 3258                    );
 3259
 3260                    if line_start < original_range.start {
 3261                        head = line_start
 3262                    } else {
 3263                        head = next_line_start
 3264                    }
 3265
 3266                    if head <= original_range.start {
 3267                        tail = original_range.end;
 3268                    } else {
 3269                        tail = original_range.start;
 3270                    }
 3271                }
 3272                SelectMode::All => {
 3273                    return;
 3274                }
 3275            };
 3276
 3277            if head < tail {
 3278                pending.start = buffer.anchor_before(head);
 3279                pending.end = buffer.anchor_before(tail);
 3280                pending.reversed = true;
 3281            } else {
 3282                pending.start = buffer.anchor_before(tail);
 3283                pending.end = buffer.anchor_before(head);
 3284                pending.reversed = false;
 3285            }
 3286
 3287            self.change_selections(None, window, cx, |s| {
 3288                s.set_pending(pending, mode);
 3289            });
 3290        } else {
 3291            log::error!("update_selection dispatched with no pending selection");
 3292            return;
 3293        }
 3294
 3295        self.apply_scroll_delta(scroll_delta, window, cx);
 3296        cx.notify();
 3297    }
 3298
 3299    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3300        self.columnar_selection_tail.take();
 3301        if self.selections.pending_anchor().is_some() {
 3302            let selections = self.selections.all::<usize>(cx);
 3303            self.change_selections(None, window, cx, |s| {
 3304                s.select(selections);
 3305                s.clear_pending();
 3306            });
 3307        }
 3308    }
 3309
 3310    fn select_columns(
 3311        &mut self,
 3312        tail: DisplayPoint,
 3313        head: DisplayPoint,
 3314        goal_column: u32,
 3315        display_map: &DisplaySnapshot,
 3316        window: &mut Window,
 3317        cx: &mut Context<Self>,
 3318    ) {
 3319        let start_row = cmp::min(tail.row(), head.row());
 3320        let end_row = cmp::max(tail.row(), head.row());
 3321        let start_column = cmp::min(tail.column(), goal_column);
 3322        let end_column = cmp::max(tail.column(), goal_column);
 3323        let reversed = start_column < tail.column();
 3324
 3325        let selection_ranges = (start_row.0..=end_row.0)
 3326            .map(DisplayRow)
 3327            .filter_map(|row| {
 3328                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3329                    let start = display_map
 3330                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3331                        .to_point(display_map);
 3332                    let end = display_map
 3333                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3334                        .to_point(display_map);
 3335                    if reversed {
 3336                        Some(end..start)
 3337                    } else {
 3338                        Some(start..end)
 3339                    }
 3340                } else {
 3341                    None
 3342                }
 3343            })
 3344            .collect::<Vec<_>>();
 3345
 3346        self.change_selections(None, window, cx, |s| {
 3347            s.select_ranges(selection_ranges);
 3348        });
 3349        cx.notify();
 3350    }
 3351
 3352    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3353        self.selections
 3354            .all_adjusted(cx)
 3355            .iter()
 3356            .any(|selection| !selection.is_empty())
 3357    }
 3358
 3359    pub fn has_pending_nonempty_selection(&self) -> bool {
 3360        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3361            Some(Selection { start, end, .. }) => start != end,
 3362            None => false,
 3363        };
 3364
 3365        pending_nonempty_selection
 3366            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3367    }
 3368
 3369    pub fn has_pending_selection(&self) -> bool {
 3370        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3371    }
 3372
 3373    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3374        self.selection_mark_mode = false;
 3375
 3376        if self.clear_expanded_diff_hunks(cx) {
 3377            cx.notify();
 3378            return;
 3379        }
 3380        if self.dismiss_menus_and_popups(true, window, cx) {
 3381            return;
 3382        }
 3383
 3384        if self.mode.is_full()
 3385            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3386        {
 3387            return;
 3388        }
 3389
 3390        cx.propagate();
 3391    }
 3392
 3393    pub fn dismiss_menus_and_popups(
 3394        &mut self,
 3395        is_user_requested: bool,
 3396        window: &mut Window,
 3397        cx: &mut Context<Self>,
 3398    ) -> bool {
 3399        if self.take_rename(false, window, cx).is_some() {
 3400            return true;
 3401        }
 3402
 3403        if hide_hover(self, cx) {
 3404            return true;
 3405        }
 3406
 3407        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3408            return true;
 3409        }
 3410
 3411        if self.hide_context_menu(window, cx).is_some() {
 3412            return true;
 3413        }
 3414
 3415        if self.mouse_context_menu.take().is_some() {
 3416            return true;
 3417        }
 3418
 3419        if is_user_requested && self.discard_inline_completion(true, cx) {
 3420            return true;
 3421        }
 3422
 3423        if self.snippet_stack.pop().is_some() {
 3424            return true;
 3425        }
 3426
 3427        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3428            self.dismiss_diagnostics(cx);
 3429            return true;
 3430        }
 3431
 3432        false
 3433    }
 3434
 3435    fn linked_editing_ranges_for(
 3436        &self,
 3437        selection: Range<text::Anchor>,
 3438        cx: &App,
 3439    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3440        if self.linked_edit_ranges.is_empty() {
 3441            return None;
 3442        }
 3443        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3444            selection.end.buffer_id.and_then(|end_buffer_id| {
 3445                if selection.start.buffer_id != Some(end_buffer_id) {
 3446                    return None;
 3447                }
 3448                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3449                let snapshot = buffer.read(cx).snapshot();
 3450                self.linked_edit_ranges
 3451                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3452                    .map(|ranges| (ranges, snapshot, buffer))
 3453            })?;
 3454        use text::ToOffset as TO;
 3455        // find offset from the start of current range to current cursor position
 3456        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3457
 3458        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3459        let start_difference = start_offset - start_byte_offset;
 3460        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3461        let end_difference = end_offset - start_byte_offset;
 3462        // Current range has associated linked ranges.
 3463        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3464        for range in linked_ranges.iter() {
 3465            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3466            let end_offset = start_offset + end_difference;
 3467            let start_offset = start_offset + start_difference;
 3468            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3469                continue;
 3470            }
 3471            if self.selections.disjoint_anchor_ranges().any(|s| {
 3472                if s.start.buffer_id != selection.start.buffer_id
 3473                    || s.end.buffer_id != selection.end.buffer_id
 3474                {
 3475                    return false;
 3476                }
 3477                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3478                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3479            }) {
 3480                continue;
 3481            }
 3482            let start = buffer_snapshot.anchor_after(start_offset);
 3483            let end = buffer_snapshot.anchor_after(end_offset);
 3484            linked_edits
 3485                .entry(buffer.clone())
 3486                .or_default()
 3487                .push(start..end);
 3488        }
 3489        Some(linked_edits)
 3490    }
 3491
 3492    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3493        let text: Arc<str> = text.into();
 3494
 3495        if self.read_only(cx) {
 3496            return;
 3497        }
 3498
 3499        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3500
 3501        let selections = self.selections.all_adjusted(cx);
 3502        let mut bracket_inserted = false;
 3503        let mut edits = Vec::new();
 3504        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3505        let mut new_selections = Vec::with_capacity(selections.len());
 3506        let mut new_autoclose_regions = Vec::new();
 3507        let snapshot = self.buffer.read(cx).read(cx);
 3508        let mut clear_linked_edit_ranges = false;
 3509
 3510        for (selection, autoclose_region) in
 3511            self.selections_with_autoclose_regions(selections, &snapshot)
 3512        {
 3513            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3514                // Determine if the inserted text matches the opening or closing
 3515                // bracket of any of this language's bracket pairs.
 3516                let mut bracket_pair = None;
 3517                let mut is_bracket_pair_start = false;
 3518                let mut is_bracket_pair_end = false;
 3519                if !text.is_empty() {
 3520                    let mut bracket_pair_matching_end = None;
 3521                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3522                    //  and they are removing the character that triggered IME popup.
 3523                    for (pair, enabled) in scope.brackets() {
 3524                        if !pair.close && !pair.surround {
 3525                            continue;
 3526                        }
 3527
 3528                        if enabled && pair.start.ends_with(text.as_ref()) {
 3529                            let prefix_len = pair.start.len() - text.len();
 3530                            let preceding_text_matches_prefix = prefix_len == 0
 3531                                || (selection.start.column >= (prefix_len as u32)
 3532                                    && snapshot.contains_str_at(
 3533                                        Point::new(
 3534                                            selection.start.row,
 3535                                            selection.start.column - (prefix_len as u32),
 3536                                        ),
 3537                                        &pair.start[..prefix_len],
 3538                                    ));
 3539                            if preceding_text_matches_prefix {
 3540                                bracket_pair = Some(pair.clone());
 3541                                is_bracket_pair_start = true;
 3542                                break;
 3543                            }
 3544                        }
 3545                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3546                        {
 3547                            // take first bracket pair matching end, but don't break in case a later bracket
 3548                            // pair matches start
 3549                            bracket_pair_matching_end = Some(pair.clone());
 3550                        }
 3551                    }
 3552                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3553                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3554                        is_bracket_pair_end = true;
 3555                    }
 3556                }
 3557
 3558                if let Some(bracket_pair) = bracket_pair {
 3559                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3560                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3561                    let auto_surround =
 3562                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3563                    if selection.is_empty() {
 3564                        if is_bracket_pair_start {
 3565                            // If the inserted text is a suffix of an opening bracket and the
 3566                            // selection is preceded by the rest of the opening bracket, then
 3567                            // insert the closing bracket.
 3568                            let following_text_allows_autoclose = snapshot
 3569                                .chars_at(selection.start)
 3570                                .next()
 3571                                .map_or(true, |c| scope.should_autoclose_before(c));
 3572
 3573                            let preceding_text_allows_autoclose = selection.start.column == 0
 3574                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3575                                    true,
 3576                                    |c| {
 3577                                        bracket_pair.start != bracket_pair.end
 3578                                            || !snapshot
 3579                                                .char_classifier_at(selection.start)
 3580                                                .is_word(c)
 3581                                    },
 3582                                );
 3583
 3584                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3585                                && bracket_pair.start.len() == 1
 3586                            {
 3587                                let target = bracket_pair.start.chars().next().unwrap();
 3588                                let current_line_count = snapshot
 3589                                    .reversed_chars_at(selection.start)
 3590                                    .take_while(|&c| c != '\n')
 3591                                    .filter(|&c| c == target)
 3592                                    .count();
 3593                                current_line_count % 2 == 1
 3594                            } else {
 3595                                false
 3596                            };
 3597
 3598                            if autoclose
 3599                                && bracket_pair.close
 3600                                && following_text_allows_autoclose
 3601                                && preceding_text_allows_autoclose
 3602                                && !is_closing_quote
 3603                            {
 3604                                let anchor = snapshot.anchor_before(selection.end);
 3605                                new_selections.push((selection.map(|_| anchor), text.len()));
 3606                                new_autoclose_regions.push((
 3607                                    anchor,
 3608                                    text.len(),
 3609                                    selection.id,
 3610                                    bracket_pair.clone(),
 3611                                ));
 3612                                edits.push((
 3613                                    selection.range(),
 3614                                    format!("{}{}", text, bracket_pair.end).into(),
 3615                                ));
 3616                                bracket_inserted = true;
 3617                                continue;
 3618                            }
 3619                        }
 3620
 3621                        if let Some(region) = autoclose_region {
 3622                            // If the selection is followed by an auto-inserted closing bracket,
 3623                            // then don't insert that closing bracket again; just move the selection
 3624                            // past the closing bracket.
 3625                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3626                                && text.as_ref() == region.pair.end.as_str();
 3627                            if should_skip {
 3628                                let anchor = snapshot.anchor_after(selection.end);
 3629                                new_selections
 3630                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3631                                continue;
 3632                            }
 3633                        }
 3634
 3635                        let always_treat_brackets_as_autoclosed = snapshot
 3636                            .language_settings_at(selection.start, cx)
 3637                            .always_treat_brackets_as_autoclosed;
 3638                        if always_treat_brackets_as_autoclosed
 3639                            && is_bracket_pair_end
 3640                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3641                        {
 3642                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3643                            // and the inserted text is a closing bracket and the selection is followed
 3644                            // by the closing bracket then move the selection past the closing bracket.
 3645                            let anchor = snapshot.anchor_after(selection.end);
 3646                            new_selections.push((selection.map(|_| anchor), text.len()));
 3647                            continue;
 3648                        }
 3649                    }
 3650                    // If an opening bracket is 1 character long and is typed while
 3651                    // text is selected, then surround that text with the bracket pair.
 3652                    else if auto_surround
 3653                        && bracket_pair.surround
 3654                        && is_bracket_pair_start
 3655                        && bracket_pair.start.chars().count() == 1
 3656                    {
 3657                        edits.push((selection.start..selection.start, text.clone()));
 3658                        edits.push((
 3659                            selection.end..selection.end,
 3660                            bracket_pair.end.as_str().into(),
 3661                        ));
 3662                        bracket_inserted = true;
 3663                        new_selections.push((
 3664                            Selection {
 3665                                id: selection.id,
 3666                                start: snapshot.anchor_after(selection.start),
 3667                                end: snapshot.anchor_before(selection.end),
 3668                                reversed: selection.reversed,
 3669                                goal: selection.goal,
 3670                            },
 3671                            0,
 3672                        ));
 3673                        continue;
 3674                    }
 3675                }
 3676            }
 3677
 3678            if self.auto_replace_emoji_shortcode
 3679                && selection.is_empty()
 3680                && text.as_ref().ends_with(':')
 3681            {
 3682                if let Some(possible_emoji_short_code) =
 3683                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3684                {
 3685                    if !possible_emoji_short_code.is_empty() {
 3686                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3687                            let emoji_shortcode_start = Point::new(
 3688                                selection.start.row,
 3689                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3690                            );
 3691
 3692                            // Remove shortcode from buffer
 3693                            edits.push((
 3694                                emoji_shortcode_start..selection.start,
 3695                                "".to_string().into(),
 3696                            ));
 3697                            new_selections.push((
 3698                                Selection {
 3699                                    id: selection.id,
 3700                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3701                                    end: snapshot.anchor_before(selection.start),
 3702                                    reversed: selection.reversed,
 3703                                    goal: selection.goal,
 3704                                },
 3705                                0,
 3706                            ));
 3707
 3708                            // Insert emoji
 3709                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3710                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3711                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3712
 3713                            continue;
 3714                        }
 3715                    }
 3716                }
 3717            }
 3718
 3719            // If not handling any auto-close operation, then just replace the selected
 3720            // text with the given input and move the selection to the end of the
 3721            // newly inserted text.
 3722            let anchor = snapshot.anchor_after(selection.end);
 3723            if !self.linked_edit_ranges.is_empty() {
 3724                let start_anchor = snapshot.anchor_before(selection.start);
 3725
 3726                let is_word_char = text.chars().next().map_or(true, |char| {
 3727                    let classifier = snapshot
 3728                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3729                        .ignore_punctuation(true);
 3730                    classifier.is_word(char)
 3731                });
 3732
 3733                if is_word_char {
 3734                    if let Some(ranges) = self
 3735                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3736                    {
 3737                        for (buffer, edits) in ranges {
 3738                            linked_edits
 3739                                .entry(buffer.clone())
 3740                                .or_default()
 3741                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3742                        }
 3743                    }
 3744                } else {
 3745                    clear_linked_edit_ranges = true;
 3746                }
 3747            }
 3748
 3749            new_selections.push((selection.map(|_| anchor), 0));
 3750            edits.push((selection.start..selection.end, text.clone()));
 3751        }
 3752
 3753        drop(snapshot);
 3754
 3755        self.transact(window, cx, |this, window, cx| {
 3756            if clear_linked_edit_ranges {
 3757                this.linked_edit_ranges.clear();
 3758            }
 3759            let initial_buffer_versions =
 3760                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3761
 3762            this.buffer.update(cx, |buffer, cx| {
 3763                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3764            });
 3765            for (buffer, edits) in linked_edits {
 3766                buffer.update(cx, |buffer, cx| {
 3767                    let snapshot = buffer.snapshot();
 3768                    let edits = edits
 3769                        .into_iter()
 3770                        .map(|(range, text)| {
 3771                            use text::ToPoint as TP;
 3772                            let end_point = TP::to_point(&range.end, &snapshot);
 3773                            let start_point = TP::to_point(&range.start, &snapshot);
 3774                            (start_point..end_point, text)
 3775                        })
 3776                        .sorted_by_key(|(range, _)| range.start);
 3777                    buffer.edit(edits, None, cx);
 3778                })
 3779            }
 3780            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3781            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3782            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3783            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3784                .zip(new_selection_deltas)
 3785                .map(|(selection, delta)| Selection {
 3786                    id: selection.id,
 3787                    start: selection.start + delta,
 3788                    end: selection.end + delta,
 3789                    reversed: selection.reversed,
 3790                    goal: SelectionGoal::None,
 3791                })
 3792                .collect::<Vec<_>>();
 3793
 3794            let mut i = 0;
 3795            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3796                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3797                let start = map.buffer_snapshot.anchor_before(position);
 3798                let end = map.buffer_snapshot.anchor_after(position);
 3799                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3800                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3801                        Ordering::Less => i += 1,
 3802                        Ordering::Greater => break,
 3803                        Ordering::Equal => {
 3804                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3805                                Ordering::Less => i += 1,
 3806                                Ordering::Equal => break,
 3807                                Ordering::Greater => break,
 3808                            }
 3809                        }
 3810                    }
 3811                }
 3812                this.autoclose_regions.insert(
 3813                    i,
 3814                    AutocloseRegion {
 3815                        selection_id,
 3816                        range: start..end,
 3817                        pair,
 3818                    },
 3819                );
 3820            }
 3821
 3822            let had_active_inline_completion = this.has_active_inline_completion();
 3823            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3824                s.select(new_selections)
 3825            });
 3826
 3827            if !bracket_inserted {
 3828                if let Some(on_type_format_task) =
 3829                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3830                {
 3831                    on_type_format_task.detach_and_log_err(cx);
 3832                }
 3833            }
 3834
 3835            let editor_settings = EditorSettings::get_global(cx);
 3836            if bracket_inserted
 3837                && (editor_settings.auto_signature_help
 3838                    || editor_settings.show_signature_help_after_edits)
 3839            {
 3840                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3841            }
 3842
 3843            let trigger_in_words =
 3844                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3845            if this.hard_wrap.is_some() {
 3846                let latest: Range<Point> = this.selections.newest(cx).range();
 3847                if latest.is_empty()
 3848                    && this
 3849                        .buffer()
 3850                        .read(cx)
 3851                        .snapshot(cx)
 3852                        .line_len(MultiBufferRow(latest.start.row))
 3853                        == latest.start.column
 3854                {
 3855                    this.rewrap_impl(
 3856                        RewrapOptions {
 3857                            override_language_settings: true,
 3858                            preserve_existing_whitespace: true,
 3859                        },
 3860                        cx,
 3861                    )
 3862                }
 3863            }
 3864            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3865            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3866            this.refresh_inline_completion(true, false, window, cx);
 3867            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3868        });
 3869    }
 3870
 3871    fn find_possible_emoji_shortcode_at_position(
 3872        snapshot: &MultiBufferSnapshot,
 3873        position: Point,
 3874    ) -> Option<String> {
 3875        let mut chars = Vec::new();
 3876        let mut found_colon = false;
 3877        for char in snapshot.reversed_chars_at(position).take(100) {
 3878            // Found a possible emoji shortcode in the middle of the buffer
 3879            if found_colon {
 3880                if char.is_whitespace() {
 3881                    chars.reverse();
 3882                    return Some(chars.iter().collect());
 3883                }
 3884                // If the previous character is not a whitespace, we are in the middle of a word
 3885                // and we only want to complete the shortcode if the word is made up of other emojis
 3886                let mut containing_word = String::new();
 3887                for ch in snapshot
 3888                    .reversed_chars_at(position)
 3889                    .skip(chars.len() + 1)
 3890                    .take(100)
 3891                {
 3892                    if ch.is_whitespace() {
 3893                        break;
 3894                    }
 3895                    containing_word.push(ch);
 3896                }
 3897                let containing_word = containing_word.chars().rev().collect::<String>();
 3898                if util::word_consists_of_emojis(containing_word.as_str()) {
 3899                    chars.reverse();
 3900                    return Some(chars.iter().collect());
 3901                }
 3902            }
 3903
 3904            if char.is_whitespace() || !char.is_ascii() {
 3905                return None;
 3906            }
 3907            if char == ':' {
 3908                found_colon = true;
 3909            } else {
 3910                chars.push(char);
 3911            }
 3912        }
 3913        // Found a possible emoji shortcode at the beginning of the buffer
 3914        chars.reverse();
 3915        Some(chars.iter().collect())
 3916    }
 3917
 3918    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3919        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3920        self.transact(window, cx, |this, window, cx| {
 3921            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3922                let selections = this.selections.all::<usize>(cx);
 3923                let multi_buffer = this.buffer.read(cx);
 3924                let buffer = multi_buffer.snapshot(cx);
 3925                selections
 3926                    .iter()
 3927                    .map(|selection| {
 3928                        let start_point = selection.start.to_point(&buffer);
 3929                        let mut existing_indent =
 3930                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3931                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3932                        let start = selection.start;
 3933                        let end = selection.end;
 3934                        let selection_is_empty = start == end;
 3935                        let language_scope = buffer.language_scope_at(start);
 3936                        let (
 3937                            comment_delimiter,
 3938                            doc_delimiter,
 3939                            insert_extra_newline,
 3940                            indent_on_newline,
 3941                            indent_on_extra_newline,
 3942                        ) = if let Some(language) = &language_scope {
 3943                            let mut insert_extra_newline =
 3944                                insert_extra_newline_brackets(&buffer, start..end, language)
 3945                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3946
 3947                            // Comment extension on newline is allowed only for cursor selections
 3948                            let comment_delimiter = maybe!({
 3949                                if !selection_is_empty {
 3950                                    return None;
 3951                                }
 3952
 3953                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3954                                    return None;
 3955                                }
 3956
 3957                                let delimiters = language.line_comment_prefixes();
 3958                                let max_len_of_delimiter =
 3959                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3960                                let (snapshot, range) =
 3961                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3962
 3963                                let num_of_whitespaces = snapshot
 3964                                    .chars_for_range(range.clone())
 3965                                    .take_while(|c| c.is_whitespace())
 3966                                    .count();
 3967                                let comment_candidate = snapshot
 3968                                    .chars_for_range(range)
 3969                                    .skip(num_of_whitespaces)
 3970                                    .take(max_len_of_delimiter)
 3971                                    .collect::<String>();
 3972                                let (delimiter, trimmed_len) = delimiters
 3973                                    .iter()
 3974                                    .filter_map(|delimiter| {
 3975                                        let prefix = delimiter.trim_end();
 3976                                        if comment_candidate.starts_with(prefix) {
 3977                                            Some((delimiter, prefix.len()))
 3978                                        } else {
 3979                                            None
 3980                                        }
 3981                                    })
 3982                                    .max_by_key(|(_, len)| *len)?;
 3983
 3984                                let cursor_is_placed_after_comment_marker =
 3985                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3986                                if cursor_is_placed_after_comment_marker {
 3987                                    Some(delimiter.clone())
 3988                                } else {
 3989                                    None
 3990                                }
 3991                            });
 3992
 3993                            let mut indent_on_newline = IndentSize::spaces(0);
 3994                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3995
 3996                            let doc_delimiter = maybe!({
 3997                                if !selection_is_empty {
 3998                                    return None;
 3999                                }
 4000
 4001                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4002                                    return None;
 4003                                }
 4004
 4005                                let DocumentationConfig {
 4006                                    start: start_tag,
 4007                                    end: end_tag,
 4008                                    prefix: delimiter,
 4009                                    tab_size: len,
 4010                                } = language.documentation()?;
 4011
 4012                                let is_within_block_comment = buffer
 4013                                    .language_scope_at(start_point)
 4014                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4015                                if !is_within_block_comment {
 4016                                    return None;
 4017                                }
 4018
 4019                                let (snapshot, range) =
 4020                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4021
 4022                                let num_of_whitespaces = snapshot
 4023                                    .chars_for_range(range.clone())
 4024                                    .take_while(|c| c.is_whitespace())
 4025                                    .count();
 4026
 4027                                // 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.
 4028                                let column = start_point.column;
 4029                                let cursor_is_after_start_tag = {
 4030                                    let start_tag_len = start_tag.len();
 4031                                    let start_tag_line = snapshot
 4032                                        .chars_for_range(range.clone())
 4033                                        .skip(num_of_whitespaces)
 4034                                        .take(start_tag_len)
 4035                                        .collect::<String>();
 4036                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4037                                        num_of_whitespaces + start_tag_len <= column as usize
 4038                                    } else {
 4039                                        false
 4040                                    }
 4041                                };
 4042
 4043                                let cursor_is_after_delimiter = {
 4044                                    let delimiter_trim = delimiter.trim_end();
 4045                                    let delimiter_line = snapshot
 4046                                        .chars_for_range(range.clone())
 4047                                        .skip(num_of_whitespaces)
 4048                                        .take(delimiter_trim.len())
 4049                                        .collect::<String>();
 4050                                    if delimiter_line.starts_with(delimiter_trim) {
 4051                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4052                                    } else {
 4053                                        false
 4054                                    }
 4055                                };
 4056
 4057                                let cursor_is_before_end_tag_if_exists = {
 4058                                    let mut char_position = 0u32;
 4059                                    let mut end_tag_offset = None;
 4060
 4061                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4062                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4063                                            let chars_before_match =
 4064                                                chunk[..byte_pos].chars().count() as u32;
 4065                                            end_tag_offset =
 4066                                                Some(char_position + chars_before_match);
 4067                                            break 'outer;
 4068                                        }
 4069                                        char_position += chunk.chars().count() as u32;
 4070                                    }
 4071
 4072                                    if let Some(end_tag_offset) = end_tag_offset {
 4073                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4074                                        if cursor_is_after_start_tag {
 4075                                            if cursor_is_before_end_tag {
 4076                                                insert_extra_newline = true;
 4077                                            }
 4078                                            let cursor_is_at_start_of_end_tag =
 4079                                                column == end_tag_offset;
 4080                                            if cursor_is_at_start_of_end_tag {
 4081                                                indent_on_extra_newline.len = (*len).into();
 4082                                            }
 4083                                        }
 4084                                        cursor_is_before_end_tag
 4085                                    } else {
 4086                                        true
 4087                                    }
 4088                                };
 4089
 4090                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4091                                    && cursor_is_before_end_tag_if_exists
 4092                                {
 4093                                    if cursor_is_after_start_tag {
 4094                                        indent_on_newline.len = (*len).into();
 4095                                    }
 4096                                    Some(delimiter.clone())
 4097                                } else {
 4098                                    None
 4099                                }
 4100                            });
 4101
 4102                            (
 4103                                comment_delimiter,
 4104                                doc_delimiter,
 4105                                insert_extra_newline,
 4106                                indent_on_newline,
 4107                                indent_on_extra_newline,
 4108                            )
 4109                        } else {
 4110                            (
 4111                                None,
 4112                                None,
 4113                                false,
 4114                                IndentSize::default(),
 4115                                IndentSize::default(),
 4116                            )
 4117                        };
 4118
 4119                        let prevent_auto_indent = doc_delimiter.is_some();
 4120                        let delimiter = comment_delimiter.or(doc_delimiter);
 4121
 4122                        let capacity_for_delimiter =
 4123                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4124                        let mut new_text = String::with_capacity(
 4125                            1 + capacity_for_delimiter
 4126                                + existing_indent.len as usize
 4127                                + indent_on_newline.len as usize
 4128                                + indent_on_extra_newline.len as usize,
 4129                        );
 4130                        new_text.push('\n');
 4131                        new_text.extend(existing_indent.chars());
 4132                        new_text.extend(indent_on_newline.chars());
 4133
 4134                        if let Some(delimiter) = &delimiter {
 4135                            new_text.push_str(delimiter);
 4136                        }
 4137
 4138                        if insert_extra_newline {
 4139                            new_text.push('\n');
 4140                            new_text.extend(existing_indent.chars());
 4141                            new_text.extend(indent_on_extra_newline.chars());
 4142                        }
 4143
 4144                        let anchor = buffer.anchor_after(end);
 4145                        let new_selection = selection.map(|_| anchor);
 4146                        (
 4147                            ((start..end, new_text), prevent_auto_indent),
 4148                            (insert_extra_newline, new_selection),
 4149                        )
 4150                    })
 4151                    .unzip()
 4152            };
 4153
 4154            let mut auto_indent_edits = Vec::new();
 4155            let mut edits = Vec::new();
 4156            for (edit, prevent_auto_indent) in edits_with_flags {
 4157                if prevent_auto_indent {
 4158                    edits.push(edit);
 4159                } else {
 4160                    auto_indent_edits.push(edit);
 4161                }
 4162            }
 4163            if !edits.is_empty() {
 4164                this.edit(edits, cx);
 4165            }
 4166            if !auto_indent_edits.is_empty() {
 4167                this.edit_with_autoindent(auto_indent_edits, cx);
 4168            }
 4169
 4170            let buffer = this.buffer.read(cx).snapshot(cx);
 4171            let new_selections = selection_info
 4172                .into_iter()
 4173                .map(|(extra_newline_inserted, new_selection)| {
 4174                    let mut cursor = new_selection.end.to_point(&buffer);
 4175                    if extra_newline_inserted {
 4176                        cursor.row -= 1;
 4177                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4178                    }
 4179                    new_selection.map(|_| cursor)
 4180                })
 4181                .collect();
 4182
 4183            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4184                s.select(new_selections)
 4185            });
 4186            this.refresh_inline_completion(true, false, window, cx);
 4187        });
 4188    }
 4189
 4190    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4191        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4192
 4193        let buffer = self.buffer.read(cx);
 4194        let snapshot = buffer.snapshot(cx);
 4195
 4196        let mut edits = Vec::new();
 4197        let mut rows = Vec::new();
 4198
 4199        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4200            let cursor = selection.head();
 4201            let row = cursor.row;
 4202
 4203            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4204
 4205            let newline = "\n".to_string();
 4206            edits.push((start_of_line..start_of_line, newline));
 4207
 4208            rows.push(row + rows_inserted as u32);
 4209        }
 4210
 4211        self.transact(window, cx, |editor, window, cx| {
 4212            editor.edit(edits, cx);
 4213
 4214            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4215                let mut index = 0;
 4216                s.move_cursors_with(|map, _, _| {
 4217                    let row = rows[index];
 4218                    index += 1;
 4219
 4220                    let point = Point::new(row, 0);
 4221                    let boundary = map.next_line_boundary(point).1;
 4222                    let clipped = map.clip_point(boundary, Bias::Left);
 4223
 4224                    (clipped, SelectionGoal::None)
 4225                });
 4226            });
 4227
 4228            let mut indent_edits = Vec::new();
 4229            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4230            for row in rows {
 4231                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4232                for (row, indent) in indents {
 4233                    if indent.len == 0 {
 4234                        continue;
 4235                    }
 4236
 4237                    let text = match indent.kind {
 4238                        IndentKind::Space => " ".repeat(indent.len as usize),
 4239                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4240                    };
 4241                    let point = Point::new(row.0, 0);
 4242                    indent_edits.push((point..point, text));
 4243                }
 4244            }
 4245            editor.edit(indent_edits, cx);
 4246        });
 4247    }
 4248
 4249    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4250        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4251
 4252        let buffer = self.buffer.read(cx);
 4253        let snapshot = buffer.snapshot(cx);
 4254
 4255        let mut edits = Vec::new();
 4256        let mut rows = Vec::new();
 4257        let mut rows_inserted = 0;
 4258
 4259        for selection in self.selections.all_adjusted(cx) {
 4260            let cursor = selection.head();
 4261            let row = cursor.row;
 4262
 4263            let point = Point::new(row + 1, 0);
 4264            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4265
 4266            let newline = "\n".to_string();
 4267            edits.push((start_of_line..start_of_line, newline));
 4268
 4269            rows_inserted += 1;
 4270            rows.push(row + rows_inserted);
 4271        }
 4272
 4273        self.transact(window, cx, |editor, window, cx| {
 4274            editor.edit(edits, cx);
 4275
 4276            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4277                let mut index = 0;
 4278                s.move_cursors_with(|map, _, _| {
 4279                    let row = rows[index];
 4280                    index += 1;
 4281
 4282                    let point = Point::new(row, 0);
 4283                    let boundary = map.next_line_boundary(point).1;
 4284                    let clipped = map.clip_point(boundary, Bias::Left);
 4285
 4286                    (clipped, SelectionGoal::None)
 4287                });
 4288            });
 4289
 4290            let mut indent_edits = Vec::new();
 4291            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4292            for row in rows {
 4293                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4294                for (row, indent) in indents {
 4295                    if indent.len == 0 {
 4296                        continue;
 4297                    }
 4298
 4299                    let text = match indent.kind {
 4300                        IndentKind::Space => " ".repeat(indent.len as usize),
 4301                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4302                    };
 4303                    let point = Point::new(row.0, 0);
 4304                    indent_edits.push((point..point, text));
 4305                }
 4306            }
 4307            editor.edit(indent_edits, cx);
 4308        });
 4309    }
 4310
 4311    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4312        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4313            original_indent_columns: Vec::new(),
 4314        });
 4315        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4316    }
 4317
 4318    fn insert_with_autoindent_mode(
 4319        &mut self,
 4320        text: &str,
 4321        autoindent_mode: Option<AutoindentMode>,
 4322        window: &mut Window,
 4323        cx: &mut Context<Self>,
 4324    ) {
 4325        if self.read_only(cx) {
 4326            return;
 4327        }
 4328
 4329        let text: Arc<str> = text.into();
 4330        self.transact(window, cx, |this, window, cx| {
 4331            let old_selections = this.selections.all_adjusted(cx);
 4332            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4333                let anchors = {
 4334                    let snapshot = buffer.read(cx);
 4335                    old_selections
 4336                        .iter()
 4337                        .map(|s| {
 4338                            let anchor = snapshot.anchor_after(s.head());
 4339                            s.map(|_| anchor)
 4340                        })
 4341                        .collect::<Vec<_>>()
 4342                };
 4343                buffer.edit(
 4344                    old_selections
 4345                        .iter()
 4346                        .map(|s| (s.start..s.end, text.clone())),
 4347                    autoindent_mode,
 4348                    cx,
 4349                );
 4350                anchors
 4351            });
 4352
 4353            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4354                s.select_anchors(selection_anchors);
 4355            });
 4356
 4357            cx.notify();
 4358        });
 4359    }
 4360
 4361    fn trigger_completion_on_input(
 4362        &mut self,
 4363        text: &str,
 4364        trigger_in_words: bool,
 4365        window: &mut Window,
 4366        cx: &mut Context<Self>,
 4367    ) {
 4368        let ignore_completion_provider = self
 4369            .context_menu
 4370            .borrow()
 4371            .as_ref()
 4372            .map(|menu| match menu {
 4373                CodeContextMenu::Completions(completions_menu) => {
 4374                    completions_menu.ignore_completion_provider
 4375                }
 4376                CodeContextMenu::CodeActions(_) => false,
 4377            })
 4378            .unwrap_or(false);
 4379
 4380        if ignore_completion_provider {
 4381            self.show_word_completions(&ShowWordCompletions, window, cx);
 4382        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4383            self.show_completions(
 4384                &ShowCompletions {
 4385                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4386                },
 4387                window,
 4388                cx,
 4389            );
 4390        } else {
 4391            self.hide_context_menu(window, cx);
 4392        }
 4393    }
 4394
 4395    fn is_completion_trigger(
 4396        &self,
 4397        text: &str,
 4398        trigger_in_words: bool,
 4399        cx: &mut Context<Self>,
 4400    ) -> bool {
 4401        let position = self.selections.newest_anchor().head();
 4402        let multibuffer = self.buffer.read(cx);
 4403        let Some(buffer) = position
 4404            .buffer_id
 4405            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4406        else {
 4407            return false;
 4408        };
 4409
 4410        if let Some(completion_provider) = &self.completion_provider {
 4411            completion_provider.is_completion_trigger(
 4412                &buffer,
 4413                position.text_anchor,
 4414                text,
 4415                trigger_in_words,
 4416                cx,
 4417            )
 4418        } else {
 4419            false
 4420        }
 4421    }
 4422
 4423    /// If any empty selections is touching the start of its innermost containing autoclose
 4424    /// region, expand it to select the brackets.
 4425    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4426        let selections = self.selections.all::<usize>(cx);
 4427        let buffer = self.buffer.read(cx).read(cx);
 4428        let new_selections = self
 4429            .selections_with_autoclose_regions(selections, &buffer)
 4430            .map(|(mut selection, region)| {
 4431                if !selection.is_empty() {
 4432                    return selection;
 4433                }
 4434
 4435                if let Some(region) = region {
 4436                    let mut range = region.range.to_offset(&buffer);
 4437                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4438                        range.start -= region.pair.start.len();
 4439                        if buffer.contains_str_at(range.start, &region.pair.start)
 4440                            && buffer.contains_str_at(range.end, &region.pair.end)
 4441                        {
 4442                            range.end += region.pair.end.len();
 4443                            selection.start = range.start;
 4444                            selection.end = range.end;
 4445
 4446                            return selection;
 4447                        }
 4448                    }
 4449                }
 4450
 4451                let always_treat_brackets_as_autoclosed = buffer
 4452                    .language_settings_at(selection.start, cx)
 4453                    .always_treat_brackets_as_autoclosed;
 4454
 4455                if !always_treat_brackets_as_autoclosed {
 4456                    return selection;
 4457                }
 4458
 4459                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4460                    for (pair, enabled) in scope.brackets() {
 4461                        if !enabled || !pair.close {
 4462                            continue;
 4463                        }
 4464
 4465                        if buffer.contains_str_at(selection.start, &pair.end) {
 4466                            let pair_start_len = pair.start.len();
 4467                            if buffer.contains_str_at(
 4468                                selection.start.saturating_sub(pair_start_len),
 4469                                &pair.start,
 4470                            ) {
 4471                                selection.start -= pair_start_len;
 4472                                selection.end += pair.end.len();
 4473
 4474                                return selection;
 4475                            }
 4476                        }
 4477                    }
 4478                }
 4479
 4480                selection
 4481            })
 4482            .collect();
 4483
 4484        drop(buffer);
 4485        self.change_selections(None, window, cx, |selections| {
 4486            selections.select(new_selections)
 4487        });
 4488    }
 4489
 4490    /// Iterate the given selections, and for each one, find the smallest surrounding
 4491    /// autoclose region. This uses the ordering of the selections and the autoclose
 4492    /// regions to avoid repeated comparisons.
 4493    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4494        &'a self,
 4495        selections: impl IntoIterator<Item = Selection<D>>,
 4496        buffer: &'a MultiBufferSnapshot,
 4497    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4498        let mut i = 0;
 4499        let mut regions = self.autoclose_regions.as_slice();
 4500        selections.into_iter().map(move |selection| {
 4501            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4502
 4503            let mut enclosing = None;
 4504            while let Some(pair_state) = regions.get(i) {
 4505                if pair_state.range.end.to_offset(buffer) < range.start {
 4506                    regions = &regions[i + 1..];
 4507                    i = 0;
 4508                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4509                    break;
 4510                } else {
 4511                    if pair_state.selection_id == selection.id {
 4512                        enclosing = Some(pair_state);
 4513                    }
 4514                    i += 1;
 4515                }
 4516            }
 4517
 4518            (selection, enclosing)
 4519        })
 4520    }
 4521
 4522    /// Remove any autoclose regions that no longer contain their selection.
 4523    fn invalidate_autoclose_regions(
 4524        &mut self,
 4525        mut selections: &[Selection<Anchor>],
 4526        buffer: &MultiBufferSnapshot,
 4527    ) {
 4528        self.autoclose_regions.retain(|state| {
 4529            let mut i = 0;
 4530            while let Some(selection) = selections.get(i) {
 4531                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4532                    selections = &selections[1..];
 4533                    continue;
 4534                }
 4535                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4536                    break;
 4537                }
 4538                if selection.id == state.selection_id {
 4539                    return true;
 4540                } else {
 4541                    i += 1;
 4542                }
 4543            }
 4544            false
 4545        });
 4546    }
 4547
 4548    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4549        let offset = position.to_offset(buffer);
 4550        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4551        if offset > word_range.start && kind == Some(CharKind::Word) {
 4552            Some(
 4553                buffer
 4554                    .text_for_range(word_range.start..offset)
 4555                    .collect::<String>(),
 4556            )
 4557        } else {
 4558            None
 4559        }
 4560    }
 4561
 4562    pub fn toggle_inline_values(
 4563        &mut self,
 4564        _: &ToggleInlineValues,
 4565        _: &mut Window,
 4566        cx: &mut Context<Self>,
 4567    ) {
 4568        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4569
 4570        self.refresh_inline_values(cx);
 4571    }
 4572
 4573    pub fn toggle_inlay_hints(
 4574        &mut self,
 4575        _: &ToggleInlayHints,
 4576        _: &mut Window,
 4577        cx: &mut Context<Self>,
 4578    ) {
 4579        self.refresh_inlay_hints(
 4580            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4581            cx,
 4582        );
 4583    }
 4584
 4585    pub fn inlay_hints_enabled(&self) -> bool {
 4586        self.inlay_hint_cache.enabled
 4587    }
 4588
 4589    pub fn inline_values_enabled(&self) -> bool {
 4590        self.inline_value_cache.enabled
 4591    }
 4592
 4593    #[cfg(any(test, feature = "test-support"))]
 4594    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4595        self.display_map
 4596            .read(cx)
 4597            .current_inlays()
 4598            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4599            .cloned()
 4600            .collect()
 4601    }
 4602
 4603    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4604        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4605            return;
 4606        }
 4607
 4608        let reason_description = reason.description();
 4609        let ignore_debounce = matches!(
 4610            reason,
 4611            InlayHintRefreshReason::SettingsChange(_)
 4612                | InlayHintRefreshReason::Toggle(_)
 4613                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4614                | InlayHintRefreshReason::ModifiersChanged(_)
 4615        );
 4616        let (invalidate_cache, required_languages) = match reason {
 4617            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4618                match self.inlay_hint_cache.modifiers_override(enabled) {
 4619                    Some(enabled) => {
 4620                        if enabled {
 4621                            (InvalidationStrategy::RefreshRequested, None)
 4622                        } else {
 4623                            self.splice_inlays(
 4624                                &self
 4625                                    .visible_inlay_hints(cx)
 4626                                    .iter()
 4627                                    .map(|inlay| inlay.id)
 4628                                    .collect::<Vec<InlayId>>(),
 4629                                Vec::new(),
 4630                                cx,
 4631                            );
 4632                            return;
 4633                        }
 4634                    }
 4635                    None => return,
 4636                }
 4637            }
 4638            InlayHintRefreshReason::Toggle(enabled) => {
 4639                if self.inlay_hint_cache.toggle(enabled) {
 4640                    if enabled {
 4641                        (InvalidationStrategy::RefreshRequested, None)
 4642                    } else {
 4643                        self.splice_inlays(
 4644                            &self
 4645                                .visible_inlay_hints(cx)
 4646                                .iter()
 4647                                .map(|inlay| inlay.id)
 4648                                .collect::<Vec<InlayId>>(),
 4649                            Vec::new(),
 4650                            cx,
 4651                        );
 4652                        return;
 4653                    }
 4654                } else {
 4655                    return;
 4656                }
 4657            }
 4658            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4659                match self.inlay_hint_cache.update_settings(
 4660                    &self.buffer,
 4661                    new_settings,
 4662                    self.visible_inlay_hints(cx),
 4663                    cx,
 4664                ) {
 4665                    ControlFlow::Break(Some(InlaySplice {
 4666                        to_remove,
 4667                        to_insert,
 4668                    })) => {
 4669                        self.splice_inlays(&to_remove, to_insert, cx);
 4670                        return;
 4671                    }
 4672                    ControlFlow::Break(None) => return,
 4673                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4674                }
 4675            }
 4676            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4677                if let Some(InlaySplice {
 4678                    to_remove,
 4679                    to_insert,
 4680                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4681                {
 4682                    self.splice_inlays(&to_remove, to_insert, cx);
 4683                }
 4684                self.display_map.update(cx, |display_map, _| {
 4685                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4686                });
 4687                return;
 4688            }
 4689            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4690            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4691                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4692            }
 4693            InlayHintRefreshReason::RefreshRequested => {
 4694                (InvalidationStrategy::RefreshRequested, None)
 4695            }
 4696        };
 4697
 4698        if let Some(InlaySplice {
 4699            to_remove,
 4700            to_insert,
 4701        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4702            reason_description,
 4703            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4704            invalidate_cache,
 4705            ignore_debounce,
 4706            cx,
 4707        ) {
 4708            self.splice_inlays(&to_remove, to_insert, cx);
 4709        }
 4710    }
 4711
 4712    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4713        self.display_map
 4714            .read(cx)
 4715            .current_inlays()
 4716            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4717            .cloned()
 4718            .collect()
 4719    }
 4720
 4721    pub fn excerpts_for_inlay_hints_query(
 4722        &self,
 4723        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4724        cx: &mut Context<Editor>,
 4725    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4726        let Some(project) = self.project.as_ref() else {
 4727            return HashMap::default();
 4728        };
 4729        let project = project.read(cx);
 4730        let multi_buffer = self.buffer().read(cx);
 4731        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4732        let multi_buffer_visible_start = self
 4733            .scroll_manager
 4734            .anchor()
 4735            .anchor
 4736            .to_point(&multi_buffer_snapshot);
 4737        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4738            multi_buffer_visible_start
 4739                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4740            Bias::Left,
 4741        );
 4742        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4743        multi_buffer_snapshot
 4744            .range_to_buffer_ranges(multi_buffer_visible_range)
 4745            .into_iter()
 4746            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4747            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4748                let buffer_file = project::File::from_dyn(buffer.file())?;
 4749                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4750                let worktree_entry = buffer_worktree
 4751                    .read(cx)
 4752                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4753                if worktree_entry.is_ignored {
 4754                    return None;
 4755                }
 4756
 4757                let language = buffer.language()?;
 4758                if let Some(restrict_to_languages) = restrict_to_languages {
 4759                    if !restrict_to_languages.contains(language) {
 4760                        return None;
 4761                    }
 4762                }
 4763                Some((
 4764                    excerpt_id,
 4765                    (
 4766                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4767                        buffer.version().clone(),
 4768                        excerpt_visible_range,
 4769                    ),
 4770                ))
 4771            })
 4772            .collect()
 4773    }
 4774
 4775    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4776        TextLayoutDetails {
 4777            text_system: window.text_system().clone(),
 4778            editor_style: self.style.clone().unwrap(),
 4779            rem_size: window.rem_size(),
 4780            scroll_anchor: self.scroll_manager.anchor(),
 4781            visible_rows: self.visible_line_count(),
 4782            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4783        }
 4784    }
 4785
 4786    pub fn splice_inlays(
 4787        &self,
 4788        to_remove: &[InlayId],
 4789        to_insert: Vec<Inlay>,
 4790        cx: &mut Context<Self>,
 4791    ) {
 4792        self.display_map.update(cx, |display_map, cx| {
 4793            display_map.splice_inlays(to_remove, to_insert, cx)
 4794        });
 4795        cx.notify();
 4796    }
 4797
 4798    fn trigger_on_type_formatting(
 4799        &self,
 4800        input: String,
 4801        window: &mut Window,
 4802        cx: &mut Context<Self>,
 4803    ) -> Option<Task<Result<()>>> {
 4804        if input.len() != 1 {
 4805            return None;
 4806        }
 4807
 4808        let project = self.project.as_ref()?;
 4809        let position = self.selections.newest_anchor().head();
 4810        let (buffer, buffer_position) = self
 4811            .buffer
 4812            .read(cx)
 4813            .text_anchor_for_position(position, cx)?;
 4814
 4815        let settings = language_settings::language_settings(
 4816            buffer
 4817                .read(cx)
 4818                .language_at(buffer_position)
 4819                .map(|l| l.name()),
 4820            buffer.read(cx).file(),
 4821            cx,
 4822        );
 4823        if !settings.use_on_type_format {
 4824            return None;
 4825        }
 4826
 4827        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4828        // hence we do LSP request & edit on host side only — add formats to host's history.
 4829        let push_to_lsp_host_history = true;
 4830        // If this is not the host, append its history with new edits.
 4831        let push_to_client_history = project.read(cx).is_via_collab();
 4832
 4833        let on_type_formatting = project.update(cx, |project, cx| {
 4834            project.on_type_format(
 4835                buffer.clone(),
 4836                buffer_position,
 4837                input,
 4838                push_to_lsp_host_history,
 4839                cx,
 4840            )
 4841        });
 4842        Some(cx.spawn_in(window, async move |editor, cx| {
 4843            if let Some(transaction) = on_type_formatting.await? {
 4844                if push_to_client_history {
 4845                    buffer
 4846                        .update(cx, |buffer, _| {
 4847                            buffer.push_transaction(transaction, Instant::now());
 4848                            buffer.finalize_last_transaction();
 4849                        })
 4850                        .ok();
 4851                }
 4852                editor.update(cx, |editor, cx| {
 4853                    editor.refresh_document_highlights(cx);
 4854                })?;
 4855            }
 4856            Ok(())
 4857        }))
 4858    }
 4859
 4860    pub fn show_word_completions(
 4861        &mut self,
 4862        _: &ShowWordCompletions,
 4863        window: &mut Window,
 4864        cx: &mut Context<Self>,
 4865    ) {
 4866        self.open_completions_menu(true, None, window, cx);
 4867    }
 4868
 4869    pub fn show_completions(
 4870        &mut self,
 4871        options: &ShowCompletions,
 4872        window: &mut Window,
 4873        cx: &mut Context<Self>,
 4874    ) {
 4875        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4876    }
 4877
 4878    fn open_completions_menu(
 4879        &mut self,
 4880        ignore_completion_provider: bool,
 4881        trigger: Option<&str>,
 4882        window: &mut Window,
 4883        cx: &mut Context<Self>,
 4884    ) {
 4885        if self.pending_rename.is_some() {
 4886            return;
 4887        }
 4888        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4889            return;
 4890        }
 4891
 4892        let position = self.selections.newest_anchor().head();
 4893        if position.diff_base_anchor.is_some() {
 4894            return;
 4895        }
 4896        let (buffer, buffer_position) =
 4897            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4898                output
 4899            } else {
 4900                return;
 4901            };
 4902        let buffer_snapshot = buffer.read(cx).snapshot();
 4903        let show_completion_documentation = buffer_snapshot
 4904            .settings_at(buffer_position, cx)
 4905            .show_completion_documentation;
 4906
 4907        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4908
 4909        let trigger_kind = match trigger {
 4910            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4911                CompletionTriggerKind::TRIGGER_CHARACTER
 4912            }
 4913            _ => CompletionTriggerKind::INVOKED,
 4914        };
 4915        let completion_context = CompletionContext {
 4916            trigger_character: trigger.and_then(|trigger| {
 4917                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4918                    Some(String::from(trigger))
 4919                } else {
 4920                    None
 4921                }
 4922            }),
 4923            trigger_kind,
 4924        };
 4925
 4926        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4927        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4928            let word_to_exclude = buffer_snapshot
 4929                .text_for_range(old_range.clone())
 4930                .collect::<String>();
 4931            (
 4932                buffer_snapshot.anchor_before(old_range.start)
 4933                    ..buffer_snapshot.anchor_after(old_range.end),
 4934                Some(word_to_exclude),
 4935            )
 4936        } else {
 4937            (buffer_position..buffer_position, None)
 4938        };
 4939
 4940        let completion_settings = language_settings(
 4941            buffer_snapshot
 4942                .language_at(buffer_position)
 4943                .map(|language| language.name()),
 4944            buffer_snapshot.file(),
 4945            cx,
 4946        )
 4947        .completions;
 4948
 4949        // The document can be large, so stay in reasonable bounds when searching for words,
 4950        // otherwise completion pop-up might be slow to appear.
 4951        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4952        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4953        let min_word_search = buffer_snapshot.clip_point(
 4954            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4955            Bias::Left,
 4956        );
 4957        let max_word_search = buffer_snapshot.clip_point(
 4958            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4959            Bias::Right,
 4960        );
 4961        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4962            ..buffer_snapshot.point_to_offset(max_word_search);
 4963
 4964        let provider = if ignore_completion_provider {
 4965            None
 4966        } else {
 4967            self.completion_provider.clone()
 4968        };
 4969        let skip_digits = query
 4970            .as_ref()
 4971            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4972
 4973        let (mut words, provided_completions) = match &provider {
 4974            Some(provider) => {
 4975                let completions = provider.completions(
 4976                    position.excerpt_id,
 4977                    &buffer,
 4978                    buffer_position,
 4979                    completion_context,
 4980                    window,
 4981                    cx,
 4982                );
 4983
 4984                let words = match completion_settings.words {
 4985                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4986                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4987                        .background_spawn(async move {
 4988                            buffer_snapshot.words_in_range(WordsQuery {
 4989                                fuzzy_contents: None,
 4990                                range: word_search_range,
 4991                                skip_digits,
 4992                            })
 4993                        }),
 4994                };
 4995
 4996                (words, completions)
 4997            }
 4998            None => (
 4999                cx.background_spawn(async move {
 5000                    buffer_snapshot.words_in_range(WordsQuery {
 5001                        fuzzy_contents: None,
 5002                        range: word_search_range,
 5003                        skip_digits,
 5004                    })
 5005                }),
 5006                Task::ready(Ok(None)),
 5007            ),
 5008        };
 5009
 5010        let sort_completions = provider
 5011            .as_ref()
 5012            .map_or(false, |provider| provider.sort_completions());
 5013
 5014        let filter_completions = provider
 5015            .as_ref()
 5016            .map_or(true, |provider| provider.filter_completions());
 5017
 5018        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5019
 5020        let id = post_inc(&mut self.next_completion_id);
 5021        let task = cx.spawn_in(window, async move |editor, cx| {
 5022            async move {
 5023                editor.update(cx, |this, _| {
 5024                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5025                })?;
 5026
 5027                let mut completions = Vec::new();
 5028                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5029                    completions.extend(provided_completions);
 5030                    if completion_settings.words == WordsCompletionMode::Fallback {
 5031                        words = Task::ready(BTreeMap::default());
 5032                    }
 5033                }
 5034
 5035                let mut words = words.await;
 5036                if let Some(word_to_exclude) = &word_to_exclude {
 5037                    words.remove(word_to_exclude);
 5038                }
 5039                for lsp_completion in &completions {
 5040                    words.remove(&lsp_completion.new_text);
 5041                }
 5042                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5043                    replace_range: old_range.clone(),
 5044                    new_text: word.clone(),
 5045                    label: CodeLabel::plain(word, None),
 5046                    icon_path: None,
 5047                    documentation: None,
 5048                    source: CompletionSource::BufferWord {
 5049                        word_range,
 5050                        resolved: false,
 5051                    },
 5052                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5053                    confirm: None,
 5054                }));
 5055
 5056                let menu = if completions.is_empty() {
 5057                    None
 5058                } else {
 5059                    let mut menu = CompletionsMenu::new(
 5060                        id,
 5061                        sort_completions,
 5062                        show_completion_documentation,
 5063                        ignore_completion_provider,
 5064                        position,
 5065                        buffer.clone(),
 5066                        completions.into(),
 5067                        snippet_sort_order,
 5068                    );
 5069
 5070                    menu.filter(
 5071                        if filter_completions {
 5072                            query.as_deref()
 5073                        } else {
 5074                            None
 5075                        },
 5076                        provider,
 5077                        editor.clone(),
 5078                        cx,
 5079                    )
 5080                    .await;
 5081
 5082                    menu.visible().then_some(menu)
 5083                };
 5084
 5085                editor.update_in(cx, |editor, window, cx| {
 5086                    match editor.context_menu.borrow().as_ref() {
 5087                        None => {}
 5088                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5089                            if prev_menu.id > id {
 5090                                return;
 5091                            }
 5092                        }
 5093                        _ => return,
 5094                    }
 5095
 5096                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5097                        let mut menu = menu.unwrap();
 5098                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5099                        crate::hover_popover::hide_hover(editor, cx);
 5100                        *editor.context_menu.borrow_mut() =
 5101                            Some(CodeContextMenu::Completions(menu));
 5102
 5103                        if editor.show_edit_predictions_in_menu() {
 5104                            editor.update_visible_inline_completion(window, cx);
 5105                        } else {
 5106                            editor.discard_inline_completion(false, cx);
 5107                        }
 5108
 5109                        cx.notify();
 5110                    } else if editor.completion_tasks.len() <= 1 {
 5111                        // If there are no more completion tasks and the last menu was
 5112                        // empty, we should hide it.
 5113                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5114                        // If it was already hidden and we don't show inline
 5115                        // completions in the menu, we should also show the
 5116                        // inline-completion when available.
 5117                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5118                            editor.update_visible_inline_completion(window, cx);
 5119                        }
 5120                    }
 5121                })?;
 5122
 5123                anyhow::Ok(())
 5124            }
 5125            .log_err()
 5126            .await
 5127        });
 5128
 5129        self.completion_tasks.push((id, task));
 5130    }
 5131
 5132    #[cfg(feature = "test-support")]
 5133    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5134        let menu = self.context_menu.borrow();
 5135        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5136            let completions = menu.completions.borrow();
 5137            Some(completions.to_vec())
 5138        } else {
 5139            None
 5140        }
 5141    }
 5142
 5143    pub fn confirm_completion(
 5144        &mut self,
 5145        action: &ConfirmCompletion,
 5146        window: &mut Window,
 5147        cx: &mut Context<Self>,
 5148    ) -> Option<Task<Result<()>>> {
 5149        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5150        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5151    }
 5152
 5153    pub fn confirm_completion_insert(
 5154        &mut self,
 5155        _: &ConfirmCompletionInsert,
 5156        window: &mut Window,
 5157        cx: &mut Context<Self>,
 5158    ) -> Option<Task<Result<()>>> {
 5159        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5160        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5161    }
 5162
 5163    pub fn confirm_completion_replace(
 5164        &mut self,
 5165        _: &ConfirmCompletionReplace,
 5166        window: &mut Window,
 5167        cx: &mut Context<Self>,
 5168    ) -> Option<Task<Result<()>>> {
 5169        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5170        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5171    }
 5172
 5173    pub fn compose_completion(
 5174        &mut self,
 5175        action: &ComposeCompletion,
 5176        window: &mut Window,
 5177        cx: &mut Context<Self>,
 5178    ) -> Option<Task<Result<()>>> {
 5179        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5180        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5181    }
 5182
 5183    fn do_completion(
 5184        &mut self,
 5185        item_ix: Option<usize>,
 5186        intent: CompletionIntent,
 5187        window: &mut Window,
 5188        cx: &mut Context<Editor>,
 5189    ) -> Option<Task<Result<()>>> {
 5190        use language::ToOffset as _;
 5191
 5192        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5193        else {
 5194            return None;
 5195        };
 5196
 5197        let candidate_id = {
 5198            let entries = completions_menu.entries.borrow();
 5199            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5200            if self.show_edit_predictions_in_menu() {
 5201                self.discard_inline_completion(true, cx);
 5202            }
 5203            mat.candidate_id
 5204        };
 5205
 5206        let buffer_handle = completions_menu.buffer;
 5207        let completion = completions_menu
 5208            .completions
 5209            .borrow()
 5210            .get(candidate_id)?
 5211            .clone();
 5212        cx.stop_propagation();
 5213
 5214        let snapshot = self.buffer.read(cx).snapshot(cx);
 5215        let newest_anchor = self.selections.newest_anchor();
 5216
 5217        let snippet;
 5218        let new_text;
 5219        if completion.is_snippet() {
 5220            let mut snippet_source = completion.new_text.clone();
 5221            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5222                if scope.prefers_label_for_snippet_in_completion() {
 5223                    if let Some(label) = completion.label() {
 5224                        if matches!(
 5225                            completion.kind(),
 5226                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5227                        ) {
 5228                            snippet_source = label;
 5229                        }
 5230                    }
 5231                }
 5232            }
 5233            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5234            new_text = snippet.as_ref().unwrap().text.clone();
 5235        } else {
 5236            snippet = None;
 5237            new_text = completion.new_text.clone();
 5238        };
 5239
 5240        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5241        let buffer = buffer_handle.read(cx);
 5242        let replace_range_multibuffer = {
 5243            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5244            let multibuffer_anchor = snapshot
 5245                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5246                .unwrap()
 5247                ..snapshot
 5248                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5249                    .unwrap();
 5250            multibuffer_anchor.start.to_offset(&snapshot)
 5251                ..multibuffer_anchor.end.to_offset(&snapshot)
 5252        };
 5253        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5254            return None;
 5255        }
 5256
 5257        let old_text = buffer
 5258            .text_for_range(replace_range.clone())
 5259            .collect::<String>();
 5260        let lookbehind = newest_anchor
 5261            .start
 5262            .text_anchor
 5263            .to_offset(buffer)
 5264            .saturating_sub(replace_range.start);
 5265        let lookahead = replace_range
 5266            .end
 5267            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5268        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5269        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5270
 5271        let selections = self.selections.all::<usize>(cx);
 5272        let mut ranges = Vec::new();
 5273        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5274
 5275        for selection in &selections {
 5276            let range = if selection.id == newest_anchor.id {
 5277                replace_range_multibuffer.clone()
 5278            } else {
 5279                let mut range = selection.range();
 5280
 5281                // if prefix is present, don't duplicate it
 5282                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5283                    range.start = range.start.saturating_sub(lookbehind);
 5284
 5285                    // if suffix is also present, mimic the newest cursor and replace it
 5286                    if selection.id != newest_anchor.id
 5287                        && snapshot.contains_str_at(range.end, suffix)
 5288                    {
 5289                        range.end += lookahead;
 5290                    }
 5291                }
 5292                range
 5293            };
 5294
 5295            ranges.push(range.clone());
 5296
 5297            if !self.linked_edit_ranges.is_empty() {
 5298                let start_anchor = snapshot.anchor_before(range.start);
 5299                let end_anchor = snapshot.anchor_after(range.end);
 5300                if let Some(ranges) = self
 5301                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5302                {
 5303                    for (buffer, edits) in ranges {
 5304                        linked_edits
 5305                            .entry(buffer.clone())
 5306                            .or_default()
 5307                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5308                    }
 5309                }
 5310            }
 5311        }
 5312
 5313        cx.emit(EditorEvent::InputHandled {
 5314            utf16_range_to_replace: None,
 5315            text: new_text.clone().into(),
 5316        });
 5317
 5318        self.transact(window, cx, |this, window, cx| {
 5319            if let Some(mut snippet) = snippet {
 5320                snippet.text = new_text.to_string();
 5321                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5322            } else {
 5323                this.buffer.update(cx, |buffer, cx| {
 5324                    let auto_indent = match completion.insert_text_mode {
 5325                        Some(InsertTextMode::AS_IS) => None,
 5326                        _ => this.autoindent_mode.clone(),
 5327                    };
 5328                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5329                    buffer.edit(edits, auto_indent, cx);
 5330                });
 5331            }
 5332            for (buffer, edits) in linked_edits {
 5333                buffer.update(cx, |buffer, cx| {
 5334                    let snapshot = buffer.snapshot();
 5335                    let edits = edits
 5336                        .into_iter()
 5337                        .map(|(range, text)| {
 5338                            use text::ToPoint as TP;
 5339                            let end_point = TP::to_point(&range.end, &snapshot);
 5340                            let start_point = TP::to_point(&range.start, &snapshot);
 5341                            (start_point..end_point, text)
 5342                        })
 5343                        .sorted_by_key(|(range, _)| range.start);
 5344                    buffer.edit(edits, None, cx);
 5345                })
 5346            }
 5347
 5348            this.refresh_inline_completion(true, false, window, cx);
 5349        });
 5350
 5351        let show_new_completions_on_confirm = completion
 5352            .confirm
 5353            .as_ref()
 5354            .map_or(false, |confirm| confirm(intent, window, cx));
 5355        if show_new_completions_on_confirm {
 5356            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5357        }
 5358
 5359        let provider = self.completion_provider.as_ref()?;
 5360        drop(completion);
 5361        let apply_edits = provider.apply_additional_edits_for_completion(
 5362            buffer_handle,
 5363            completions_menu.completions.clone(),
 5364            candidate_id,
 5365            true,
 5366            cx,
 5367        );
 5368
 5369        let editor_settings = EditorSettings::get_global(cx);
 5370        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5371            // After the code completion is finished, users often want to know what signatures are needed.
 5372            // so we should automatically call signature_help
 5373            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5374        }
 5375
 5376        Some(cx.foreground_executor().spawn(async move {
 5377            apply_edits.await?;
 5378            Ok(())
 5379        }))
 5380    }
 5381
 5382    pub fn toggle_code_actions(
 5383        &mut self,
 5384        action: &ToggleCodeActions,
 5385        window: &mut Window,
 5386        cx: &mut Context<Self>,
 5387    ) {
 5388        let quick_launch = action.quick_launch;
 5389        let mut context_menu = self.context_menu.borrow_mut();
 5390        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5391            if code_actions.deployed_from == action.deployed_from {
 5392                // Toggle if we're selecting the same one
 5393                *context_menu = None;
 5394                cx.notify();
 5395                return;
 5396            } else {
 5397                // Otherwise, clear it and start a new one
 5398                *context_menu = None;
 5399                cx.notify();
 5400            }
 5401        }
 5402        drop(context_menu);
 5403        let snapshot = self.snapshot(window, cx);
 5404        let deployed_from = action.deployed_from.clone();
 5405        let mut task = self.code_actions_task.take();
 5406        let action = action.clone();
 5407        cx.spawn_in(window, async move |editor, cx| {
 5408            while let Some(prev_task) = task {
 5409                prev_task.await.log_err();
 5410                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5411            }
 5412
 5413            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5414                if editor.focus_handle.is_focused(window) {
 5415                    let multibuffer_point = match &action.deployed_from {
 5416                        Some(CodeActionSource::Indicator(row)) => {
 5417                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5418                        }
 5419                        _ => editor.selections.newest::<Point>(cx).head(),
 5420                    };
 5421                    let (buffer, buffer_row) = snapshot
 5422                        .buffer_snapshot
 5423                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5424                        .and_then(|(buffer_snapshot, range)| {
 5425                            editor
 5426                                .buffer
 5427                                .read(cx)
 5428                                .buffer(buffer_snapshot.remote_id())
 5429                                .map(|buffer| (buffer, range.start.row))
 5430                        })?;
 5431                    let (_, code_actions) = editor
 5432                        .available_code_actions
 5433                        .clone()
 5434                        .and_then(|(location, code_actions)| {
 5435                            let snapshot = location.buffer.read(cx).snapshot();
 5436                            let point_range = location.range.to_point(&snapshot);
 5437                            let point_range = point_range.start.row..=point_range.end.row;
 5438                            if point_range.contains(&buffer_row) {
 5439                                Some((location, code_actions))
 5440                            } else {
 5441                                None
 5442                            }
 5443                        })
 5444                        .unzip();
 5445                    let buffer_id = buffer.read(cx).remote_id();
 5446                    let tasks = editor
 5447                        .tasks
 5448                        .get(&(buffer_id, buffer_row))
 5449                        .map(|t| Arc::new(t.to_owned()));
 5450                    if tasks.is_none() && code_actions.is_none() {
 5451                        return None;
 5452                    }
 5453
 5454                    editor.completion_tasks.clear();
 5455                    editor.discard_inline_completion(false, cx);
 5456                    let task_context =
 5457                        tasks
 5458                            .as_ref()
 5459                            .zip(editor.project.clone())
 5460                            .map(|(tasks, project)| {
 5461                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5462                            });
 5463
 5464                    Some(cx.spawn_in(window, async move |editor, cx| {
 5465                        let task_context = match task_context {
 5466                            Some(task_context) => task_context.await,
 5467                            None => None,
 5468                        };
 5469                        let resolved_tasks =
 5470                            tasks
 5471                                .zip(task_context.clone())
 5472                                .map(|(tasks, task_context)| ResolvedTasks {
 5473                                    templates: tasks.resolve(&task_context).collect(),
 5474                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5475                                        multibuffer_point.row,
 5476                                        tasks.column,
 5477                                    )),
 5478                                });
 5479                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5480                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5481                                maybe!({
 5482                                    let project = editor.project.as_ref()?;
 5483                                    let dap_store = project.read(cx).dap_store();
 5484                                    let mut scenarios = vec![];
 5485                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5486                                    let buffer = buffer.read(cx);
 5487                                    let language = buffer.language()?;
 5488                                    let file = buffer.file();
 5489                                    let debug_adapter =
 5490                                        language_settings(language.name().into(), file, cx)
 5491                                            .debuggers
 5492                                            .first()
 5493                                            .map(SharedString::from)
 5494                                            .or_else(|| {
 5495                                                language
 5496                                                    .config()
 5497                                                    .debuggers
 5498                                                    .first()
 5499                                                    .map(SharedString::from)
 5500                                            })?;
 5501
 5502                                    dap_store.update(cx, |dap_store, cx| {
 5503                                        for (_, task) in &resolved_tasks.templates {
 5504                                            if let Some(scenario) = dap_store
 5505                                                .debug_scenario_for_build_task(
 5506                                                    task.original_task().clone(),
 5507                                                    debug_adapter.clone().into(),
 5508                                                    task.display_label().to_owned().into(),
 5509                                                    cx,
 5510                                                )
 5511                                            {
 5512                                                scenarios.push(scenario);
 5513                                            }
 5514                                        }
 5515                                    });
 5516                                    Some(scenarios)
 5517                                })
 5518                                .unwrap_or_default()
 5519                            } else {
 5520                                vec![]
 5521                            }
 5522                        })?;
 5523                        let spawn_straight_away = quick_launch
 5524                            && resolved_tasks
 5525                                .as_ref()
 5526                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5527                            && code_actions
 5528                                .as_ref()
 5529                                .map_or(true, |actions| actions.is_empty())
 5530                            && debug_scenarios.is_empty();
 5531                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5532                            crate::hover_popover::hide_hover(editor, cx);
 5533                            *editor.context_menu.borrow_mut() =
 5534                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5535                                    buffer,
 5536                                    actions: CodeActionContents::new(
 5537                                        resolved_tasks,
 5538                                        code_actions,
 5539                                        debug_scenarios,
 5540                                        task_context.unwrap_or_default(),
 5541                                    ),
 5542                                    selected_item: Default::default(),
 5543                                    scroll_handle: UniformListScrollHandle::default(),
 5544                                    deployed_from,
 5545                                }));
 5546                            if spawn_straight_away {
 5547                                if let Some(task) = editor.confirm_code_action(
 5548                                    &ConfirmCodeAction { item_ix: Some(0) },
 5549                                    window,
 5550                                    cx,
 5551                                ) {
 5552                                    cx.notify();
 5553                                    return task;
 5554                                }
 5555                            }
 5556                            cx.notify();
 5557                            Task::ready(Ok(()))
 5558                        }) {
 5559                            task.await
 5560                        } else {
 5561                            Ok(())
 5562                        }
 5563                    }))
 5564                } else {
 5565                    Some(Task::ready(Ok(())))
 5566                }
 5567            })?;
 5568            if let Some(task) = spawned_test_task {
 5569                task.await?;
 5570            }
 5571
 5572            anyhow::Ok(())
 5573        })
 5574        .detach_and_log_err(cx);
 5575    }
 5576
 5577    pub fn confirm_code_action(
 5578        &mut self,
 5579        action: &ConfirmCodeAction,
 5580        window: &mut Window,
 5581        cx: &mut Context<Self>,
 5582    ) -> Option<Task<Result<()>>> {
 5583        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5584
 5585        let actions_menu =
 5586            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5587                menu
 5588            } else {
 5589                return None;
 5590            };
 5591
 5592        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5593        let action = actions_menu.actions.get(action_ix)?;
 5594        let title = action.label();
 5595        let buffer = actions_menu.buffer;
 5596        let workspace = self.workspace()?;
 5597
 5598        match action {
 5599            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5600                workspace.update(cx, |workspace, cx| {
 5601                    workspace.schedule_resolved_task(
 5602                        task_source_kind,
 5603                        resolved_task,
 5604                        false,
 5605                        window,
 5606                        cx,
 5607                    );
 5608
 5609                    Some(Task::ready(Ok(())))
 5610                })
 5611            }
 5612            CodeActionsItem::CodeAction {
 5613                excerpt_id,
 5614                action,
 5615                provider,
 5616            } => {
 5617                let apply_code_action =
 5618                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5619                let workspace = workspace.downgrade();
 5620                Some(cx.spawn_in(window, async move |editor, cx| {
 5621                    let project_transaction = apply_code_action.await?;
 5622                    Self::open_project_transaction(
 5623                        &editor,
 5624                        workspace,
 5625                        project_transaction,
 5626                        title,
 5627                        cx,
 5628                    )
 5629                    .await
 5630                }))
 5631            }
 5632            CodeActionsItem::DebugScenario(scenario) => {
 5633                let context = actions_menu.actions.context.clone();
 5634
 5635                workspace.update(cx, |workspace, cx| {
 5636                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5637                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5638                });
 5639                Some(Task::ready(Ok(())))
 5640            }
 5641        }
 5642    }
 5643
 5644    pub async fn open_project_transaction(
 5645        this: &WeakEntity<Editor>,
 5646        workspace: WeakEntity<Workspace>,
 5647        transaction: ProjectTransaction,
 5648        title: String,
 5649        cx: &mut AsyncWindowContext,
 5650    ) -> Result<()> {
 5651        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5652        cx.update(|_, cx| {
 5653            entries.sort_unstable_by_key(|(buffer, _)| {
 5654                buffer.read(cx).file().map(|f| f.path().clone())
 5655            });
 5656        })?;
 5657
 5658        // If the project transaction's edits are all contained within this editor, then
 5659        // avoid opening a new editor to display them.
 5660
 5661        if let Some((buffer, transaction)) = entries.first() {
 5662            if entries.len() == 1 {
 5663                let excerpt = this.update(cx, |editor, cx| {
 5664                    editor
 5665                        .buffer()
 5666                        .read(cx)
 5667                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5668                })?;
 5669                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5670                    if excerpted_buffer == *buffer {
 5671                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5672                            let excerpt_range = excerpt_range.to_offset(buffer);
 5673                            buffer
 5674                                .edited_ranges_for_transaction::<usize>(transaction)
 5675                                .all(|range| {
 5676                                    excerpt_range.start <= range.start
 5677                                        && excerpt_range.end >= range.end
 5678                                })
 5679                        })?;
 5680
 5681                        if all_edits_within_excerpt {
 5682                            return Ok(());
 5683                        }
 5684                    }
 5685                }
 5686            }
 5687        } else {
 5688            return Ok(());
 5689        }
 5690
 5691        let mut ranges_to_highlight = Vec::new();
 5692        let excerpt_buffer = cx.new(|cx| {
 5693            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5694            for (buffer_handle, transaction) in &entries {
 5695                let edited_ranges = buffer_handle
 5696                    .read(cx)
 5697                    .edited_ranges_for_transaction::<Point>(transaction)
 5698                    .collect::<Vec<_>>();
 5699                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5700                    PathKey::for_buffer(buffer_handle, cx),
 5701                    buffer_handle.clone(),
 5702                    edited_ranges,
 5703                    DEFAULT_MULTIBUFFER_CONTEXT,
 5704                    cx,
 5705                );
 5706
 5707                ranges_to_highlight.extend(ranges);
 5708            }
 5709            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5710            multibuffer
 5711        })?;
 5712
 5713        workspace.update_in(cx, |workspace, window, cx| {
 5714            let project = workspace.project().clone();
 5715            let editor =
 5716                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5717            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5718            editor.update(cx, |editor, cx| {
 5719                editor.highlight_background::<Self>(
 5720                    &ranges_to_highlight,
 5721                    |theme| theme.editor_highlighted_line_background,
 5722                    cx,
 5723                );
 5724            });
 5725        })?;
 5726
 5727        Ok(())
 5728    }
 5729
 5730    pub fn clear_code_action_providers(&mut self) {
 5731        self.code_action_providers.clear();
 5732        self.available_code_actions.take();
 5733    }
 5734
 5735    pub fn add_code_action_provider(
 5736        &mut self,
 5737        provider: Rc<dyn CodeActionProvider>,
 5738        window: &mut Window,
 5739        cx: &mut Context<Self>,
 5740    ) {
 5741        if self
 5742            .code_action_providers
 5743            .iter()
 5744            .any(|existing_provider| existing_provider.id() == provider.id())
 5745        {
 5746            return;
 5747        }
 5748
 5749        self.code_action_providers.push(provider);
 5750        self.refresh_code_actions(window, cx);
 5751    }
 5752
 5753    pub fn remove_code_action_provider(
 5754        &mut self,
 5755        id: Arc<str>,
 5756        window: &mut Window,
 5757        cx: &mut Context<Self>,
 5758    ) {
 5759        self.code_action_providers
 5760            .retain(|provider| provider.id() != id);
 5761        self.refresh_code_actions(window, cx);
 5762    }
 5763
 5764    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5765        !self.code_action_providers.is_empty()
 5766            && EditorSettings::get_global(cx).toolbar.code_actions
 5767    }
 5768
 5769    pub fn has_available_code_actions(&self) -> bool {
 5770        self.available_code_actions
 5771            .as_ref()
 5772            .is_some_and(|(_, actions)| !actions.is_empty())
 5773    }
 5774
 5775    fn render_inline_code_actions(
 5776        &self,
 5777        icon_size: ui::IconSize,
 5778        display_row: DisplayRow,
 5779        is_active: bool,
 5780        cx: &mut Context<Self>,
 5781    ) -> AnyElement {
 5782        let show_tooltip = !self.context_menu_visible();
 5783        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5784            .icon_size(icon_size)
 5785            .shape(ui::IconButtonShape::Square)
 5786            .style(ButtonStyle::Transparent)
 5787            .icon_color(ui::Color::Hidden)
 5788            .toggle_state(is_active)
 5789            .when(show_tooltip, |this| {
 5790                this.tooltip({
 5791                    let focus_handle = self.focus_handle.clone();
 5792                    move |window, cx| {
 5793                        Tooltip::for_action_in(
 5794                            "Toggle Code Actions",
 5795                            &ToggleCodeActions {
 5796                                deployed_from: None,
 5797                                quick_launch: false,
 5798                            },
 5799                            &focus_handle,
 5800                            window,
 5801                            cx,
 5802                        )
 5803                    }
 5804                })
 5805            })
 5806            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5807                window.focus(&editor.focus_handle(cx));
 5808                editor.toggle_code_actions(
 5809                    &crate::actions::ToggleCodeActions {
 5810                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5811                            display_row,
 5812                        )),
 5813                        quick_launch: false,
 5814                    },
 5815                    window,
 5816                    cx,
 5817                );
 5818            }))
 5819            .into_any_element()
 5820    }
 5821
 5822    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5823        &self.context_menu
 5824    }
 5825
 5826    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5827        let newest_selection = self.selections.newest_anchor().clone();
 5828        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5829        let buffer = self.buffer.read(cx);
 5830        if newest_selection.head().diff_base_anchor.is_some() {
 5831            return None;
 5832        }
 5833        let (start_buffer, start) =
 5834            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5835        let (end_buffer, end) =
 5836            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5837        if start_buffer != end_buffer {
 5838            return None;
 5839        }
 5840
 5841        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5842            cx.background_executor()
 5843                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5844                .await;
 5845
 5846            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5847                let providers = this.code_action_providers.clone();
 5848                let tasks = this
 5849                    .code_action_providers
 5850                    .iter()
 5851                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5852                    .collect::<Vec<_>>();
 5853                (providers, tasks)
 5854            })?;
 5855
 5856            let mut actions = Vec::new();
 5857            for (provider, provider_actions) in
 5858                providers.into_iter().zip(future::join_all(tasks).await)
 5859            {
 5860                if let Some(provider_actions) = provider_actions.log_err() {
 5861                    actions.extend(provider_actions.into_iter().map(|action| {
 5862                        AvailableCodeAction {
 5863                            excerpt_id: newest_selection.start.excerpt_id,
 5864                            action,
 5865                            provider: provider.clone(),
 5866                        }
 5867                    }));
 5868                }
 5869            }
 5870
 5871            this.update(cx, |this, cx| {
 5872                this.available_code_actions = if actions.is_empty() {
 5873                    None
 5874                } else {
 5875                    Some((
 5876                        Location {
 5877                            buffer: start_buffer,
 5878                            range: start..end,
 5879                        },
 5880                        actions.into(),
 5881                    ))
 5882                };
 5883                cx.notify();
 5884            })
 5885        }));
 5886        None
 5887    }
 5888
 5889    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5890        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5891            self.show_git_blame_inline = false;
 5892
 5893            self.show_git_blame_inline_delay_task =
 5894                Some(cx.spawn_in(window, async move |this, cx| {
 5895                    cx.background_executor().timer(delay).await;
 5896
 5897                    this.update(cx, |this, cx| {
 5898                        this.show_git_blame_inline = true;
 5899                        cx.notify();
 5900                    })
 5901                    .log_err();
 5902                }));
 5903        }
 5904    }
 5905
 5906    fn show_blame_popover(
 5907        &mut self,
 5908        blame_entry: &BlameEntry,
 5909        position: gpui::Point<Pixels>,
 5910        cx: &mut Context<Self>,
 5911    ) {
 5912        if let Some(state) = &mut self.inline_blame_popover {
 5913            state.hide_task.take();
 5914            cx.notify();
 5915        } else {
 5916            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5917            let show_task = cx.spawn(async move |editor, cx| {
 5918                cx.background_executor()
 5919                    .timer(std::time::Duration::from_millis(delay))
 5920                    .await;
 5921                editor
 5922                    .update(cx, |editor, cx| {
 5923                        if let Some(state) = &mut editor.inline_blame_popover {
 5924                            state.show_task = None;
 5925                            cx.notify();
 5926                        }
 5927                    })
 5928                    .ok();
 5929            });
 5930            let Some(blame) = self.blame.as_ref() else {
 5931                return;
 5932            };
 5933            let blame = blame.read(cx);
 5934            let details = blame.details_for_entry(&blame_entry);
 5935            let markdown = cx.new(|cx| {
 5936                Markdown::new(
 5937                    details
 5938                        .as_ref()
 5939                        .map(|message| message.message.clone())
 5940                        .unwrap_or_default(),
 5941                    None,
 5942                    None,
 5943                    cx,
 5944                )
 5945            });
 5946            self.inline_blame_popover = Some(InlineBlamePopover {
 5947                position,
 5948                show_task: Some(show_task),
 5949                hide_task: None,
 5950                popover_bounds: None,
 5951                popover_state: InlineBlamePopoverState {
 5952                    scroll_handle: ScrollHandle::new(),
 5953                    commit_message: details,
 5954                    markdown,
 5955                },
 5956            });
 5957        }
 5958    }
 5959
 5960    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5961        if let Some(state) = &mut self.inline_blame_popover {
 5962            if state.show_task.is_some() {
 5963                self.inline_blame_popover.take();
 5964                cx.notify();
 5965            } else {
 5966                let hide_task = cx.spawn(async move |editor, cx| {
 5967                    cx.background_executor()
 5968                        .timer(std::time::Duration::from_millis(100))
 5969                        .await;
 5970                    editor
 5971                        .update(cx, |editor, cx| {
 5972                            editor.inline_blame_popover.take();
 5973                            cx.notify();
 5974                        })
 5975                        .ok();
 5976                });
 5977                state.hide_task = Some(hide_task);
 5978            }
 5979        }
 5980    }
 5981
 5982    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5983        if self.pending_rename.is_some() {
 5984            return None;
 5985        }
 5986
 5987        let provider = self.semantics_provider.clone()?;
 5988        let buffer = self.buffer.read(cx);
 5989        let newest_selection = self.selections.newest_anchor().clone();
 5990        let cursor_position = newest_selection.head();
 5991        let (cursor_buffer, cursor_buffer_position) =
 5992            buffer.text_anchor_for_position(cursor_position, cx)?;
 5993        let (tail_buffer, tail_buffer_position) =
 5994            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5995        if cursor_buffer != tail_buffer {
 5996            return None;
 5997        }
 5998
 5999        let snapshot = cursor_buffer.read(cx).snapshot();
 6000        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6001        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6002        if start_word_range != end_word_range {
 6003            self.document_highlights_task.take();
 6004            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6005            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6006            return None;
 6007        }
 6008
 6009        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6010        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6011            cx.background_executor()
 6012                .timer(Duration::from_millis(debounce))
 6013                .await;
 6014
 6015            let highlights = if let Some(highlights) = cx
 6016                .update(|cx| {
 6017                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6018                })
 6019                .ok()
 6020                .flatten()
 6021            {
 6022                highlights.await.log_err()
 6023            } else {
 6024                None
 6025            };
 6026
 6027            if let Some(highlights) = highlights {
 6028                this.update(cx, |this, cx| {
 6029                    if this.pending_rename.is_some() {
 6030                        return;
 6031                    }
 6032
 6033                    let buffer_id = cursor_position.buffer_id;
 6034                    let buffer = this.buffer.read(cx);
 6035                    if !buffer
 6036                        .text_anchor_for_position(cursor_position, cx)
 6037                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6038                    {
 6039                        return;
 6040                    }
 6041
 6042                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6043                    let mut write_ranges = Vec::new();
 6044                    let mut read_ranges = Vec::new();
 6045                    for highlight in highlights {
 6046                        for (excerpt_id, excerpt_range) in
 6047                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6048                        {
 6049                            let start = highlight
 6050                                .range
 6051                                .start
 6052                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6053                            let end = highlight
 6054                                .range
 6055                                .end
 6056                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6057                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6058                                continue;
 6059                            }
 6060
 6061                            let range = Anchor {
 6062                                buffer_id,
 6063                                excerpt_id,
 6064                                text_anchor: start,
 6065                                diff_base_anchor: None,
 6066                            }..Anchor {
 6067                                buffer_id,
 6068                                excerpt_id,
 6069                                text_anchor: end,
 6070                                diff_base_anchor: None,
 6071                            };
 6072                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6073                                write_ranges.push(range);
 6074                            } else {
 6075                                read_ranges.push(range);
 6076                            }
 6077                        }
 6078                    }
 6079
 6080                    this.highlight_background::<DocumentHighlightRead>(
 6081                        &read_ranges,
 6082                        |theme| theme.editor_document_highlight_read_background,
 6083                        cx,
 6084                    );
 6085                    this.highlight_background::<DocumentHighlightWrite>(
 6086                        &write_ranges,
 6087                        |theme| theme.editor_document_highlight_write_background,
 6088                        cx,
 6089                    );
 6090                    cx.notify();
 6091                })
 6092                .log_err();
 6093            }
 6094        }));
 6095        None
 6096    }
 6097
 6098    fn prepare_highlight_query_from_selection(
 6099        &mut self,
 6100        cx: &mut Context<Editor>,
 6101    ) -> Option<(String, Range<Anchor>)> {
 6102        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6103            return None;
 6104        }
 6105        if !EditorSettings::get_global(cx).selection_highlight {
 6106            return None;
 6107        }
 6108        if self.selections.count() != 1 || self.selections.line_mode {
 6109            return None;
 6110        }
 6111        let selection = self.selections.newest::<Point>(cx);
 6112        if selection.is_empty() || selection.start.row != selection.end.row {
 6113            return None;
 6114        }
 6115        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6116        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6117        let query = multi_buffer_snapshot
 6118            .text_for_range(selection_anchor_range.clone())
 6119            .collect::<String>();
 6120        if query.trim().is_empty() {
 6121            return None;
 6122        }
 6123        Some((query, selection_anchor_range))
 6124    }
 6125
 6126    fn update_selection_occurrence_highlights(
 6127        &mut self,
 6128        query_text: String,
 6129        query_range: Range<Anchor>,
 6130        multi_buffer_range_to_query: Range<Point>,
 6131        use_debounce: bool,
 6132        window: &mut Window,
 6133        cx: &mut Context<Editor>,
 6134    ) -> Task<()> {
 6135        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6136        cx.spawn_in(window, async move |editor, cx| {
 6137            if use_debounce {
 6138                cx.background_executor()
 6139                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6140                    .await;
 6141            }
 6142            let match_task = cx.background_spawn(async move {
 6143                let buffer_ranges = multi_buffer_snapshot
 6144                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6145                    .into_iter()
 6146                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6147                let mut match_ranges = Vec::new();
 6148                let Ok(regex) = project::search::SearchQuery::text(
 6149                    query_text.clone(),
 6150                    false,
 6151                    false,
 6152                    false,
 6153                    Default::default(),
 6154                    Default::default(),
 6155                    false,
 6156                    None,
 6157                ) else {
 6158                    return Vec::default();
 6159                };
 6160                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6161                    match_ranges.extend(
 6162                        regex
 6163                            .search(&buffer_snapshot, Some(search_range.clone()))
 6164                            .await
 6165                            .into_iter()
 6166                            .filter_map(|match_range| {
 6167                                let match_start = buffer_snapshot
 6168                                    .anchor_after(search_range.start + match_range.start);
 6169                                let match_end = buffer_snapshot
 6170                                    .anchor_before(search_range.start + match_range.end);
 6171                                let match_anchor_range = Anchor::range_in_buffer(
 6172                                    excerpt_id,
 6173                                    buffer_snapshot.remote_id(),
 6174                                    match_start..match_end,
 6175                                );
 6176                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6177                            }),
 6178                    );
 6179                }
 6180                match_ranges
 6181            });
 6182            let match_ranges = match_task.await;
 6183            editor
 6184                .update_in(cx, |editor, _, cx| {
 6185                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6186                    if !match_ranges.is_empty() {
 6187                        editor.highlight_background::<SelectedTextHighlight>(
 6188                            &match_ranges,
 6189                            |theme| theme.editor_document_highlight_bracket_background,
 6190                            cx,
 6191                        )
 6192                    }
 6193                })
 6194                .log_err();
 6195        })
 6196    }
 6197
 6198    fn refresh_selected_text_highlights(
 6199        &mut self,
 6200        on_buffer_edit: bool,
 6201        window: &mut Window,
 6202        cx: &mut Context<Editor>,
 6203    ) {
 6204        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6205        else {
 6206            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6207            self.quick_selection_highlight_task.take();
 6208            self.debounced_selection_highlight_task.take();
 6209            return;
 6210        };
 6211        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6212        if on_buffer_edit
 6213            || self
 6214                .quick_selection_highlight_task
 6215                .as_ref()
 6216                .map_or(true, |(prev_anchor_range, _)| {
 6217                    prev_anchor_range != &query_range
 6218                })
 6219        {
 6220            let multi_buffer_visible_start = self
 6221                .scroll_manager
 6222                .anchor()
 6223                .anchor
 6224                .to_point(&multi_buffer_snapshot);
 6225            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6226                multi_buffer_visible_start
 6227                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6228                Bias::Left,
 6229            );
 6230            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6231            self.quick_selection_highlight_task = Some((
 6232                query_range.clone(),
 6233                self.update_selection_occurrence_highlights(
 6234                    query_text.clone(),
 6235                    query_range.clone(),
 6236                    multi_buffer_visible_range,
 6237                    false,
 6238                    window,
 6239                    cx,
 6240                ),
 6241            ));
 6242        }
 6243        if on_buffer_edit
 6244            || self
 6245                .debounced_selection_highlight_task
 6246                .as_ref()
 6247                .map_or(true, |(prev_anchor_range, _)| {
 6248                    prev_anchor_range != &query_range
 6249                })
 6250        {
 6251            let multi_buffer_start = multi_buffer_snapshot
 6252                .anchor_before(0)
 6253                .to_point(&multi_buffer_snapshot);
 6254            let multi_buffer_end = multi_buffer_snapshot
 6255                .anchor_after(multi_buffer_snapshot.len())
 6256                .to_point(&multi_buffer_snapshot);
 6257            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6258            self.debounced_selection_highlight_task = Some((
 6259                query_range.clone(),
 6260                self.update_selection_occurrence_highlights(
 6261                    query_text,
 6262                    query_range,
 6263                    multi_buffer_full_range,
 6264                    true,
 6265                    window,
 6266                    cx,
 6267                ),
 6268            ));
 6269        }
 6270    }
 6271
 6272    pub fn refresh_inline_completion(
 6273        &mut self,
 6274        debounce: bool,
 6275        user_requested: bool,
 6276        window: &mut Window,
 6277        cx: &mut Context<Self>,
 6278    ) -> Option<()> {
 6279        let provider = self.edit_prediction_provider()?;
 6280        let cursor = self.selections.newest_anchor().head();
 6281        let (buffer, cursor_buffer_position) =
 6282            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6283
 6284        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6285            self.discard_inline_completion(false, cx);
 6286            return None;
 6287        }
 6288
 6289        if !user_requested
 6290            && (!self.should_show_edit_predictions()
 6291                || !self.is_focused(window)
 6292                || buffer.read(cx).is_empty())
 6293        {
 6294            self.discard_inline_completion(false, cx);
 6295            return None;
 6296        }
 6297
 6298        self.update_visible_inline_completion(window, cx);
 6299        provider.refresh(
 6300            self.project.clone(),
 6301            buffer,
 6302            cursor_buffer_position,
 6303            debounce,
 6304            cx,
 6305        );
 6306        Some(())
 6307    }
 6308
 6309    fn show_edit_predictions_in_menu(&self) -> bool {
 6310        match self.edit_prediction_settings {
 6311            EditPredictionSettings::Disabled => false,
 6312            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6313        }
 6314    }
 6315
 6316    pub fn edit_predictions_enabled(&self) -> bool {
 6317        match self.edit_prediction_settings {
 6318            EditPredictionSettings::Disabled => false,
 6319            EditPredictionSettings::Enabled { .. } => true,
 6320        }
 6321    }
 6322
 6323    fn edit_prediction_requires_modifier(&self) -> bool {
 6324        match self.edit_prediction_settings {
 6325            EditPredictionSettings::Disabled => false,
 6326            EditPredictionSettings::Enabled {
 6327                preview_requires_modifier,
 6328                ..
 6329            } => preview_requires_modifier,
 6330        }
 6331    }
 6332
 6333    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6334        if self.edit_prediction_provider.is_none() {
 6335            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6336        } else {
 6337            let selection = self.selections.newest_anchor();
 6338            let cursor = selection.head();
 6339
 6340            if let Some((buffer, cursor_buffer_position)) =
 6341                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6342            {
 6343                self.edit_prediction_settings =
 6344                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6345            }
 6346        }
 6347    }
 6348
 6349    fn edit_prediction_settings_at_position(
 6350        &self,
 6351        buffer: &Entity<Buffer>,
 6352        buffer_position: language::Anchor,
 6353        cx: &App,
 6354    ) -> EditPredictionSettings {
 6355        if !self.mode.is_full()
 6356            || !self.show_inline_completions_override.unwrap_or(true)
 6357            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6358        {
 6359            return EditPredictionSettings::Disabled;
 6360        }
 6361
 6362        let buffer = buffer.read(cx);
 6363
 6364        let file = buffer.file();
 6365
 6366        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6367            return EditPredictionSettings::Disabled;
 6368        };
 6369
 6370        let by_provider = matches!(
 6371            self.menu_inline_completions_policy,
 6372            MenuInlineCompletionsPolicy::ByProvider
 6373        );
 6374
 6375        let show_in_menu = by_provider
 6376            && self
 6377                .edit_prediction_provider
 6378                .as_ref()
 6379                .map_or(false, |provider| {
 6380                    provider.provider.show_completions_in_menu()
 6381                });
 6382
 6383        let preview_requires_modifier =
 6384            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6385
 6386        EditPredictionSettings::Enabled {
 6387            show_in_menu,
 6388            preview_requires_modifier,
 6389        }
 6390    }
 6391
 6392    fn should_show_edit_predictions(&self) -> bool {
 6393        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6394    }
 6395
 6396    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6397        matches!(
 6398            self.edit_prediction_preview,
 6399            EditPredictionPreview::Active { .. }
 6400        )
 6401    }
 6402
 6403    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6404        let cursor = self.selections.newest_anchor().head();
 6405        if let Some((buffer, cursor_position)) =
 6406            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6407        {
 6408            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6409        } else {
 6410            false
 6411        }
 6412    }
 6413
 6414    pub fn supports_minimap(&self, cx: &App) -> bool {
 6415        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6416    }
 6417
 6418    fn edit_predictions_enabled_in_buffer(
 6419        &self,
 6420        buffer: &Entity<Buffer>,
 6421        buffer_position: language::Anchor,
 6422        cx: &App,
 6423    ) -> bool {
 6424        maybe!({
 6425            if self.read_only(cx) {
 6426                return Some(false);
 6427            }
 6428            let provider = self.edit_prediction_provider()?;
 6429            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6430                return Some(false);
 6431            }
 6432            let buffer = buffer.read(cx);
 6433            let Some(file) = buffer.file() else {
 6434                return Some(true);
 6435            };
 6436            let settings = all_language_settings(Some(file), cx);
 6437            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6438        })
 6439        .unwrap_or(false)
 6440    }
 6441
 6442    fn cycle_inline_completion(
 6443        &mut self,
 6444        direction: Direction,
 6445        window: &mut Window,
 6446        cx: &mut Context<Self>,
 6447    ) -> Option<()> {
 6448        let provider = self.edit_prediction_provider()?;
 6449        let cursor = self.selections.newest_anchor().head();
 6450        let (buffer, cursor_buffer_position) =
 6451            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6452        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6453            return None;
 6454        }
 6455
 6456        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6457        self.update_visible_inline_completion(window, cx);
 6458
 6459        Some(())
 6460    }
 6461
 6462    pub fn show_inline_completion(
 6463        &mut self,
 6464        _: &ShowEditPrediction,
 6465        window: &mut Window,
 6466        cx: &mut Context<Self>,
 6467    ) {
 6468        if !self.has_active_inline_completion() {
 6469            self.refresh_inline_completion(false, true, window, cx);
 6470            return;
 6471        }
 6472
 6473        self.update_visible_inline_completion(window, cx);
 6474    }
 6475
 6476    pub fn display_cursor_names(
 6477        &mut self,
 6478        _: &DisplayCursorNames,
 6479        window: &mut Window,
 6480        cx: &mut Context<Self>,
 6481    ) {
 6482        self.show_cursor_names(window, cx);
 6483    }
 6484
 6485    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6486        self.show_cursor_names = true;
 6487        cx.notify();
 6488        cx.spawn_in(window, async move |this, cx| {
 6489            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6490            this.update(cx, |this, cx| {
 6491                this.show_cursor_names = false;
 6492                cx.notify()
 6493            })
 6494            .ok()
 6495        })
 6496        .detach();
 6497    }
 6498
 6499    pub fn next_edit_prediction(
 6500        &mut self,
 6501        _: &NextEditPrediction,
 6502        window: &mut Window,
 6503        cx: &mut Context<Self>,
 6504    ) {
 6505        if self.has_active_inline_completion() {
 6506            self.cycle_inline_completion(Direction::Next, window, cx);
 6507        } else {
 6508            let is_copilot_disabled = self
 6509                .refresh_inline_completion(false, true, window, cx)
 6510                .is_none();
 6511            if is_copilot_disabled {
 6512                cx.propagate();
 6513            }
 6514        }
 6515    }
 6516
 6517    pub fn previous_edit_prediction(
 6518        &mut self,
 6519        _: &PreviousEditPrediction,
 6520        window: &mut Window,
 6521        cx: &mut Context<Self>,
 6522    ) {
 6523        if self.has_active_inline_completion() {
 6524            self.cycle_inline_completion(Direction::Prev, window, cx);
 6525        } else {
 6526            let is_copilot_disabled = self
 6527                .refresh_inline_completion(false, true, window, cx)
 6528                .is_none();
 6529            if is_copilot_disabled {
 6530                cx.propagate();
 6531            }
 6532        }
 6533    }
 6534
 6535    pub fn accept_edit_prediction(
 6536        &mut self,
 6537        _: &AcceptEditPrediction,
 6538        window: &mut Window,
 6539        cx: &mut Context<Self>,
 6540    ) {
 6541        if self.show_edit_predictions_in_menu() {
 6542            self.hide_context_menu(window, cx);
 6543        }
 6544
 6545        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6546            return;
 6547        };
 6548
 6549        self.report_inline_completion_event(
 6550            active_inline_completion.completion_id.clone(),
 6551            true,
 6552            cx,
 6553        );
 6554
 6555        match &active_inline_completion.completion {
 6556            InlineCompletion::Move { target, .. } => {
 6557                let target = *target;
 6558
 6559                if let Some(position_map) = &self.last_position_map {
 6560                    if position_map
 6561                        .visible_row_range
 6562                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6563                        || !self.edit_prediction_requires_modifier()
 6564                    {
 6565                        self.unfold_ranges(&[target..target], true, false, cx);
 6566                        // Note that this is also done in vim's handler of the Tab action.
 6567                        self.change_selections(
 6568                            Some(Autoscroll::newest()),
 6569                            window,
 6570                            cx,
 6571                            |selections| {
 6572                                selections.select_anchor_ranges([target..target]);
 6573                            },
 6574                        );
 6575                        self.clear_row_highlights::<EditPredictionPreview>();
 6576
 6577                        self.edit_prediction_preview
 6578                            .set_previous_scroll_position(None);
 6579                    } else {
 6580                        self.edit_prediction_preview
 6581                            .set_previous_scroll_position(Some(
 6582                                position_map.snapshot.scroll_anchor,
 6583                            ));
 6584
 6585                        self.highlight_rows::<EditPredictionPreview>(
 6586                            target..target,
 6587                            cx.theme().colors().editor_highlighted_line_background,
 6588                            RowHighlightOptions {
 6589                                autoscroll: true,
 6590                                ..Default::default()
 6591                            },
 6592                            cx,
 6593                        );
 6594                        self.request_autoscroll(Autoscroll::fit(), cx);
 6595                    }
 6596                }
 6597            }
 6598            InlineCompletion::Edit { edits, .. } => {
 6599                if let Some(provider) = self.edit_prediction_provider() {
 6600                    provider.accept(cx);
 6601                }
 6602
 6603                // Store the transaction ID and selections before applying the edit
 6604                let transaction_id_prev =
 6605                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6606
 6607                let snapshot = self.buffer.read(cx).snapshot(cx);
 6608                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6609
 6610                self.buffer.update(cx, |buffer, cx| {
 6611                    buffer.edit(edits.iter().cloned(), None, cx)
 6612                });
 6613
 6614                self.change_selections(None, window, cx, |s| {
 6615                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6616                });
 6617
 6618                let selections = self.selections.disjoint_anchors();
 6619                if let Some(transaction_id_now) =
 6620                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6621                {
 6622                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6623                    if has_new_transaction {
 6624                        self.selection_history
 6625                            .insert_transaction(transaction_id_now, selections);
 6626                    }
 6627                }
 6628
 6629                self.update_visible_inline_completion(window, cx);
 6630                if self.active_inline_completion.is_none() {
 6631                    self.refresh_inline_completion(true, true, window, cx);
 6632                }
 6633
 6634                cx.notify();
 6635            }
 6636        }
 6637
 6638        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6639    }
 6640
 6641    pub fn accept_partial_inline_completion(
 6642        &mut self,
 6643        _: &AcceptPartialEditPrediction,
 6644        window: &mut Window,
 6645        cx: &mut Context<Self>,
 6646    ) {
 6647        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6648            return;
 6649        };
 6650        if self.selections.count() != 1 {
 6651            return;
 6652        }
 6653
 6654        self.report_inline_completion_event(
 6655            active_inline_completion.completion_id.clone(),
 6656            true,
 6657            cx,
 6658        );
 6659
 6660        match &active_inline_completion.completion {
 6661            InlineCompletion::Move { target, .. } => {
 6662                let target = *target;
 6663                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6664                    selections.select_anchor_ranges([target..target]);
 6665                });
 6666            }
 6667            InlineCompletion::Edit { edits, .. } => {
 6668                // Find an insertion that starts at the cursor position.
 6669                let snapshot = self.buffer.read(cx).snapshot(cx);
 6670                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6671                let insertion = edits.iter().find_map(|(range, text)| {
 6672                    let range = range.to_offset(&snapshot);
 6673                    if range.is_empty() && range.start == cursor_offset {
 6674                        Some(text)
 6675                    } else {
 6676                        None
 6677                    }
 6678                });
 6679
 6680                if let Some(text) = insertion {
 6681                    let mut partial_completion = text
 6682                        .chars()
 6683                        .by_ref()
 6684                        .take_while(|c| c.is_alphabetic())
 6685                        .collect::<String>();
 6686                    if partial_completion.is_empty() {
 6687                        partial_completion = text
 6688                            .chars()
 6689                            .by_ref()
 6690                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6691                            .collect::<String>();
 6692                    }
 6693
 6694                    cx.emit(EditorEvent::InputHandled {
 6695                        utf16_range_to_replace: None,
 6696                        text: partial_completion.clone().into(),
 6697                    });
 6698
 6699                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6700
 6701                    self.refresh_inline_completion(true, true, window, cx);
 6702                    cx.notify();
 6703                } else {
 6704                    self.accept_edit_prediction(&Default::default(), window, cx);
 6705                }
 6706            }
 6707        }
 6708    }
 6709
 6710    fn discard_inline_completion(
 6711        &mut self,
 6712        should_report_inline_completion_event: bool,
 6713        cx: &mut Context<Self>,
 6714    ) -> bool {
 6715        if should_report_inline_completion_event {
 6716            let completion_id = self
 6717                .active_inline_completion
 6718                .as_ref()
 6719                .and_then(|active_completion| active_completion.completion_id.clone());
 6720
 6721            self.report_inline_completion_event(completion_id, false, cx);
 6722        }
 6723
 6724        if let Some(provider) = self.edit_prediction_provider() {
 6725            provider.discard(cx);
 6726        }
 6727
 6728        self.take_active_inline_completion(cx)
 6729    }
 6730
 6731    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6732        let Some(provider) = self.edit_prediction_provider() else {
 6733            return;
 6734        };
 6735
 6736        let Some((_, buffer, _)) = self
 6737            .buffer
 6738            .read(cx)
 6739            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6740        else {
 6741            return;
 6742        };
 6743
 6744        let extension = buffer
 6745            .read(cx)
 6746            .file()
 6747            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6748
 6749        let event_type = match accepted {
 6750            true => "Edit Prediction Accepted",
 6751            false => "Edit Prediction Discarded",
 6752        };
 6753        telemetry::event!(
 6754            event_type,
 6755            provider = provider.name(),
 6756            prediction_id = id,
 6757            suggestion_accepted = accepted,
 6758            file_extension = extension,
 6759        );
 6760    }
 6761
 6762    pub fn has_active_inline_completion(&self) -> bool {
 6763        self.active_inline_completion.is_some()
 6764    }
 6765
 6766    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6767        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6768            return false;
 6769        };
 6770
 6771        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6772        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6773        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6774        true
 6775    }
 6776
 6777    /// Returns true when we're displaying the edit prediction popover below the cursor
 6778    /// like we are not previewing and the LSP autocomplete menu is visible
 6779    /// or we are in `when_holding_modifier` mode.
 6780    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6781        if self.edit_prediction_preview_is_active()
 6782            || !self.show_edit_predictions_in_menu()
 6783            || !self.edit_predictions_enabled()
 6784        {
 6785            return false;
 6786        }
 6787
 6788        if self.has_visible_completions_menu() {
 6789            return true;
 6790        }
 6791
 6792        has_completion && self.edit_prediction_requires_modifier()
 6793    }
 6794
 6795    fn handle_modifiers_changed(
 6796        &mut self,
 6797        modifiers: Modifiers,
 6798        position_map: &PositionMap,
 6799        window: &mut Window,
 6800        cx: &mut Context<Self>,
 6801    ) {
 6802        if self.show_edit_predictions_in_menu() {
 6803            self.update_edit_prediction_preview(&modifiers, window, cx);
 6804        }
 6805
 6806        self.update_selection_mode(&modifiers, position_map, window, cx);
 6807
 6808        let mouse_position = window.mouse_position();
 6809        if !position_map.text_hitbox.is_hovered(window) {
 6810            return;
 6811        }
 6812
 6813        self.update_hovered_link(
 6814            position_map.point_for_position(mouse_position),
 6815            &position_map.snapshot,
 6816            modifiers,
 6817            window,
 6818            cx,
 6819        )
 6820    }
 6821
 6822    fn update_selection_mode(
 6823        &mut self,
 6824        modifiers: &Modifiers,
 6825        position_map: &PositionMap,
 6826        window: &mut Window,
 6827        cx: &mut Context<Self>,
 6828    ) {
 6829        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6830            return;
 6831        }
 6832
 6833        let mouse_position = window.mouse_position();
 6834        let point_for_position = position_map.point_for_position(mouse_position);
 6835        let position = point_for_position.previous_valid;
 6836
 6837        self.select(
 6838            SelectPhase::BeginColumnar {
 6839                position,
 6840                reset: false,
 6841                goal_column: point_for_position.exact_unclipped.column(),
 6842            },
 6843            window,
 6844            cx,
 6845        );
 6846    }
 6847
 6848    fn update_edit_prediction_preview(
 6849        &mut self,
 6850        modifiers: &Modifiers,
 6851        window: &mut Window,
 6852        cx: &mut Context<Self>,
 6853    ) {
 6854        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6855        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6856            return;
 6857        };
 6858
 6859        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6860            if matches!(
 6861                self.edit_prediction_preview,
 6862                EditPredictionPreview::Inactive { .. }
 6863            ) {
 6864                self.edit_prediction_preview = EditPredictionPreview::Active {
 6865                    previous_scroll_position: None,
 6866                    since: Instant::now(),
 6867                };
 6868
 6869                self.update_visible_inline_completion(window, cx);
 6870                cx.notify();
 6871            }
 6872        } else if let EditPredictionPreview::Active {
 6873            previous_scroll_position,
 6874            since,
 6875        } = self.edit_prediction_preview
 6876        {
 6877            if let (Some(previous_scroll_position), Some(position_map)) =
 6878                (previous_scroll_position, self.last_position_map.as_ref())
 6879            {
 6880                self.set_scroll_position(
 6881                    previous_scroll_position
 6882                        .scroll_position(&position_map.snapshot.display_snapshot),
 6883                    window,
 6884                    cx,
 6885                );
 6886            }
 6887
 6888            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6889                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6890            };
 6891            self.clear_row_highlights::<EditPredictionPreview>();
 6892            self.update_visible_inline_completion(window, cx);
 6893            cx.notify();
 6894        }
 6895    }
 6896
 6897    fn update_visible_inline_completion(
 6898        &mut self,
 6899        _window: &mut Window,
 6900        cx: &mut Context<Self>,
 6901    ) -> Option<()> {
 6902        let selection = self.selections.newest_anchor();
 6903        let cursor = selection.head();
 6904        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6905        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6906        let excerpt_id = cursor.excerpt_id;
 6907
 6908        let show_in_menu = self.show_edit_predictions_in_menu();
 6909        let completions_menu_has_precedence = !show_in_menu
 6910            && (self.context_menu.borrow().is_some()
 6911                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6912
 6913        if completions_menu_has_precedence
 6914            || !offset_selection.is_empty()
 6915            || self
 6916                .active_inline_completion
 6917                .as_ref()
 6918                .map_or(false, |completion| {
 6919                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6920                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6921                    !invalidation_range.contains(&offset_selection.head())
 6922                })
 6923        {
 6924            self.discard_inline_completion(false, cx);
 6925            return None;
 6926        }
 6927
 6928        self.take_active_inline_completion(cx);
 6929        let Some(provider) = self.edit_prediction_provider() else {
 6930            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6931            return None;
 6932        };
 6933
 6934        let (buffer, cursor_buffer_position) =
 6935            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6936
 6937        self.edit_prediction_settings =
 6938            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6939
 6940        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6941
 6942        if self.edit_prediction_indent_conflict {
 6943            let cursor_point = cursor.to_point(&multibuffer);
 6944
 6945            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6946
 6947            if let Some((_, indent)) = indents.iter().next() {
 6948                if indent.len == cursor_point.column {
 6949                    self.edit_prediction_indent_conflict = false;
 6950                }
 6951            }
 6952        }
 6953
 6954        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6955        let edits = inline_completion
 6956            .edits
 6957            .into_iter()
 6958            .flat_map(|(range, new_text)| {
 6959                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6960                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6961                Some((start..end, new_text))
 6962            })
 6963            .collect::<Vec<_>>();
 6964        if edits.is_empty() {
 6965            return None;
 6966        }
 6967
 6968        let first_edit_start = edits.first().unwrap().0.start;
 6969        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6970        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6971
 6972        let last_edit_end = edits.last().unwrap().0.end;
 6973        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6974        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6975
 6976        let cursor_row = cursor.to_point(&multibuffer).row;
 6977
 6978        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6979
 6980        let mut inlay_ids = Vec::new();
 6981        let invalidation_row_range;
 6982        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6983            Some(cursor_row..edit_end_row)
 6984        } else if cursor_row > edit_end_row {
 6985            Some(edit_start_row..cursor_row)
 6986        } else {
 6987            None
 6988        };
 6989        let is_move =
 6990            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6991        let completion = if is_move {
 6992            invalidation_row_range =
 6993                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6994            let target = first_edit_start;
 6995            InlineCompletion::Move { target, snapshot }
 6996        } else {
 6997            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6998                && !self.inline_completions_hidden_for_vim_mode;
 6999
 7000            if show_completions_in_buffer {
 7001                if edits
 7002                    .iter()
 7003                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7004                {
 7005                    let mut inlays = Vec::new();
 7006                    for (range, new_text) in &edits {
 7007                        let inlay = Inlay::inline_completion(
 7008                            post_inc(&mut self.next_inlay_id),
 7009                            range.start,
 7010                            new_text.as_str(),
 7011                        );
 7012                        inlay_ids.push(inlay.id);
 7013                        inlays.push(inlay);
 7014                    }
 7015
 7016                    self.splice_inlays(&[], inlays, cx);
 7017                } else {
 7018                    let background_color = cx.theme().status().deleted_background;
 7019                    self.highlight_text::<InlineCompletionHighlight>(
 7020                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7021                        HighlightStyle {
 7022                            background_color: Some(background_color),
 7023                            ..Default::default()
 7024                        },
 7025                        cx,
 7026                    );
 7027                }
 7028            }
 7029
 7030            invalidation_row_range = edit_start_row..edit_end_row;
 7031
 7032            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7033                if provider.show_tab_accept_marker() {
 7034                    EditDisplayMode::TabAccept
 7035                } else {
 7036                    EditDisplayMode::Inline
 7037                }
 7038            } else {
 7039                EditDisplayMode::DiffPopover
 7040            };
 7041
 7042            InlineCompletion::Edit {
 7043                edits,
 7044                edit_preview: inline_completion.edit_preview,
 7045                display_mode,
 7046                snapshot,
 7047            }
 7048        };
 7049
 7050        let invalidation_range = multibuffer
 7051            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7052            ..multibuffer.anchor_after(Point::new(
 7053                invalidation_row_range.end,
 7054                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7055            ));
 7056
 7057        self.stale_inline_completion_in_menu = None;
 7058        self.active_inline_completion = Some(InlineCompletionState {
 7059            inlay_ids,
 7060            completion,
 7061            completion_id: inline_completion.id,
 7062            invalidation_range,
 7063        });
 7064
 7065        cx.notify();
 7066
 7067        Some(())
 7068    }
 7069
 7070    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7071        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7072    }
 7073
 7074    fn clear_tasks(&mut self) {
 7075        self.tasks.clear()
 7076    }
 7077
 7078    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7079        if self.tasks.insert(key, value).is_some() {
 7080            // This case should hopefully be rare, but just in case...
 7081            log::error!(
 7082                "multiple different run targets found on a single line, only the last target will be rendered"
 7083            )
 7084        }
 7085    }
 7086
 7087    /// Get all display points of breakpoints that will be rendered within editor
 7088    ///
 7089    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7090    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7091    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7092    fn active_breakpoints(
 7093        &self,
 7094        range: Range<DisplayRow>,
 7095        window: &mut Window,
 7096        cx: &mut Context<Self>,
 7097    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7098        let mut breakpoint_display_points = HashMap::default();
 7099
 7100        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7101            return breakpoint_display_points;
 7102        };
 7103
 7104        let snapshot = self.snapshot(window, cx);
 7105
 7106        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7107        let Some(project) = self.project.as_ref() else {
 7108            return breakpoint_display_points;
 7109        };
 7110
 7111        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7112            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7113
 7114        for (buffer_snapshot, range, excerpt_id) in
 7115            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7116        {
 7117            let Some(buffer) = project.read_with(cx, |this, cx| {
 7118                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7119            }) else {
 7120                continue;
 7121            };
 7122            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7123                &buffer,
 7124                Some(
 7125                    buffer_snapshot.anchor_before(range.start)
 7126                        ..buffer_snapshot.anchor_after(range.end),
 7127                ),
 7128                buffer_snapshot,
 7129                cx,
 7130            );
 7131            for (breakpoint, state) in breakpoints {
 7132                let multi_buffer_anchor =
 7133                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7134                let position = multi_buffer_anchor
 7135                    .to_point(&multi_buffer_snapshot)
 7136                    .to_display_point(&snapshot);
 7137
 7138                breakpoint_display_points.insert(
 7139                    position.row(),
 7140                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7141                );
 7142            }
 7143        }
 7144
 7145        breakpoint_display_points
 7146    }
 7147
 7148    fn breakpoint_context_menu(
 7149        &self,
 7150        anchor: Anchor,
 7151        window: &mut Window,
 7152        cx: &mut Context<Self>,
 7153    ) -> Entity<ui::ContextMenu> {
 7154        let weak_editor = cx.weak_entity();
 7155        let focus_handle = self.focus_handle(cx);
 7156
 7157        let row = self
 7158            .buffer
 7159            .read(cx)
 7160            .snapshot(cx)
 7161            .summary_for_anchor::<Point>(&anchor)
 7162            .row;
 7163
 7164        let breakpoint = self
 7165            .breakpoint_at_row(row, window, cx)
 7166            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7167
 7168        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7169            "Edit Log Breakpoint"
 7170        } else {
 7171            "Set Log Breakpoint"
 7172        };
 7173
 7174        let condition_breakpoint_msg = if breakpoint
 7175            .as_ref()
 7176            .is_some_and(|bp| bp.1.condition.is_some())
 7177        {
 7178            "Edit Condition Breakpoint"
 7179        } else {
 7180            "Set Condition Breakpoint"
 7181        };
 7182
 7183        let hit_condition_breakpoint_msg = if breakpoint
 7184            .as_ref()
 7185            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7186        {
 7187            "Edit Hit Condition Breakpoint"
 7188        } else {
 7189            "Set Hit Condition Breakpoint"
 7190        };
 7191
 7192        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7193            "Unset Breakpoint"
 7194        } else {
 7195            "Set Breakpoint"
 7196        };
 7197
 7198        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7199            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7200
 7201        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7202            BreakpointState::Enabled => Some("Disable"),
 7203            BreakpointState::Disabled => Some("Enable"),
 7204        });
 7205
 7206        let (anchor, breakpoint) =
 7207            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7208
 7209        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7210            menu.on_blur_subscription(Subscription::new(|| {}))
 7211                .context(focus_handle)
 7212                .when(run_to_cursor, |this| {
 7213                    let weak_editor = weak_editor.clone();
 7214                    this.entry("Run to cursor", None, move |window, cx| {
 7215                        weak_editor
 7216                            .update(cx, |editor, cx| {
 7217                                editor.change_selections(None, window, cx, |s| {
 7218                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7219                                });
 7220                            })
 7221                            .ok();
 7222
 7223                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7224                    })
 7225                    .separator()
 7226                })
 7227                .when_some(toggle_state_msg, |this, msg| {
 7228                    this.entry(msg, None, {
 7229                        let weak_editor = weak_editor.clone();
 7230                        let breakpoint = breakpoint.clone();
 7231                        move |_window, cx| {
 7232                            weak_editor
 7233                                .update(cx, |this, cx| {
 7234                                    this.edit_breakpoint_at_anchor(
 7235                                        anchor,
 7236                                        breakpoint.as_ref().clone(),
 7237                                        BreakpointEditAction::InvertState,
 7238                                        cx,
 7239                                    );
 7240                                })
 7241                                .log_err();
 7242                        }
 7243                    })
 7244                })
 7245                .entry(set_breakpoint_msg, None, {
 7246                    let weak_editor = weak_editor.clone();
 7247                    let breakpoint = breakpoint.clone();
 7248                    move |_window, cx| {
 7249                        weak_editor
 7250                            .update(cx, |this, cx| {
 7251                                this.edit_breakpoint_at_anchor(
 7252                                    anchor,
 7253                                    breakpoint.as_ref().clone(),
 7254                                    BreakpointEditAction::Toggle,
 7255                                    cx,
 7256                                );
 7257                            })
 7258                            .log_err();
 7259                    }
 7260                })
 7261                .entry(log_breakpoint_msg, None, {
 7262                    let breakpoint = breakpoint.clone();
 7263                    let weak_editor = weak_editor.clone();
 7264                    move |window, cx| {
 7265                        weak_editor
 7266                            .update(cx, |this, cx| {
 7267                                this.add_edit_breakpoint_block(
 7268                                    anchor,
 7269                                    breakpoint.as_ref(),
 7270                                    BreakpointPromptEditAction::Log,
 7271                                    window,
 7272                                    cx,
 7273                                );
 7274                            })
 7275                            .log_err();
 7276                    }
 7277                })
 7278                .entry(condition_breakpoint_msg, None, {
 7279                    let breakpoint = breakpoint.clone();
 7280                    let weak_editor = weak_editor.clone();
 7281                    move |window, cx| {
 7282                        weak_editor
 7283                            .update(cx, |this, cx| {
 7284                                this.add_edit_breakpoint_block(
 7285                                    anchor,
 7286                                    breakpoint.as_ref(),
 7287                                    BreakpointPromptEditAction::Condition,
 7288                                    window,
 7289                                    cx,
 7290                                );
 7291                            })
 7292                            .log_err();
 7293                    }
 7294                })
 7295                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7296                    weak_editor
 7297                        .update(cx, |this, cx| {
 7298                            this.add_edit_breakpoint_block(
 7299                                anchor,
 7300                                breakpoint.as_ref(),
 7301                                BreakpointPromptEditAction::HitCondition,
 7302                                window,
 7303                                cx,
 7304                            );
 7305                        })
 7306                        .log_err();
 7307                })
 7308        })
 7309    }
 7310
 7311    fn render_breakpoint(
 7312        &self,
 7313        position: Anchor,
 7314        row: DisplayRow,
 7315        breakpoint: &Breakpoint,
 7316        state: Option<BreakpointSessionState>,
 7317        cx: &mut Context<Self>,
 7318    ) -> IconButton {
 7319        let is_rejected = state.is_some_and(|s| !s.verified);
 7320        // Is it a breakpoint that shows up when hovering over gutter?
 7321        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7322            (false, false),
 7323            |PhantomBreakpointIndicator {
 7324                 is_active,
 7325                 display_row,
 7326                 collides_with_existing_breakpoint,
 7327             }| {
 7328                (
 7329                    is_active && display_row == row,
 7330                    collides_with_existing_breakpoint,
 7331                )
 7332            },
 7333        );
 7334
 7335        let (color, icon) = {
 7336            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7337                (false, false) => ui::IconName::DebugBreakpoint,
 7338                (true, false) => ui::IconName::DebugLogBreakpoint,
 7339                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7340                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7341            };
 7342
 7343            let color = if is_phantom {
 7344                Color::Hint
 7345            } else if is_rejected {
 7346                Color::Disabled
 7347            } else {
 7348                Color::Debugger
 7349            };
 7350
 7351            (color, icon)
 7352        };
 7353
 7354        let breakpoint = Arc::from(breakpoint.clone());
 7355
 7356        let alt_as_text = gpui::Keystroke {
 7357            modifiers: Modifiers::secondary_key(),
 7358            ..Default::default()
 7359        };
 7360        let primary_action_text = if breakpoint.is_disabled() {
 7361            "Enable breakpoint"
 7362        } else if is_phantom && !collides_with_existing {
 7363            "Set breakpoint"
 7364        } else {
 7365            "Unset breakpoint"
 7366        };
 7367        let focus_handle = self.focus_handle.clone();
 7368
 7369        let meta = if is_rejected {
 7370            SharedString::from("No executable code is associated with this line.")
 7371        } else if collides_with_existing && !breakpoint.is_disabled() {
 7372            SharedString::from(format!(
 7373                "{alt_as_text}-click to disable,\nright-click for more options."
 7374            ))
 7375        } else {
 7376            SharedString::from("Right-click for more options.")
 7377        };
 7378        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7379            .icon_size(IconSize::XSmall)
 7380            .size(ui::ButtonSize::None)
 7381            .when(is_rejected, |this| {
 7382                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7383            })
 7384            .icon_color(color)
 7385            .style(ButtonStyle::Transparent)
 7386            .on_click(cx.listener({
 7387                let breakpoint = breakpoint.clone();
 7388
 7389                move |editor, event: &ClickEvent, window, cx| {
 7390                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7391                        BreakpointEditAction::InvertState
 7392                    } else {
 7393                        BreakpointEditAction::Toggle
 7394                    };
 7395
 7396                    window.focus(&editor.focus_handle(cx));
 7397                    editor.edit_breakpoint_at_anchor(
 7398                        position,
 7399                        breakpoint.as_ref().clone(),
 7400                        edit_action,
 7401                        cx,
 7402                    );
 7403                }
 7404            }))
 7405            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7406                editor.set_breakpoint_context_menu(
 7407                    row,
 7408                    Some(position),
 7409                    event.down.position,
 7410                    window,
 7411                    cx,
 7412                );
 7413            }))
 7414            .tooltip(move |window, cx| {
 7415                Tooltip::with_meta_in(
 7416                    primary_action_text,
 7417                    Some(&ToggleBreakpoint),
 7418                    meta.clone(),
 7419                    &focus_handle,
 7420                    window,
 7421                    cx,
 7422                )
 7423            })
 7424    }
 7425
 7426    fn build_tasks_context(
 7427        project: &Entity<Project>,
 7428        buffer: &Entity<Buffer>,
 7429        buffer_row: u32,
 7430        tasks: &Arc<RunnableTasks>,
 7431        cx: &mut Context<Self>,
 7432    ) -> Task<Option<task::TaskContext>> {
 7433        let position = Point::new(buffer_row, tasks.column);
 7434        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7435        let location = Location {
 7436            buffer: buffer.clone(),
 7437            range: range_start..range_start,
 7438        };
 7439        // Fill in the environmental variables from the tree-sitter captures
 7440        let mut captured_task_variables = TaskVariables::default();
 7441        for (capture_name, value) in tasks.extra_variables.clone() {
 7442            captured_task_variables.insert(
 7443                task::VariableName::Custom(capture_name.into()),
 7444                value.clone(),
 7445            );
 7446        }
 7447        project.update(cx, |project, cx| {
 7448            project.task_store().update(cx, |task_store, cx| {
 7449                task_store.task_context_for_location(captured_task_variables, location, cx)
 7450            })
 7451        })
 7452    }
 7453
 7454    pub fn spawn_nearest_task(
 7455        &mut self,
 7456        action: &SpawnNearestTask,
 7457        window: &mut Window,
 7458        cx: &mut Context<Self>,
 7459    ) {
 7460        let Some((workspace, _)) = self.workspace.clone() else {
 7461            return;
 7462        };
 7463        let Some(project) = self.project.clone() else {
 7464            return;
 7465        };
 7466
 7467        // Try to find a closest, enclosing node using tree-sitter that has a
 7468        // task
 7469        let Some((buffer, buffer_row, tasks)) = self
 7470            .find_enclosing_node_task(cx)
 7471            // Or find the task that's closest in row-distance.
 7472            .or_else(|| self.find_closest_task(cx))
 7473        else {
 7474            return;
 7475        };
 7476
 7477        let reveal_strategy = action.reveal;
 7478        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7479        cx.spawn_in(window, async move |_, cx| {
 7480            let context = task_context.await?;
 7481            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7482
 7483            let resolved = &mut resolved_task.resolved;
 7484            resolved.reveal = reveal_strategy;
 7485
 7486            workspace
 7487                .update_in(cx, |workspace, window, cx| {
 7488                    workspace.schedule_resolved_task(
 7489                        task_source_kind,
 7490                        resolved_task,
 7491                        false,
 7492                        window,
 7493                        cx,
 7494                    );
 7495                })
 7496                .ok()
 7497        })
 7498        .detach();
 7499    }
 7500
 7501    fn find_closest_task(
 7502        &mut self,
 7503        cx: &mut Context<Self>,
 7504    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7505        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7506
 7507        let ((buffer_id, row), tasks) = self
 7508            .tasks
 7509            .iter()
 7510            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7511
 7512        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7513        let tasks = Arc::new(tasks.to_owned());
 7514        Some((buffer, *row, tasks))
 7515    }
 7516
 7517    fn find_enclosing_node_task(
 7518        &mut self,
 7519        cx: &mut Context<Self>,
 7520    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7521        let snapshot = self.buffer.read(cx).snapshot(cx);
 7522        let offset = self.selections.newest::<usize>(cx).head();
 7523        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7524        let buffer_id = excerpt.buffer().remote_id();
 7525
 7526        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7527        let mut cursor = layer.node().walk();
 7528
 7529        while cursor.goto_first_child_for_byte(offset).is_some() {
 7530            if cursor.node().end_byte() == offset {
 7531                cursor.goto_next_sibling();
 7532            }
 7533        }
 7534
 7535        // Ascend to the smallest ancestor that contains the range and has a task.
 7536        loop {
 7537            let node = cursor.node();
 7538            let node_range = node.byte_range();
 7539            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7540
 7541            // Check if this node contains our offset
 7542            if node_range.start <= offset && node_range.end >= offset {
 7543                // If it contains offset, check for task
 7544                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7545                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7546                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7547                }
 7548            }
 7549
 7550            if !cursor.goto_parent() {
 7551                break;
 7552            }
 7553        }
 7554        None
 7555    }
 7556
 7557    fn render_run_indicator(
 7558        &self,
 7559        _style: &EditorStyle,
 7560        is_active: bool,
 7561        row: DisplayRow,
 7562        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7563        cx: &mut Context<Self>,
 7564    ) -> IconButton {
 7565        let color = Color::Muted;
 7566        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7567
 7568        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7569            .shape(ui::IconButtonShape::Square)
 7570            .icon_size(IconSize::XSmall)
 7571            .icon_color(color)
 7572            .toggle_state(is_active)
 7573            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7574                let quick_launch = e.down.button == MouseButton::Left;
 7575                window.focus(&editor.focus_handle(cx));
 7576                editor.toggle_code_actions(
 7577                    &ToggleCodeActions {
 7578                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7579                        quick_launch,
 7580                    },
 7581                    window,
 7582                    cx,
 7583                );
 7584            }))
 7585            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7586                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7587            }))
 7588    }
 7589
 7590    pub fn context_menu_visible(&self) -> bool {
 7591        !self.edit_prediction_preview_is_active()
 7592            && self
 7593                .context_menu
 7594                .borrow()
 7595                .as_ref()
 7596                .map_or(false, |menu| menu.visible())
 7597    }
 7598
 7599    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7600        self.context_menu
 7601            .borrow()
 7602            .as_ref()
 7603            .map(|menu| menu.origin())
 7604    }
 7605
 7606    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7607        self.context_menu_options = Some(options);
 7608    }
 7609
 7610    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7611    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7612
 7613    fn render_edit_prediction_popover(
 7614        &mut self,
 7615        text_bounds: &Bounds<Pixels>,
 7616        content_origin: gpui::Point<Pixels>,
 7617        right_margin: Pixels,
 7618        editor_snapshot: &EditorSnapshot,
 7619        visible_row_range: Range<DisplayRow>,
 7620        scroll_top: f32,
 7621        scroll_bottom: f32,
 7622        line_layouts: &[LineWithInvisibles],
 7623        line_height: Pixels,
 7624        scroll_pixel_position: gpui::Point<Pixels>,
 7625        newest_selection_head: Option<DisplayPoint>,
 7626        editor_width: Pixels,
 7627        style: &EditorStyle,
 7628        window: &mut Window,
 7629        cx: &mut App,
 7630    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7631        if self.mode().is_minimap() {
 7632            return None;
 7633        }
 7634        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7635
 7636        if self.edit_prediction_visible_in_cursor_popover(true) {
 7637            return None;
 7638        }
 7639
 7640        match &active_inline_completion.completion {
 7641            InlineCompletion::Move { target, .. } => {
 7642                let target_display_point = target.to_display_point(editor_snapshot);
 7643
 7644                if self.edit_prediction_requires_modifier() {
 7645                    if !self.edit_prediction_preview_is_active() {
 7646                        return None;
 7647                    }
 7648
 7649                    self.render_edit_prediction_modifier_jump_popover(
 7650                        text_bounds,
 7651                        content_origin,
 7652                        visible_row_range,
 7653                        line_layouts,
 7654                        line_height,
 7655                        scroll_pixel_position,
 7656                        newest_selection_head,
 7657                        target_display_point,
 7658                        window,
 7659                        cx,
 7660                    )
 7661                } else {
 7662                    self.render_edit_prediction_eager_jump_popover(
 7663                        text_bounds,
 7664                        content_origin,
 7665                        editor_snapshot,
 7666                        visible_row_range,
 7667                        scroll_top,
 7668                        scroll_bottom,
 7669                        line_height,
 7670                        scroll_pixel_position,
 7671                        target_display_point,
 7672                        editor_width,
 7673                        window,
 7674                        cx,
 7675                    )
 7676                }
 7677            }
 7678            InlineCompletion::Edit {
 7679                display_mode: EditDisplayMode::Inline,
 7680                ..
 7681            } => None,
 7682            InlineCompletion::Edit {
 7683                display_mode: EditDisplayMode::TabAccept,
 7684                edits,
 7685                ..
 7686            } => {
 7687                let range = &edits.first()?.0;
 7688                let target_display_point = range.end.to_display_point(editor_snapshot);
 7689
 7690                self.render_edit_prediction_end_of_line_popover(
 7691                    "Accept",
 7692                    editor_snapshot,
 7693                    visible_row_range,
 7694                    target_display_point,
 7695                    line_height,
 7696                    scroll_pixel_position,
 7697                    content_origin,
 7698                    editor_width,
 7699                    window,
 7700                    cx,
 7701                )
 7702            }
 7703            InlineCompletion::Edit {
 7704                edits,
 7705                edit_preview,
 7706                display_mode: EditDisplayMode::DiffPopover,
 7707                snapshot,
 7708            } => self.render_edit_prediction_diff_popover(
 7709                text_bounds,
 7710                content_origin,
 7711                right_margin,
 7712                editor_snapshot,
 7713                visible_row_range,
 7714                line_layouts,
 7715                line_height,
 7716                scroll_pixel_position,
 7717                newest_selection_head,
 7718                editor_width,
 7719                style,
 7720                edits,
 7721                edit_preview,
 7722                snapshot,
 7723                window,
 7724                cx,
 7725            ),
 7726        }
 7727    }
 7728
 7729    fn render_edit_prediction_modifier_jump_popover(
 7730        &mut self,
 7731        text_bounds: &Bounds<Pixels>,
 7732        content_origin: gpui::Point<Pixels>,
 7733        visible_row_range: Range<DisplayRow>,
 7734        line_layouts: &[LineWithInvisibles],
 7735        line_height: Pixels,
 7736        scroll_pixel_position: gpui::Point<Pixels>,
 7737        newest_selection_head: Option<DisplayPoint>,
 7738        target_display_point: DisplayPoint,
 7739        window: &mut Window,
 7740        cx: &mut App,
 7741    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7742        let scrolled_content_origin =
 7743            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7744
 7745        const SCROLL_PADDING_Y: Pixels = px(12.);
 7746
 7747        if target_display_point.row() < visible_row_range.start {
 7748            return self.render_edit_prediction_scroll_popover(
 7749                |_| SCROLL_PADDING_Y,
 7750                IconName::ArrowUp,
 7751                visible_row_range,
 7752                line_layouts,
 7753                newest_selection_head,
 7754                scrolled_content_origin,
 7755                window,
 7756                cx,
 7757            );
 7758        } else if target_display_point.row() >= visible_row_range.end {
 7759            return self.render_edit_prediction_scroll_popover(
 7760                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7761                IconName::ArrowDown,
 7762                visible_row_range,
 7763                line_layouts,
 7764                newest_selection_head,
 7765                scrolled_content_origin,
 7766                window,
 7767                cx,
 7768            );
 7769        }
 7770
 7771        const POLE_WIDTH: Pixels = px(2.);
 7772
 7773        let line_layout =
 7774            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7775        let target_column = target_display_point.column() as usize;
 7776
 7777        let target_x = line_layout.x_for_index(target_column);
 7778        let target_y =
 7779            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7780
 7781        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7782
 7783        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7784        border_color.l += 0.001;
 7785
 7786        let mut element = v_flex()
 7787            .items_end()
 7788            .when(flag_on_right, |el| el.items_start())
 7789            .child(if flag_on_right {
 7790                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7791                    .rounded_bl(px(0.))
 7792                    .rounded_tl(px(0.))
 7793                    .border_l_2()
 7794                    .border_color(border_color)
 7795            } else {
 7796                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7797                    .rounded_br(px(0.))
 7798                    .rounded_tr(px(0.))
 7799                    .border_r_2()
 7800                    .border_color(border_color)
 7801            })
 7802            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7803            .into_any();
 7804
 7805        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7806
 7807        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7808            - point(
 7809                if flag_on_right {
 7810                    POLE_WIDTH
 7811                } else {
 7812                    size.width - POLE_WIDTH
 7813                },
 7814                size.height - line_height,
 7815            );
 7816
 7817        origin.x = origin.x.max(content_origin.x);
 7818
 7819        element.prepaint_at(origin, window, cx);
 7820
 7821        Some((element, origin))
 7822    }
 7823
 7824    fn render_edit_prediction_scroll_popover(
 7825        &mut self,
 7826        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7827        scroll_icon: IconName,
 7828        visible_row_range: Range<DisplayRow>,
 7829        line_layouts: &[LineWithInvisibles],
 7830        newest_selection_head: Option<DisplayPoint>,
 7831        scrolled_content_origin: gpui::Point<Pixels>,
 7832        window: &mut Window,
 7833        cx: &mut App,
 7834    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7835        let mut element = self
 7836            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7837            .into_any();
 7838
 7839        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7840
 7841        let cursor = newest_selection_head?;
 7842        let cursor_row_layout =
 7843            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7844        let cursor_column = cursor.column() as usize;
 7845
 7846        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7847
 7848        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7849
 7850        element.prepaint_at(origin, window, cx);
 7851        Some((element, origin))
 7852    }
 7853
 7854    fn render_edit_prediction_eager_jump_popover(
 7855        &mut self,
 7856        text_bounds: &Bounds<Pixels>,
 7857        content_origin: gpui::Point<Pixels>,
 7858        editor_snapshot: &EditorSnapshot,
 7859        visible_row_range: Range<DisplayRow>,
 7860        scroll_top: f32,
 7861        scroll_bottom: f32,
 7862        line_height: Pixels,
 7863        scroll_pixel_position: gpui::Point<Pixels>,
 7864        target_display_point: DisplayPoint,
 7865        editor_width: Pixels,
 7866        window: &mut Window,
 7867        cx: &mut App,
 7868    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7869        if target_display_point.row().as_f32() < scroll_top {
 7870            let mut element = self
 7871                .render_edit_prediction_line_popover(
 7872                    "Jump to Edit",
 7873                    Some(IconName::ArrowUp),
 7874                    window,
 7875                    cx,
 7876                )?
 7877                .into_any();
 7878
 7879            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7880            let offset = point(
 7881                (text_bounds.size.width - size.width) / 2.,
 7882                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7883            );
 7884
 7885            let origin = text_bounds.origin + offset;
 7886            element.prepaint_at(origin, window, cx);
 7887            Some((element, origin))
 7888        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7889            let mut element = self
 7890                .render_edit_prediction_line_popover(
 7891                    "Jump to Edit",
 7892                    Some(IconName::ArrowDown),
 7893                    window,
 7894                    cx,
 7895                )?
 7896                .into_any();
 7897
 7898            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7899            let offset = point(
 7900                (text_bounds.size.width - size.width) / 2.,
 7901                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7902            );
 7903
 7904            let origin = text_bounds.origin + offset;
 7905            element.prepaint_at(origin, window, cx);
 7906            Some((element, origin))
 7907        } else {
 7908            self.render_edit_prediction_end_of_line_popover(
 7909                "Jump to Edit",
 7910                editor_snapshot,
 7911                visible_row_range,
 7912                target_display_point,
 7913                line_height,
 7914                scroll_pixel_position,
 7915                content_origin,
 7916                editor_width,
 7917                window,
 7918                cx,
 7919            )
 7920        }
 7921    }
 7922
 7923    fn render_edit_prediction_end_of_line_popover(
 7924        self: &mut Editor,
 7925        label: &'static str,
 7926        editor_snapshot: &EditorSnapshot,
 7927        visible_row_range: Range<DisplayRow>,
 7928        target_display_point: DisplayPoint,
 7929        line_height: Pixels,
 7930        scroll_pixel_position: gpui::Point<Pixels>,
 7931        content_origin: gpui::Point<Pixels>,
 7932        editor_width: Pixels,
 7933        window: &mut Window,
 7934        cx: &mut App,
 7935    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7936        let target_line_end = DisplayPoint::new(
 7937            target_display_point.row(),
 7938            editor_snapshot.line_len(target_display_point.row()),
 7939        );
 7940
 7941        let mut element = self
 7942            .render_edit_prediction_line_popover(label, None, window, cx)?
 7943            .into_any();
 7944
 7945        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7946
 7947        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7948
 7949        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7950        let mut origin = start_point
 7951            + line_origin
 7952            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7953        origin.x = origin.x.max(content_origin.x);
 7954
 7955        let max_x = content_origin.x + editor_width - size.width;
 7956
 7957        if origin.x > max_x {
 7958            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7959
 7960            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7961                origin.y += offset;
 7962                IconName::ArrowUp
 7963            } else {
 7964                origin.y -= offset;
 7965                IconName::ArrowDown
 7966            };
 7967
 7968            element = self
 7969                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7970                .into_any();
 7971
 7972            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7973
 7974            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7975        }
 7976
 7977        element.prepaint_at(origin, window, cx);
 7978        Some((element, origin))
 7979    }
 7980
 7981    fn render_edit_prediction_diff_popover(
 7982        self: &Editor,
 7983        text_bounds: &Bounds<Pixels>,
 7984        content_origin: gpui::Point<Pixels>,
 7985        right_margin: Pixels,
 7986        editor_snapshot: &EditorSnapshot,
 7987        visible_row_range: Range<DisplayRow>,
 7988        line_layouts: &[LineWithInvisibles],
 7989        line_height: Pixels,
 7990        scroll_pixel_position: gpui::Point<Pixels>,
 7991        newest_selection_head: Option<DisplayPoint>,
 7992        editor_width: Pixels,
 7993        style: &EditorStyle,
 7994        edits: &Vec<(Range<Anchor>, String)>,
 7995        edit_preview: &Option<language::EditPreview>,
 7996        snapshot: &language::BufferSnapshot,
 7997        window: &mut Window,
 7998        cx: &mut App,
 7999    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8000        let edit_start = edits
 8001            .first()
 8002            .unwrap()
 8003            .0
 8004            .start
 8005            .to_display_point(editor_snapshot);
 8006        let edit_end = edits
 8007            .last()
 8008            .unwrap()
 8009            .0
 8010            .end
 8011            .to_display_point(editor_snapshot);
 8012
 8013        let is_visible = visible_row_range.contains(&edit_start.row())
 8014            || visible_row_range.contains(&edit_end.row());
 8015        if !is_visible {
 8016            return None;
 8017        }
 8018
 8019        let highlighted_edits =
 8020            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8021
 8022        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8023        let line_count = highlighted_edits.text.lines().count();
 8024
 8025        const BORDER_WIDTH: Pixels = px(1.);
 8026
 8027        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8028        let has_keybind = keybind.is_some();
 8029
 8030        let mut element = h_flex()
 8031            .items_start()
 8032            .child(
 8033                h_flex()
 8034                    .bg(cx.theme().colors().editor_background)
 8035                    .border(BORDER_WIDTH)
 8036                    .shadow_sm()
 8037                    .border_color(cx.theme().colors().border)
 8038                    .rounded_l_lg()
 8039                    .when(line_count > 1, |el| el.rounded_br_lg())
 8040                    .pr_1()
 8041                    .child(styled_text),
 8042            )
 8043            .child(
 8044                h_flex()
 8045                    .h(line_height + BORDER_WIDTH * 2.)
 8046                    .px_1p5()
 8047                    .gap_1()
 8048                    // Workaround: For some reason, there's a gap if we don't do this
 8049                    .ml(-BORDER_WIDTH)
 8050                    .shadow(vec![gpui::BoxShadow {
 8051                        color: gpui::black().opacity(0.05),
 8052                        offset: point(px(1.), px(1.)),
 8053                        blur_radius: px(2.),
 8054                        spread_radius: px(0.),
 8055                    }])
 8056                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8057                    .border(BORDER_WIDTH)
 8058                    .border_color(cx.theme().colors().border)
 8059                    .rounded_r_lg()
 8060                    .id("edit_prediction_diff_popover_keybind")
 8061                    .when(!has_keybind, |el| {
 8062                        let status_colors = cx.theme().status();
 8063
 8064                        el.bg(status_colors.error_background)
 8065                            .border_color(status_colors.error.opacity(0.6))
 8066                            .child(Icon::new(IconName::Info).color(Color::Error))
 8067                            .cursor_default()
 8068                            .hoverable_tooltip(move |_window, cx| {
 8069                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8070                            })
 8071                    })
 8072                    .children(keybind),
 8073            )
 8074            .into_any();
 8075
 8076        let longest_row =
 8077            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8078        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8079            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8080        } else {
 8081            layout_line(
 8082                longest_row,
 8083                editor_snapshot,
 8084                style,
 8085                editor_width,
 8086                |_| false,
 8087                window,
 8088                cx,
 8089            )
 8090            .width
 8091        };
 8092
 8093        let viewport_bounds =
 8094            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8095                right: -right_margin,
 8096                ..Default::default()
 8097            });
 8098
 8099        let x_after_longest =
 8100            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8101                - scroll_pixel_position.x;
 8102
 8103        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8104
 8105        // Fully visible if it can be displayed within the window (allow overlapping other
 8106        // panes). However, this is only allowed if the popover starts within text_bounds.
 8107        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8108            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8109
 8110        let mut origin = if can_position_to_the_right {
 8111            point(
 8112                x_after_longest,
 8113                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8114                    - scroll_pixel_position.y,
 8115            )
 8116        } else {
 8117            let cursor_row = newest_selection_head.map(|head| head.row());
 8118            let above_edit = edit_start
 8119                .row()
 8120                .0
 8121                .checked_sub(line_count as u32)
 8122                .map(DisplayRow);
 8123            let below_edit = Some(edit_end.row() + 1);
 8124            let above_cursor =
 8125                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8126            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8127
 8128            // Place the edit popover adjacent to the edit if there is a location
 8129            // available that is onscreen and does not obscure the cursor. Otherwise,
 8130            // place it adjacent to the cursor.
 8131            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8132                .into_iter()
 8133                .flatten()
 8134                .find(|&start_row| {
 8135                    let end_row = start_row + line_count as u32;
 8136                    visible_row_range.contains(&start_row)
 8137                        && visible_row_range.contains(&end_row)
 8138                        && cursor_row.map_or(true, |cursor_row| {
 8139                            !((start_row..end_row).contains(&cursor_row))
 8140                        })
 8141                })?;
 8142
 8143            content_origin
 8144                + point(
 8145                    -scroll_pixel_position.x,
 8146                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8147                )
 8148        };
 8149
 8150        origin.x -= BORDER_WIDTH;
 8151
 8152        window.defer_draw(element, origin, 1);
 8153
 8154        // Do not return an element, since it will already be drawn due to defer_draw.
 8155        None
 8156    }
 8157
 8158    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8159        px(30.)
 8160    }
 8161
 8162    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8163        if self.read_only(cx) {
 8164            cx.theme().players().read_only()
 8165        } else {
 8166            self.style.as_ref().unwrap().local_player
 8167        }
 8168    }
 8169
 8170    fn render_edit_prediction_accept_keybind(
 8171        &self,
 8172        window: &mut Window,
 8173        cx: &App,
 8174    ) -> Option<AnyElement> {
 8175        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8176        let accept_keystroke = accept_binding.keystroke()?;
 8177
 8178        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8179
 8180        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8181            Color::Accent
 8182        } else {
 8183            Color::Muted
 8184        };
 8185
 8186        h_flex()
 8187            .px_0p5()
 8188            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8189            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8190            .text_size(TextSize::XSmall.rems(cx))
 8191            .child(h_flex().children(ui::render_modifiers(
 8192                &accept_keystroke.modifiers,
 8193                PlatformStyle::platform(),
 8194                Some(modifiers_color),
 8195                Some(IconSize::XSmall.rems().into()),
 8196                true,
 8197            )))
 8198            .when(is_platform_style_mac, |parent| {
 8199                parent.child(accept_keystroke.key.clone())
 8200            })
 8201            .when(!is_platform_style_mac, |parent| {
 8202                parent.child(
 8203                    Key::new(
 8204                        util::capitalize(&accept_keystroke.key),
 8205                        Some(Color::Default),
 8206                    )
 8207                    .size(Some(IconSize::XSmall.rems().into())),
 8208                )
 8209            })
 8210            .into_any()
 8211            .into()
 8212    }
 8213
 8214    fn render_edit_prediction_line_popover(
 8215        &self,
 8216        label: impl Into<SharedString>,
 8217        icon: Option<IconName>,
 8218        window: &mut Window,
 8219        cx: &App,
 8220    ) -> Option<Stateful<Div>> {
 8221        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8222
 8223        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8224        let has_keybind = keybind.is_some();
 8225
 8226        let result = h_flex()
 8227            .id("ep-line-popover")
 8228            .py_0p5()
 8229            .pl_1()
 8230            .pr(padding_right)
 8231            .gap_1()
 8232            .rounded_md()
 8233            .border_1()
 8234            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8235            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8236            .shadow_sm()
 8237            .when(!has_keybind, |el| {
 8238                let status_colors = cx.theme().status();
 8239
 8240                el.bg(status_colors.error_background)
 8241                    .border_color(status_colors.error.opacity(0.6))
 8242                    .pl_2()
 8243                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8244                    .cursor_default()
 8245                    .hoverable_tooltip(move |_window, cx| {
 8246                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8247                    })
 8248            })
 8249            .children(keybind)
 8250            .child(
 8251                Label::new(label)
 8252                    .size(LabelSize::Small)
 8253                    .when(!has_keybind, |el| {
 8254                        el.color(cx.theme().status().error.into()).strikethrough()
 8255                    }),
 8256            )
 8257            .when(!has_keybind, |el| {
 8258                el.child(
 8259                    h_flex().ml_1().child(
 8260                        Icon::new(IconName::Info)
 8261                            .size(IconSize::Small)
 8262                            .color(cx.theme().status().error.into()),
 8263                    ),
 8264                )
 8265            })
 8266            .when_some(icon, |element, icon| {
 8267                element.child(
 8268                    div()
 8269                        .mt(px(1.5))
 8270                        .child(Icon::new(icon).size(IconSize::Small)),
 8271                )
 8272            });
 8273
 8274        Some(result)
 8275    }
 8276
 8277    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8278        let accent_color = cx.theme().colors().text_accent;
 8279        let editor_bg_color = cx.theme().colors().editor_background;
 8280        editor_bg_color.blend(accent_color.opacity(0.1))
 8281    }
 8282
 8283    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8284        let accent_color = cx.theme().colors().text_accent;
 8285        let editor_bg_color = cx.theme().colors().editor_background;
 8286        editor_bg_color.blend(accent_color.opacity(0.6))
 8287    }
 8288
 8289    fn render_edit_prediction_cursor_popover(
 8290        &self,
 8291        min_width: Pixels,
 8292        max_width: Pixels,
 8293        cursor_point: Point,
 8294        style: &EditorStyle,
 8295        accept_keystroke: Option<&gpui::Keystroke>,
 8296        _window: &Window,
 8297        cx: &mut Context<Editor>,
 8298    ) -> Option<AnyElement> {
 8299        let provider = self.edit_prediction_provider.as_ref()?;
 8300
 8301        if provider.provider.needs_terms_acceptance(cx) {
 8302            return Some(
 8303                h_flex()
 8304                    .min_w(min_width)
 8305                    .flex_1()
 8306                    .px_2()
 8307                    .py_1()
 8308                    .gap_3()
 8309                    .elevation_2(cx)
 8310                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8311                    .id("accept-terms")
 8312                    .cursor_pointer()
 8313                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8314                    .on_click(cx.listener(|this, _event, window, cx| {
 8315                        cx.stop_propagation();
 8316                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8317                        window.dispatch_action(
 8318                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8319                            cx,
 8320                        );
 8321                    }))
 8322                    .child(
 8323                        h_flex()
 8324                            .flex_1()
 8325                            .gap_2()
 8326                            .child(Icon::new(IconName::ZedPredict))
 8327                            .child(Label::new("Accept Terms of Service"))
 8328                            .child(div().w_full())
 8329                            .child(
 8330                                Icon::new(IconName::ArrowUpRight)
 8331                                    .color(Color::Muted)
 8332                                    .size(IconSize::Small),
 8333                            )
 8334                            .into_any_element(),
 8335                    )
 8336                    .into_any(),
 8337            );
 8338        }
 8339
 8340        let is_refreshing = provider.provider.is_refreshing(cx);
 8341
 8342        fn pending_completion_container() -> Div {
 8343            h_flex()
 8344                .h_full()
 8345                .flex_1()
 8346                .gap_2()
 8347                .child(Icon::new(IconName::ZedPredict))
 8348        }
 8349
 8350        let completion = match &self.active_inline_completion {
 8351            Some(prediction) => {
 8352                if !self.has_visible_completions_menu() {
 8353                    const RADIUS: Pixels = px(6.);
 8354                    const BORDER_WIDTH: Pixels = px(1.);
 8355
 8356                    return Some(
 8357                        h_flex()
 8358                            .elevation_2(cx)
 8359                            .border(BORDER_WIDTH)
 8360                            .border_color(cx.theme().colors().border)
 8361                            .when(accept_keystroke.is_none(), |el| {
 8362                                el.border_color(cx.theme().status().error)
 8363                            })
 8364                            .rounded(RADIUS)
 8365                            .rounded_tl(px(0.))
 8366                            .overflow_hidden()
 8367                            .child(div().px_1p5().child(match &prediction.completion {
 8368                                InlineCompletion::Move { target, snapshot } => {
 8369                                    use text::ToPoint as _;
 8370                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8371                                    {
 8372                                        Icon::new(IconName::ZedPredictDown)
 8373                                    } else {
 8374                                        Icon::new(IconName::ZedPredictUp)
 8375                                    }
 8376                                }
 8377                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8378                            }))
 8379                            .child(
 8380                                h_flex()
 8381                                    .gap_1()
 8382                                    .py_1()
 8383                                    .px_2()
 8384                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8385                                    .border_l_1()
 8386                                    .border_color(cx.theme().colors().border)
 8387                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8388                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8389                                        el.child(
 8390                                            Label::new("Hold")
 8391                                                .size(LabelSize::Small)
 8392                                                .when(accept_keystroke.is_none(), |el| {
 8393                                                    el.strikethrough()
 8394                                                })
 8395                                                .line_height_style(LineHeightStyle::UiLabel),
 8396                                        )
 8397                                    })
 8398                                    .id("edit_prediction_cursor_popover_keybind")
 8399                                    .when(accept_keystroke.is_none(), |el| {
 8400                                        let status_colors = cx.theme().status();
 8401
 8402                                        el.bg(status_colors.error_background)
 8403                                            .border_color(status_colors.error.opacity(0.6))
 8404                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8405                                            .cursor_default()
 8406                                            .hoverable_tooltip(move |_window, cx| {
 8407                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8408                                                    .into()
 8409                                            })
 8410                                    })
 8411                                    .when_some(
 8412                                        accept_keystroke.as_ref(),
 8413                                        |el, accept_keystroke| {
 8414                                            el.child(h_flex().children(ui::render_modifiers(
 8415                                                &accept_keystroke.modifiers,
 8416                                                PlatformStyle::platform(),
 8417                                                Some(Color::Default),
 8418                                                Some(IconSize::XSmall.rems().into()),
 8419                                                false,
 8420                                            )))
 8421                                        },
 8422                                    ),
 8423                            )
 8424                            .into_any(),
 8425                    );
 8426                }
 8427
 8428                self.render_edit_prediction_cursor_popover_preview(
 8429                    prediction,
 8430                    cursor_point,
 8431                    style,
 8432                    cx,
 8433                )?
 8434            }
 8435
 8436            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8437                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8438                    stale_completion,
 8439                    cursor_point,
 8440                    style,
 8441                    cx,
 8442                )?,
 8443
 8444                None => {
 8445                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8446                }
 8447            },
 8448
 8449            None => pending_completion_container().child(Label::new("No Prediction")),
 8450        };
 8451
 8452        let completion = if is_refreshing {
 8453            completion
 8454                .with_animation(
 8455                    "loading-completion",
 8456                    Animation::new(Duration::from_secs(2))
 8457                        .repeat()
 8458                        .with_easing(pulsating_between(0.4, 0.8)),
 8459                    |label, delta| label.opacity(delta),
 8460                )
 8461                .into_any_element()
 8462        } else {
 8463            completion.into_any_element()
 8464        };
 8465
 8466        let has_completion = self.active_inline_completion.is_some();
 8467
 8468        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8469        Some(
 8470            h_flex()
 8471                .min_w(min_width)
 8472                .max_w(max_width)
 8473                .flex_1()
 8474                .elevation_2(cx)
 8475                .border_color(cx.theme().colors().border)
 8476                .child(
 8477                    div()
 8478                        .flex_1()
 8479                        .py_1()
 8480                        .px_2()
 8481                        .overflow_hidden()
 8482                        .child(completion),
 8483                )
 8484                .when_some(accept_keystroke, |el, accept_keystroke| {
 8485                    if !accept_keystroke.modifiers.modified() {
 8486                        return el;
 8487                    }
 8488
 8489                    el.child(
 8490                        h_flex()
 8491                            .h_full()
 8492                            .border_l_1()
 8493                            .rounded_r_lg()
 8494                            .border_color(cx.theme().colors().border)
 8495                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8496                            .gap_1()
 8497                            .py_1()
 8498                            .px_2()
 8499                            .child(
 8500                                h_flex()
 8501                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8502                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8503                                    .child(h_flex().children(ui::render_modifiers(
 8504                                        &accept_keystroke.modifiers,
 8505                                        PlatformStyle::platform(),
 8506                                        Some(if !has_completion {
 8507                                            Color::Muted
 8508                                        } else {
 8509                                            Color::Default
 8510                                        }),
 8511                                        None,
 8512                                        false,
 8513                                    ))),
 8514                            )
 8515                            .child(Label::new("Preview").into_any_element())
 8516                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8517                    )
 8518                })
 8519                .into_any(),
 8520        )
 8521    }
 8522
 8523    fn render_edit_prediction_cursor_popover_preview(
 8524        &self,
 8525        completion: &InlineCompletionState,
 8526        cursor_point: Point,
 8527        style: &EditorStyle,
 8528        cx: &mut Context<Editor>,
 8529    ) -> Option<Div> {
 8530        use text::ToPoint as _;
 8531
 8532        fn render_relative_row_jump(
 8533            prefix: impl Into<String>,
 8534            current_row: u32,
 8535            target_row: u32,
 8536        ) -> Div {
 8537            let (row_diff, arrow) = if target_row < current_row {
 8538                (current_row - target_row, IconName::ArrowUp)
 8539            } else {
 8540                (target_row - current_row, IconName::ArrowDown)
 8541            };
 8542
 8543            h_flex()
 8544                .child(
 8545                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8546                        .color(Color::Muted)
 8547                        .size(LabelSize::Small),
 8548                )
 8549                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8550        }
 8551
 8552        match &completion.completion {
 8553            InlineCompletion::Move {
 8554                target, snapshot, ..
 8555            } => Some(
 8556                h_flex()
 8557                    .px_2()
 8558                    .gap_2()
 8559                    .flex_1()
 8560                    .child(
 8561                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8562                            Icon::new(IconName::ZedPredictDown)
 8563                        } else {
 8564                            Icon::new(IconName::ZedPredictUp)
 8565                        },
 8566                    )
 8567                    .child(Label::new("Jump to Edit")),
 8568            ),
 8569
 8570            InlineCompletion::Edit {
 8571                edits,
 8572                edit_preview,
 8573                snapshot,
 8574                display_mode: _,
 8575            } => {
 8576                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8577
 8578                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8579                    &snapshot,
 8580                    &edits,
 8581                    edit_preview.as_ref()?,
 8582                    true,
 8583                    cx,
 8584                )
 8585                .first_line_preview();
 8586
 8587                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8588                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8589
 8590                let preview = h_flex()
 8591                    .gap_1()
 8592                    .min_w_16()
 8593                    .child(styled_text)
 8594                    .when(has_more_lines, |parent| parent.child(""));
 8595
 8596                let left = if first_edit_row != cursor_point.row {
 8597                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8598                        .into_any_element()
 8599                } else {
 8600                    Icon::new(IconName::ZedPredict).into_any_element()
 8601                };
 8602
 8603                Some(
 8604                    h_flex()
 8605                        .h_full()
 8606                        .flex_1()
 8607                        .gap_2()
 8608                        .pr_1()
 8609                        .overflow_x_hidden()
 8610                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8611                        .child(left)
 8612                        .child(preview),
 8613                )
 8614            }
 8615        }
 8616    }
 8617
 8618    pub fn render_context_menu(
 8619        &self,
 8620        style: &EditorStyle,
 8621        max_height_in_lines: u32,
 8622        window: &mut Window,
 8623        cx: &mut Context<Editor>,
 8624    ) -> Option<AnyElement> {
 8625        let menu = self.context_menu.borrow();
 8626        let menu = menu.as_ref()?;
 8627        if !menu.visible() {
 8628            return None;
 8629        };
 8630        Some(menu.render(style, max_height_in_lines, window, cx))
 8631    }
 8632
 8633    fn render_context_menu_aside(
 8634        &mut self,
 8635        max_size: Size<Pixels>,
 8636        window: &mut Window,
 8637        cx: &mut Context<Editor>,
 8638    ) -> Option<AnyElement> {
 8639        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8640            if menu.visible() {
 8641                menu.render_aside(self, max_size, window, cx)
 8642            } else {
 8643                None
 8644            }
 8645        })
 8646    }
 8647
 8648    fn hide_context_menu(
 8649        &mut self,
 8650        window: &mut Window,
 8651        cx: &mut Context<Self>,
 8652    ) -> Option<CodeContextMenu> {
 8653        cx.notify();
 8654        self.completion_tasks.clear();
 8655        let context_menu = self.context_menu.borrow_mut().take();
 8656        self.stale_inline_completion_in_menu.take();
 8657        self.update_visible_inline_completion(window, cx);
 8658        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8659            if let Some(completion_provider) = &self.completion_provider {
 8660                completion_provider.selection_changed(None, window, cx);
 8661            }
 8662        }
 8663        context_menu
 8664    }
 8665
 8666    fn show_snippet_choices(
 8667        &mut self,
 8668        choices: &Vec<String>,
 8669        selection: Range<Anchor>,
 8670        cx: &mut Context<Self>,
 8671    ) {
 8672        if selection.start.buffer_id.is_none() {
 8673            return;
 8674        }
 8675        let buffer_id = selection.start.buffer_id.unwrap();
 8676        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8677        let id = post_inc(&mut self.next_completion_id);
 8678        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8679
 8680        if let Some(buffer) = buffer {
 8681            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8682                CompletionsMenu::new_snippet_choices(
 8683                    id,
 8684                    true,
 8685                    choices,
 8686                    selection,
 8687                    buffer,
 8688                    snippet_sort_order,
 8689                ),
 8690            ));
 8691        }
 8692    }
 8693
 8694    pub fn insert_snippet(
 8695        &mut self,
 8696        insertion_ranges: &[Range<usize>],
 8697        snippet: Snippet,
 8698        window: &mut Window,
 8699        cx: &mut Context<Self>,
 8700    ) -> Result<()> {
 8701        struct Tabstop<T> {
 8702            is_end_tabstop: bool,
 8703            ranges: Vec<Range<T>>,
 8704            choices: Option<Vec<String>>,
 8705        }
 8706
 8707        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8708            let snippet_text: Arc<str> = snippet.text.clone().into();
 8709            let edits = insertion_ranges
 8710                .iter()
 8711                .cloned()
 8712                .map(|range| (range, snippet_text.clone()));
 8713            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8714
 8715            let snapshot = &*buffer.read(cx);
 8716            let snippet = &snippet;
 8717            snippet
 8718                .tabstops
 8719                .iter()
 8720                .map(|tabstop| {
 8721                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8722                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8723                    });
 8724                    let mut tabstop_ranges = tabstop
 8725                        .ranges
 8726                        .iter()
 8727                        .flat_map(|tabstop_range| {
 8728                            let mut delta = 0_isize;
 8729                            insertion_ranges.iter().map(move |insertion_range| {
 8730                                let insertion_start = insertion_range.start as isize + delta;
 8731                                delta +=
 8732                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8733
 8734                                let start = ((insertion_start + tabstop_range.start) as usize)
 8735                                    .min(snapshot.len());
 8736                                let end = ((insertion_start + tabstop_range.end) as usize)
 8737                                    .min(snapshot.len());
 8738                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8739                            })
 8740                        })
 8741                        .collect::<Vec<_>>();
 8742                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8743
 8744                    Tabstop {
 8745                        is_end_tabstop,
 8746                        ranges: tabstop_ranges,
 8747                        choices: tabstop.choices.clone(),
 8748                    }
 8749                })
 8750                .collect::<Vec<_>>()
 8751        });
 8752        if let Some(tabstop) = tabstops.first() {
 8753            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8754                s.select_ranges(tabstop.ranges.iter().cloned());
 8755            });
 8756
 8757            if let Some(choices) = &tabstop.choices {
 8758                if let Some(selection) = tabstop.ranges.first() {
 8759                    self.show_snippet_choices(choices, selection.clone(), cx)
 8760                }
 8761            }
 8762
 8763            // If we're already at the last tabstop and it's at the end of the snippet,
 8764            // we're done, we don't need to keep the state around.
 8765            if !tabstop.is_end_tabstop {
 8766                let choices = tabstops
 8767                    .iter()
 8768                    .map(|tabstop| tabstop.choices.clone())
 8769                    .collect();
 8770
 8771                let ranges = tabstops
 8772                    .into_iter()
 8773                    .map(|tabstop| tabstop.ranges)
 8774                    .collect::<Vec<_>>();
 8775
 8776                self.snippet_stack.push(SnippetState {
 8777                    active_index: 0,
 8778                    ranges,
 8779                    choices,
 8780                });
 8781            }
 8782
 8783            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8784            if self.autoclose_regions.is_empty() {
 8785                let snapshot = self.buffer.read(cx).snapshot(cx);
 8786                for selection in &mut self.selections.all::<Point>(cx) {
 8787                    let selection_head = selection.head();
 8788                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8789                        continue;
 8790                    };
 8791
 8792                    let mut bracket_pair = None;
 8793                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8794                    let prev_chars = snapshot
 8795                        .reversed_chars_at(selection_head)
 8796                        .collect::<String>();
 8797                    for (pair, enabled) in scope.brackets() {
 8798                        if enabled
 8799                            && pair.close
 8800                            && prev_chars.starts_with(pair.start.as_str())
 8801                            && next_chars.starts_with(pair.end.as_str())
 8802                        {
 8803                            bracket_pair = Some(pair.clone());
 8804                            break;
 8805                        }
 8806                    }
 8807                    if let Some(pair) = bracket_pair {
 8808                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8809                        let autoclose_enabled =
 8810                            self.use_autoclose && snapshot_settings.use_autoclose;
 8811                        if autoclose_enabled {
 8812                            let start = snapshot.anchor_after(selection_head);
 8813                            let end = snapshot.anchor_after(selection_head);
 8814                            self.autoclose_regions.push(AutocloseRegion {
 8815                                selection_id: selection.id,
 8816                                range: start..end,
 8817                                pair,
 8818                            });
 8819                        }
 8820                    }
 8821                }
 8822            }
 8823        }
 8824        Ok(())
 8825    }
 8826
 8827    pub fn move_to_next_snippet_tabstop(
 8828        &mut self,
 8829        window: &mut Window,
 8830        cx: &mut Context<Self>,
 8831    ) -> bool {
 8832        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8833    }
 8834
 8835    pub fn move_to_prev_snippet_tabstop(
 8836        &mut self,
 8837        window: &mut Window,
 8838        cx: &mut Context<Self>,
 8839    ) -> bool {
 8840        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8841    }
 8842
 8843    pub fn move_to_snippet_tabstop(
 8844        &mut self,
 8845        bias: Bias,
 8846        window: &mut Window,
 8847        cx: &mut Context<Self>,
 8848    ) -> bool {
 8849        if let Some(mut snippet) = self.snippet_stack.pop() {
 8850            match bias {
 8851                Bias::Left => {
 8852                    if snippet.active_index > 0 {
 8853                        snippet.active_index -= 1;
 8854                    } else {
 8855                        self.snippet_stack.push(snippet);
 8856                        return false;
 8857                    }
 8858                }
 8859                Bias::Right => {
 8860                    if snippet.active_index + 1 < snippet.ranges.len() {
 8861                        snippet.active_index += 1;
 8862                    } else {
 8863                        self.snippet_stack.push(snippet);
 8864                        return false;
 8865                    }
 8866                }
 8867            }
 8868            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8869                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8870                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8871                });
 8872
 8873                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8874                    if let Some(selection) = current_ranges.first() {
 8875                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8876                    }
 8877                }
 8878
 8879                // If snippet state is not at the last tabstop, push it back on the stack
 8880                if snippet.active_index + 1 < snippet.ranges.len() {
 8881                    self.snippet_stack.push(snippet);
 8882                }
 8883                return true;
 8884            }
 8885        }
 8886
 8887        false
 8888    }
 8889
 8890    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8891        self.transact(window, cx, |this, window, cx| {
 8892            this.select_all(&SelectAll, window, cx);
 8893            this.insert("", window, cx);
 8894        });
 8895    }
 8896
 8897    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8898        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8899        self.transact(window, cx, |this, window, cx| {
 8900            this.select_autoclose_pair(window, cx);
 8901            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8902            if !this.linked_edit_ranges.is_empty() {
 8903                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8904                let snapshot = this.buffer.read(cx).snapshot(cx);
 8905
 8906                for selection in selections.iter() {
 8907                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8908                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8909                    if selection_start.buffer_id != selection_end.buffer_id {
 8910                        continue;
 8911                    }
 8912                    if let Some(ranges) =
 8913                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8914                    {
 8915                        for (buffer, entries) in ranges {
 8916                            linked_ranges.entry(buffer).or_default().extend(entries);
 8917                        }
 8918                    }
 8919                }
 8920            }
 8921
 8922            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8923            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8924            for selection in &mut selections {
 8925                if selection.is_empty() {
 8926                    let old_head = selection.head();
 8927                    let mut new_head =
 8928                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8929                            .to_point(&display_map);
 8930                    if let Some((buffer, line_buffer_range)) = display_map
 8931                        .buffer_snapshot
 8932                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8933                    {
 8934                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8935                        let indent_len = match indent_size.kind {
 8936                            IndentKind::Space => {
 8937                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8938                            }
 8939                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8940                        };
 8941                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8942                            let indent_len = indent_len.get();
 8943                            new_head = cmp::min(
 8944                                new_head,
 8945                                MultiBufferPoint::new(
 8946                                    old_head.row,
 8947                                    ((old_head.column - 1) / indent_len) * indent_len,
 8948                                ),
 8949                            );
 8950                        }
 8951                    }
 8952
 8953                    selection.set_head(new_head, SelectionGoal::None);
 8954                }
 8955            }
 8956
 8957            this.signature_help_state.set_backspace_pressed(true);
 8958            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8959                s.select(selections)
 8960            });
 8961            this.insert("", window, cx);
 8962            let empty_str: Arc<str> = Arc::from("");
 8963            for (buffer, edits) in linked_ranges {
 8964                let snapshot = buffer.read(cx).snapshot();
 8965                use text::ToPoint as TP;
 8966
 8967                let edits = edits
 8968                    .into_iter()
 8969                    .map(|range| {
 8970                        let end_point = TP::to_point(&range.end, &snapshot);
 8971                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8972
 8973                        if end_point == start_point {
 8974                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8975                                .saturating_sub(1);
 8976                            start_point =
 8977                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8978                        };
 8979
 8980                        (start_point..end_point, empty_str.clone())
 8981                    })
 8982                    .sorted_by_key(|(range, _)| range.start)
 8983                    .collect::<Vec<_>>();
 8984                buffer.update(cx, |this, cx| {
 8985                    this.edit(edits, None, cx);
 8986                })
 8987            }
 8988            this.refresh_inline_completion(true, false, window, cx);
 8989            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8990        });
 8991    }
 8992
 8993    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8994        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8995        self.transact(window, cx, |this, window, cx| {
 8996            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8997                s.move_with(|map, selection| {
 8998                    if selection.is_empty() {
 8999                        let cursor = movement::right(map, selection.head());
 9000                        selection.end = cursor;
 9001                        selection.reversed = true;
 9002                        selection.goal = SelectionGoal::None;
 9003                    }
 9004                })
 9005            });
 9006            this.insert("", window, cx);
 9007            this.refresh_inline_completion(true, false, window, cx);
 9008        });
 9009    }
 9010
 9011    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9012        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9013        if self.move_to_prev_snippet_tabstop(window, cx) {
 9014            return;
 9015        }
 9016        self.outdent(&Outdent, window, cx);
 9017    }
 9018
 9019    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9020        if self.move_to_next_snippet_tabstop(window, cx) {
 9021            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9022            return;
 9023        }
 9024        if self.read_only(cx) {
 9025            return;
 9026        }
 9027        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9028        let mut selections = self.selections.all_adjusted(cx);
 9029        let buffer = self.buffer.read(cx);
 9030        let snapshot = buffer.snapshot(cx);
 9031        let rows_iter = selections.iter().map(|s| s.head().row);
 9032        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9033
 9034        let has_some_cursor_in_whitespace = selections
 9035            .iter()
 9036            .filter(|selection| selection.is_empty())
 9037            .any(|selection| {
 9038                let cursor = selection.head();
 9039                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9040                cursor.column < current_indent.len
 9041            });
 9042
 9043        let mut edits = Vec::new();
 9044        let mut prev_edited_row = 0;
 9045        let mut row_delta = 0;
 9046        for selection in &mut selections {
 9047            if selection.start.row != prev_edited_row {
 9048                row_delta = 0;
 9049            }
 9050            prev_edited_row = selection.end.row;
 9051
 9052            // If the selection is non-empty, then increase the indentation of the selected lines.
 9053            if !selection.is_empty() {
 9054                row_delta =
 9055                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9056                continue;
 9057            }
 9058
 9059            let cursor = selection.head();
 9060            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9061            if let Some(suggested_indent) =
 9062                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9063            {
 9064                // Don't do anything if already at suggested indent
 9065                // and there is any other cursor which is not
 9066                if has_some_cursor_in_whitespace
 9067                    && cursor.column == current_indent.len
 9068                    && current_indent.len == suggested_indent.len
 9069                {
 9070                    continue;
 9071                }
 9072
 9073                // Adjust line and move cursor to suggested indent
 9074                // if cursor is not at suggested indent
 9075                if cursor.column < suggested_indent.len
 9076                    && cursor.column <= current_indent.len
 9077                    && current_indent.len <= suggested_indent.len
 9078                {
 9079                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9080                    selection.end = selection.start;
 9081                    if row_delta == 0 {
 9082                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9083                            cursor.row,
 9084                            current_indent,
 9085                            suggested_indent,
 9086                        ));
 9087                        row_delta = suggested_indent.len - current_indent.len;
 9088                    }
 9089                    continue;
 9090                }
 9091
 9092                // If current indent is more than suggested indent
 9093                // only move cursor to current indent and skip indent
 9094                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9095                    selection.start = Point::new(cursor.row, current_indent.len);
 9096                    selection.end = selection.start;
 9097                    continue;
 9098                }
 9099            }
 9100
 9101            // Otherwise, insert a hard or soft tab.
 9102            let settings = buffer.language_settings_at(cursor, cx);
 9103            let tab_size = if settings.hard_tabs {
 9104                IndentSize::tab()
 9105            } else {
 9106                let tab_size = settings.tab_size.get();
 9107                let indent_remainder = snapshot
 9108                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9109                    .flat_map(str::chars)
 9110                    .fold(row_delta % tab_size, |counter: u32, c| {
 9111                        if c == '\t' {
 9112                            0
 9113                        } else {
 9114                            (counter + 1) % tab_size
 9115                        }
 9116                    });
 9117
 9118                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9119                IndentSize::spaces(chars_to_next_tab_stop)
 9120            };
 9121            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9122            selection.end = selection.start;
 9123            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9124            row_delta += tab_size.len;
 9125        }
 9126
 9127        self.transact(window, cx, |this, window, cx| {
 9128            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9129            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9130                s.select(selections)
 9131            });
 9132            this.refresh_inline_completion(true, false, window, cx);
 9133        });
 9134    }
 9135
 9136    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9137        if self.read_only(cx) {
 9138            return;
 9139        }
 9140        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9141        let mut selections = self.selections.all::<Point>(cx);
 9142        let mut prev_edited_row = 0;
 9143        let mut row_delta = 0;
 9144        let mut edits = Vec::new();
 9145        let buffer = self.buffer.read(cx);
 9146        let snapshot = buffer.snapshot(cx);
 9147        for selection in &mut selections {
 9148            if selection.start.row != prev_edited_row {
 9149                row_delta = 0;
 9150            }
 9151            prev_edited_row = selection.end.row;
 9152
 9153            row_delta =
 9154                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9155        }
 9156
 9157        self.transact(window, cx, |this, window, cx| {
 9158            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9159            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9160                s.select(selections)
 9161            });
 9162        });
 9163    }
 9164
 9165    fn indent_selection(
 9166        buffer: &MultiBuffer,
 9167        snapshot: &MultiBufferSnapshot,
 9168        selection: &mut Selection<Point>,
 9169        edits: &mut Vec<(Range<Point>, String)>,
 9170        delta_for_start_row: u32,
 9171        cx: &App,
 9172    ) -> u32 {
 9173        let settings = buffer.language_settings_at(selection.start, cx);
 9174        let tab_size = settings.tab_size.get();
 9175        let indent_kind = if settings.hard_tabs {
 9176            IndentKind::Tab
 9177        } else {
 9178            IndentKind::Space
 9179        };
 9180        let mut start_row = selection.start.row;
 9181        let mut end_row = selection.end.row + 1;
 9182
 9183        // If a selection ends at the beginning of a line, don't indent
 9184        // that last line.
 9185        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9186            end_row -= 1;
 9187        }
 9188
 9189        // Avoid re-indenting a row that has already been indented by a
 9190        // previous selection, but still update this selection's column
 9191        // to reflect that indentation.
 9192        if delta_for_start_row > 0 {
 9193            start_row += 1;
 9194            selection.start.column += delta_for_start_row;
 9195            if selection.end.row == selection.start.row {
 9196                selection.end.column += delta_for_start_row;
 9197            }
 9198        }
 9199
 9200        let mut delta_for_end_row = 0;
 9201        let has_multiple_rows = start_row + 1 != end_row;
 9202        for row in start_row..end_row {
 9203            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9204            let indent_delta = match (current_indent.kind, indent_kind) {
 9205                (IndentKind::Space, IndentKind::Space) => {
 9206                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9207                    IndentSize::spaces(columns_to_next_tab_stop)
 9208                }
 9209                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9210                (_, IndentKind::Tab) => IndentSize::tab(),
 9211            };
 9212
 9213            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9214                0
 9215            } else {
 9216                selection.start.column
 9217            };
 9218            let row_start = Point::new(row, start);
 9219            edits.push((
 9220                row_start..row_start,
 9221                indent_delta.chars().collect::<String>(),
 9222            ));
 9223
 9224            // Update this selection's endpoints to reflect the indentation.
 9225            if row == selection.start.row {
 9226                selection.start.column += indent_delta.len;
 9227            }
 9228            if row == selection.end.row {
 9229                selection.end.column += indent_delta.len;
 9230                delta_for_end_row = indent_delta.len;
 9231            }
 9232        }
 9233
 9234        if selection.start.row == selection.end.row {
 9235            delta_for_start_row + delta_for_end_row
 9236        } else {
 9237            delta_for_end_row
 9238        }
 9239    }
 9240
 9241    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9242        if self.read_only(cx) {
 9243            return;
 9244        }
 9245        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9247        let selections = self.selections.all::<Point>(cx);
 9248        let mut deletion_ranges = Vec::new();
 9249        let mut last_outdent = None;
 9250        {
 9251            let buffer = self.buffer.read(cx);
 9252            let snapshot = buffer.snapshot(cx);
 9253            for selection in &selections {
 9254                let settings = buffer.language_settings_at(selection.start, cx);
 9255                let tab_size = settings.tab_size.get();
 9256                let mut rows = selection.spanned_rows(false, &display_map);
 9257
 9258                // Avoid re-outdenting a row that has already been outdented by a
 9259                // previous selection.
 9260                if let Some(last_row) = last_outdent {
 9261                    if last_row == rows.start {
 9262                        rows.start = rows.start.next_row();
 9263                    }
 9264                }
 9265                let has_multiple_rows = rows.len() > 1;
 9266                for row in rows.iter_rows() {
 9267                    let indent_size = snapshot.indent_size_for_line(row);
 9268                    if indent_size.len > 0 {
 9269                        let deletion_len = match indent_size.kind {
 9270                            IndentKind::Space => {
 9271                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9272                                if columns_to_prev_tab_stop == 0 {
 9273                                    tab_size
 9274                                } else {
 9275                                    columns_to_prev_tab_stop
 9276                                }
 9277                            }
 9278                            IndentKind::Tab => 1,
 9279                        };
 9280                        let start = if has_multiple_rows
 9281                            || deletion_len > selection.start.column
 9282                            || indent_size.len < selection.start.column
 9283                        {
 9284                            0
 9285                        } else {
 9286                            selection.start.column - deletion_len
 9287                        };
 9288                        deletion_ranges.push(
 9289                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9290                        );
 9291                        last_outdent = Some(row);
 9292                    }
 9293                }
 9294            }
 9295        }
 9296
 9297        self.transact(window, cx, |this, window, cx| {
 9298            this.buffer.update(cx, |buffer, cx| {
 9299                let empty_str: Arc<str> = Arc::default();
 9300                buffer.edit(
 9301                    deletion_ranges
 9302                        .into_iter()
 9303                        .map(|range| (range, empty_str.clone())),
 9304                    None,
 9305                    cx,
 9306                );
 9307            });
 9308            let selections = this.selections.all::<usize>(cx);
 9309            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9310                s.select(selections)
 9311            });
 9312        });
 9313    }
 9314
 9315    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9316        if self.read_only(cx) {
 9317            return;
 9318        }
 9319        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9320        let selections = self
 9321            .selections
 9322            .all::<usize>(cx)
 9323            .into_iter()
 9324            .map(|s| s.range());
 9325
 9326        self.transact(window, cx, |this, window, cx| {
 9327            this.buffer.update(cx, |buffer, cx| {
 9328                buffer.autoindent_ranges(selections, cx);
 9329            });
 9330            let selections = this.selections.all::<usize>(cx);
 9331            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9332                s.select(selections)
 9333            });
 9334        });
 9335    }
 9336
 9337    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9338        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9339        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9340        let selections = self.selections.all::<Point>(cx);
 9341
 9342        let mut new_cursors = Vec::new();
 9343        let mut edit_ranges = Vec::new();
 9344        let mut selections = selections.iter().peekable();
 9345        while let Some(selection) = selections.next() {
 9346            let mut rows = selection.spanned_rows(false, &display_map);
 9347            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9348
 9349            // Accumulate contiguous regions of rows that we want to delete.
 9350            while let Some(next_selection) = selections.peek() {
 9351                let next_rows = next_selection.spanned_rows(false, &display_map);
 9352                if next_rows.start <= rows.end {
 9353                    rows.end = next_rows.end;
 9354                    selections.next().unwrap();
 9355                } else {
 9356                    break;
 9357                }
 9358            }
 9359
 9360            let buffer = &display_map.buffer_snapshot;
 9361            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9362            let edit_end;
 9363            let cursor_buffer_row;
 9364            if buffer.max_point().row >= rows.end.0 {
 9365                // If there's a line after the range, delete the \n from the end of the row range
 9366                // and position the cursor on the next line.
 9367                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9368                cursor_buffer_row = rows.end;
 9369            } else {
 9370                // If there isn't a line after the range, delete the \n from the line before the
 9371                // start of the row range and position the cursor there.
 9372                edit_start = edit_start.saturating_sub(1);
 9373                edit_end = buffer.len();
 9374                cursor_buffer_row = rows.start.previous_row();
 9375            }
 9376
 9377            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9378            *cursor.column_mut() =
 9379                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9380
 9381            new_cursors.push((
 9382                selection.id,
 9383                buffer.anchor_after(cursor.to_point(&display_map)),
 9384            ));
 9385            edit_ranges.push(edit_start..edit_end);
 9386        }
 9387
 9388        self.transact(window, cx, |this, window, cx| {
 9389            let buffer = this.buffer.update(cx, |buffer, cx| {
 9390                let empty_str: Arc<str> = Arc::default();
 9391                buffer.edit(
 9392                    edit_ranges
 9393                        .into_iter()
 9394                        .map(|range| (range, empty_str.clone())),
 9395                    None,
 9396                    cx,
 9397                );
 9398                buffer.snapshot(cx)
 9399            });
 9400            let new_selections = new_cursors
 9401                .into_iter()
 9402                .map(|(id, cursor)| {
 9403                    let cursor = cursor.to_point(&buffer);
 9404                    Selection {
 9405                        id,
 9406                        start: cursor,
 9407                        end: cursor,
 9408                        reversed: false,
 9409                        goal: SelectionGoal::None,
 9410                    }
 9411                })
 9412                .collect();
 9413
 9414            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9415                s.select(new_selections);
 9416            });
 9417        });
 9418    }
 9419
 9420    pub fn join_lines_impl(
 9421        &mut self,
 9422        insert_whitespace: bool,
 9423        window: &mut Window,
 9424        cx: &mut Context<Self>,
 9425    ) {
 9426        if self.read_only(cx) {
 9427            return;
 9428        }
 9429        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9430        for selection in self.selections.all::<Point>(cx) {
 9431            let start = MultiBufferRow(selection.start.row);
 9432            // Treat single line selections as if they include the next line. Otherwise this action
 9433            // would do nothing for single line selections individual cursors.
 9434            let end = if selection.start.row == selection.end.row {
 9435                MultiBufferRow(selection.start.row + 1)
 9436            } else {
 9437                MultiBufferRow(selection.end.row)
 9438            };
 9439
 9440            if let Some(last_row_range) = row_ranges.last_mut() {
 9441                if start <= last_row_range.end {
 9442                    last_row_range.end = end;
 9443                    continue;
 9444                }
 9445            }
 9446            row_ranges.push(start..end);
 9447        }
 9448
 9449        let snapshot = self.buffer.read(cx).snapshot(cx);
 9450        let mut cursor_positions = Vec::new();
 9451        for row_range in &row_ranges {
 9452            let anchor = snapshot.anchor_before(Point::new(
 9453                row_range.end.previous_row().0,
 9454                snapshot.line_len(row_range.end.previous_row()),
 9455            ));
 9456            cursor_positions.push(anchor..anchor);
 9457        }
 9458
 9459        self.transact(window, cx, |this, window, cx| {
 9460            for row_range in row_ranges.into_iter().rev() {
 9461                for row in row_range.iter_rows().rev() {
 9462                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9463                    let next_line_row = row.next_row();
 9464                    let indent = snapshot.indent_size_for_line(next_line_row);
 9465                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9466
 9467                    let replace =
 9468                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9469                            " "
 9470                        } else {
 9471                            ""
 9472                        };
 9473
 9474                    this.buffer.update(cx, |buffer, cx| {
 9475                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9476                    });
 9477                }
 9478            }
 9479
 9480            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9481                s.select_anchor_ranges(cursor_positions)
 9482            });
 9483        });
 9484    }
 9485
 9486    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9487        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9488        self.join_lines_impl(true, window, cx);
 9489    }
 9490
 9491    pub fn sort_lines_case_sensitive(
 9492        &mut self,
 9493        _: &SortLinesCaseSensitive,
 9494        window: &mut Window,
 9495        cx: &mut Context<Self>,
 9496    ) {
 9497        self.manipulate_lines(window, cx, |lines| lines.sort())
 9498    }
 9499
 9500    pub fn sort_lines_case_insensitive(
 9501        &mut self,
 9502        _: &SortLinesCaseInsensitive,
 9503        window: &mut Window,
 9504        cx: &mut Context<Self>,
 9505    ) {
 9506        self.manipulate_lines(window, cx, |lines| {
 9507            lines.sort_by_key(|line| line.to_lowercase())
 9508        })
 9509    }
 9510
 9511    pub fn unique_lines_case_insensitive(
 9512        &mut self,
 9513        _: &UniqueLinesCaseInsensitive,
 9514        window: &mut Window,
 9515        cx: &mut Context<Self>,
 9516    ) {
 9517        self.manipulate_lines(window, cx, |lines| {
 9518            let mut seen = HashSet::default();
 9519            lines.retain(|line| seen.insert(line.to_lowercase()));
 9520        })
 9521    }
 9522
 9523    pub fn unique_lines_case_sensitive(
 9524        &mut self,
 9525        _: &UniqueLinesCaseSensitive,
 9526        window: &mut Window,
 9527        cx: &mut Context<Self>,
 9528    ) {
 9529        self.manipulate_lines(window, cx, |lines| {
 9530            let mut seen = HashSet::default();
 9531            lines.retain(|line| seen.insert(*line));
 9532        })
 9533    }
 9534
 9535    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9536        let Some(project) = self.project.clone() else {
 9537            return;
 9538        };
 9539        self.reload(project, window, cx)
 9540            .detach_and_notify_err(window, cx);
 9541    }
 9542
 9543    pub fn restore_file(
 9544        &mut self,
 9545        _: &::git::RestoreFile,
 9546        window: &mut Window,
 9547        cx: &mut Context<Self>,
 9548    ) {
 9549        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9550        let mut buffer_ids = HashSet::default();
 9551        let snapshot = self.buffer().read(cx).snapshot(cx);
 9552        for selection in self.selections.all::<usize>(cx) {
 9553            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9554        }
 9555
 9556        let buffer = self.buffer().read(cx);
 9557        let ranges = buffer_ids
 9558            .into_iter()
 9559            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9560            .collect::<Vec<_>>();
 9561
 9562        self.restore_hunks_in_ranges(ranges, window, cx);
 9563    }
 9564
 9565    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9567        let selections = self
 9568            .selections
 9569            .all(cx)
 9570            .into_iter()
 9571            .map(|s| s.range())
 9572            .collect();
 9573        self.restore_hunks_in_ranges(selections, window, cx);
 9574    }
 9575
 9576    pub fn restore_hunks_in_ranges(
 9577        &mut self,
 9578        ranges: Vec<Range<Point>>,
 9579        window: &mut Window,
 9580        cx: &mut Context<Editor>,
 9581    ) {
 9582        let mut revert_changes = HashMap::default();
 9583        let chunk_by = self
 9584            .snapshot(window, cx)
 9585            .hunks_for_ranges(ranges)
 9586            .into_iter()
 9587            .chunk_by(|hunk| hunk.buffer_id);
 9588        for (buffer_id, hunks) in &chunk_by {
 9589            let hunks = hunks.collect::<Vec<_>>();
 9590            for hunk in &hunks {
 9591                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9592            }
 9593            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9594        }
 9595        drop(chunk_by);
 9596        if !revert_changes.is_empty() {
 9597            self.transact(window, cx, |editor, window, cx| {
 9598                editor.restore(revert_changes, window, cx);
 9599            });
 9600        }
 9601    }
 9602
 9603    pub fn open_active_item_in_terminal(
 9604        &mut self,
 9605        _: &OpenInTerminal,
 9606        window: &mut Window,
 9607        cx: &mut Context<Self>,
 9608    ) {
 9609        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9610            let project_path = buffer.read(cx).project_path(cx)?;
 9611            let project = self.project.as_ref()?.read(cx);
 9612            let entry = project.entry_for_path(&project_path, cx)?;
 9613            let parent = match &entry.canonical_path {
 9614                Some(canonical_path) => canonical_path.to_path_buf(),
 9615                None => project.absolute_path(&project_path, cx)?,
 9616            }
 9617            .parent()?
 9618            .to_path_buf();
 9619            Some(parent)
 9620        }) {
 9621            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9622        }
 9623    }
 9624
 9625    fn set_breakpoint_context_menu(
 9626        &mut self,
 9627        display_row: DisplayRow,
 9628        position: Option<Anchor>,
 9629        clicked_point: gpui::Point<Pixels>,
 9630        window: &mut Window,
 9631        cx: &mut Context<Self>,
 9632    ) {
 9633        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9634            return;
 9635        }
 9636        let source = self
 9637            .buffer
 9638            .read(cx)
 9639            .snapshot(cx)
 9640            .anchor_before(Point::new(display_row.0, 0u32));
 9641
 9642        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9643
 9644        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9645            self,
 9646            source,
 9647            clicked_point,
 9648            context_menu,
 9649            window,
 9650            cx,
 9651        );
 9652    }
 9653
 9654    fn add_edit_breakpoint_block(
 9655        &mut self,
 9656        anchor: Anchor,
 9657        breakpoint: &Breakpoint,
 9658        edit_action: BreakpointPromptEditAction,
 9659        window: &mut Window,
 9660        cx: &mut Context<Self>,
 9661    ) {
 9662        let weak_editor = cx.weak_entity();
 9663        let bp_prompt = cx.new(|cx| {
 9664            BreakpointPromptEditor::new(
 9665                weak_editor,
 9666                anchor,
 9667                breakpoint.clone(),
 9668                edit_action,
 9669                window,
 9670                cx,
 9671            )
 9672        });
 9673
 9674        let height = bp_prompt.update(cx, |this, cx| {
 9675            this.prompt
 9676                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9677        });
 9678        let cloned_prompt = bp_prompt.clone();
 9679        let blocks = vec![BlockProperties {
 9680            style: BlockStyle::Sticky,
 9681            placement: BlockPlacement::Above(anchor),
 9682            height: Some(height),
 9683            render: Arc::new(move |cx| {
 9684                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9685                cloned_prompt.clone().into_any_element()
 9686            }),
 9687            priority: 0,
 9688            render_in_minimap: true,
 9689        }];
 9690
 9691        let focus_handle = bp_prompt.focus_handle(cx);
 9692        window.focus(&focus_handle);
 9693
 9694        let block_ids = self.insert_blocks(blocks, None, cx);
 9695        bp_prompt.update(cx, |prompt, _| {
 9696            prompt.add_block_ids(block_ids);
 9697        });
 9698    }
 9699
 9700    pub(crate) fn breakpoint_at_row(
 9701        &self,
 9702        row: u32,
 9703        window: &mut Window,
 9704        cx: &mut Context<Self>,
 9705    ) -> Option<(Anchor, Breakpoint)> {
 9706        let snapshot = self.snapshot(window, cx);
 9707        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9708
 9709        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9710    }
 9711
 9712    pub(crate) fn breakpoint_at_anchor(
 9713        &self,
 9714        breakpoint_position: Anchor,
 9715        snapshot: &EditorSnapshot,
 9716        cx: &mut Context<Self>,
 9717    ) -> Option<(Anchor, Breakpoint)> {
 9718        let project = self.project.clone()?;
 9719
 9720        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9721            snapshot
 9722                .buffer_snapshot
 9723                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9724        })?;
 9725
 9726        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9727        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9728        let buffer_snapshot = buffer.read(cx).snapshot();
 9729
 9730        let row = buffer_snapshot
 9731            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9732            .row;
 9733
 9734        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9735        let anchor_end = snapshot
 9736            .buffer_snapshot
 9737            .anchor_after(Point::new(row, line_len));
 9738
 9739        let bp = self
 9740            .breakpoint_store
 9741            .as_ref()?
 9742            .read_with(cx, |breakpoint_store, cx| {
 9743                breakpoint_store
 9744                    .breakpoints(
 9745                        &buffer,
 9746                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9747                        &buffer_snapshot,
 9748                        cx,
 9749                    )
 9750                    .next()
 9751                    .and_then(|(bp, _)| {
 9752                        let breakpoint_row = buffer_snapshot
 9753                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9754                            .row;
 9755
 9756                        if breakpoint_row == row {
 9757                            snapshot
 9758                                .buffer_snapshot
 9759                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9760                                .map(|position| (position, bp.bp.clone()))
 9761                        } else {
 9762                            None
 9763                        }
 9764                    })
 9765            });
 9766        bp
 9767    }
 9768
 9769    pub fn edit_log_breakpoint(
 9770        &mut self,
 9771        _: &EditLogBreakpoint,
 9772        window: &mut Window,
 9773        cx: &mut Context<Self>,
 9774    ) {
 9775        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9776            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9777                message: None,
 9778                state: BreakpointState::Enabled,
 9779                condition: None,
 9780                hit_condition: None,
 9781            });
 9782
 9783            self.add_edit_breakpoint_block(
 9784                anchor,
 9785                &breakpoint,
 9786                BreakpointPromptEditAction::Log,
 9787                window,
 9788                cx,
 9789            );
 9790        }
 9791    }
 9792
 9793    fn breakpoints_at_cursors(
 9794        &self,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9798        let snapshot = self.snapshot(window, cx);
 9799        let cursors = self
 9800            .selections
 9801            .disjoint_anchors()
 9802            .into_iter()
 9803            .map(|selection| {
 9804                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9805
 9806                let breakpoint_position = self
 9807                    .breakpoint_at_row(cursor_position.row, window, cx)
 9808                    .map(|bp| bp.0)
 9809                    .unwrap_or_else(|| {
 9810                        snapshot
 9811                            .display_snapshot
 9812                            .buffer_snapshot
 9813                            .anchor_after(Point::new(cursor_position.row, 0))
 9814                    });
 9815
 9816                let breakpoint = self
 9817                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9818                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9819
 9820                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9821            })
 9822            // 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.
 9823            .collect::<HashMap<Anchor, _>>();
 9824
 9825        cursors.into_iter().collect()
 9826    }
 9827
 9828    pub fn enable_breakpoint(
 9829        &mut self,
 9830        _: &crate::actions::EnableBreakpoint,
 9831        window: &mut Window,
 9832        cx: &mut Context<Self>,
 9833    ) {
 9834        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9835            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9836                continue;
 9837            };
 9838            self.edit_breakpoint_at_anchor(
 9839                anchor,
 9840                breakpoint,
 9841                BreakpointEditAction::InvertState,
 9842                cx,
 9843            );
 9844        }
 9845    }
 9846
 9847    pub fn disable_breakpoint(
 9848        &mut self,
 9849        _: &crate::actions::DisableBreakpoint,
 9850        window: &mut Window,
 9851        cx: &mut Context<Self>,
 9852    ) {
 9853        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9854            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9855                continue;
 9856            };
 9857            self.edit_breakpoint_at_anchor(
 9858                anchor,
 9859                breakpoint,
 9860                BreakpointEditAction::InvertState,
 9861                cx,
 9862            );
 9863        }
 9864    }
 9865
 9866    pub fn toggle_breakpoint(
 9867        &mut self,
 9868        _: &crate::actions::ToggleBreakpoint,
 9869        window: &mut Window,
 9870        cx: &mut Context<Self>,
 9871    ) {
 9872        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9873            if let Some(breakpoint) = breakpoint {
 9874                self.edit_breakpoint_at_anchor(
 9875                    anchor,
 9876                    breakpoint,
 9877                    BreakpointEditAction::Toggle,
 9878                    cx,
 9879                );
 9880            } else {
 9881                self.edit_breakpoint_at_anchor(
 9882                    anchor,
 9883                    Breakpoint::new_standard(),
 9884                    BreakpointEditAction::Toggle,
 9885                    cx,
 9886                );
 9887            }
 9888        }
 9889    }
 9890
 9891    pub fn edit_breakpoint_at_anchor(
 9892        &mut self,
 9893        breakpoint_position: Anchor,
 9894        breakpoint: Breakpoint,
 9895        edit_action: BreakpointEditAction,
 9896        cx: &mut Context<Self>,
 9897    ) {
 9898        let Some(breakpoint_store) = &self.breakpoint_store else {
 9899            return;
 9900        };
 9901
 9902        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9903            if breakpoint_position == Anchor::min() {
 9904                self.buffer()
 9905                    .read(cx)
 9906                    .excerpt_buffer_ids()
 9907                    .into_iter()
 9908                    .next()
 9909            } else {
 9910                None
 9911            }
 9912        }) else {
 9913            return;
 9914        };
 9915
 9916        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9917            return;
 9918        };
 9919
 9920        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9921            breakpoint_store.toggle_breakpoint(
 9922                buffer,
 9923                BreakpointWithPosition {
 9924                    position: breakpoint_position.text_anchor,
 9925                    bp: breakpoint,
 9926                },
 9927                edit_action,
 9928                cx,
 9929            );
 9930        });
 9931
 9932        cx.notify();
 9933    }
 9934
 9935    #[cfg(any(test, feature = "test-support"))]
 9936    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9937        self.breakpoint_store.clone()
 9938    }
 9939
 9940    pub fn prepare_restore_change(
 9941        &self,
 9942        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9943        hunk: &MultiBufferDiffHunk,
 9944        cx: &mut App,
 9945    ) -> Option<()> {
 9946        if hunk.is_created_file() {
 9947            return None;
 9948        }
 9949        let buffer = self.buffer.read(cx);
 9950        let diff = buffer.diff_for(hunk.buffer_id)?;
 9951        let buffer = buffer.buffer(hunk.buffer_id)?;
 9952        let buffer = buffer.read(cx);
 9953        let original_text = diff
 9954            .read(cx)
 9955            .base_text()
 9956            .as_rope()
 9957            .slice(hunk.diff_base_byte_range.clone());
 9958        let buffer_snapshot = buffer.snapshot();
 9959        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9960        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9961            probe
 9962                .0
 9963                .start
 9964                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9965                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9966        }) {
 9967            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9968            Some(())
 9969        } else {
 9970            None
 9971        }
 9972    }
 9973
 9974    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9975        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9976    }
 9977
 9978    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9979        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9980    }
 9981
 9982    fn manipulate_lines<Fn>(
 9983        &mut self,
 9984        window: &mut Window,
 9985        cx: &mut Context<Self>,
 9986        mut callback: Fn,
 9987    ) where
 9988        Fn: FnMut(&mut Vec<&str>),
 9989    {
 9990        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9991
 9992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9993        let buffer = self.buffer.read(cx).snapshot(cx);
 9994
 9995        let mut edits = Vec::new();
 9996
 9997        let selections = self.selections.all::<Point>(cx);
 9998        let mut selections = selections.iter().peekable();
 9999        let mut contiguous_row_selections = Vec::new();
10000        let mut new_selections = Vec::new();
10001        let mut added_lines = 0;
10002        let mut removed_lines = 0;
10003
10004        while let Some(selection) = selections.next() {
10005            let (start_row, end_row) = consume_contiguous_rows(
10006                &mut contiguous_row_selections,
10007                selection,
10008                &display_map,
10009                &mut selections,
10010            );
10011
10012            let start_point = Point::new(start_row.0, 0);
10013            let end_point = Point::new(
10014                end_row.previous_row().0,
10015                buffer.line_len(end_row.previous_row()),
10016            );
10017            let text = buffer
10018                .text_for_range(start_point..end_point)
10019                .collect::<String>();
10020
10021            let mut lines = text.split('\n').collect_vec();
10022
10023            let lines_before = lines.len();
10024            callback(&mut lines);
10025            let lines_after = lines.len();
10026
10027            edits.push((start_point..end_point, lines.join("\n")));
10028
10029            // Selections must change based on added and removed line count
10030            let start_row =
10031                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10032            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10033            new_selections.push(Selection {
10034                id: selection.id,
10035                start: start_row,
10036                end: end_row,
10037                goal: SelectionGoal::None,
10038                reversed: selection.reversed,
10039            });
10040
10041            if lines_after > lines_before {
10042                added_lines += lines_after - lines_before;
10043            } else if lines_before > lines_after {
10044                removed_lines += lines_before - lines_after;
10045            }
10046        }
10047
10048        self.transact(window, cx, |this, window, cx| {
10049            let buffer = this.buffer.update(cx, |buffer, cx| {
10050                buffer.edit(edits, None, cx);
10051                buffer.snapshot(cx)
10052            });
10053
10054            // Recalculate offsets on newly edited buffer
10055            let new_selections = new_selections
10056                .iter()
10057                .map(|s| {
10058                    let start_point = Point::new(s.start.0, 0);
10059                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10060                    Selection {
10061                        id: s.id,
10062                        start: buffer.point_to_offset(start_point),
10063                        end: buffer.point_to_offset(end_point),
10064                        goal: s.goal,
10065                        reversed: s.reversed,
10066                    }
10067                })
10068                .collect();
10069
10070            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10071                s.select(new_selections);
10072            });
10073
10074            this.request_autoscroll(Autoscroll::fit(), cx);
10075        });
10076    }
10077
10078    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10079        self.manipulate_text(window, cx, |text| {
10080            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10081            if has_upper_case_characters {
10082                text.to_lowercase()
10083            } else {
10084                text.to_uppercase()
10085            }
10086        })
10087    }
10088
10089    pub fn convert_to_upper_case(
10090        &mut self,
10091        _: &ConvertToUpperCase,
10092        window: &mut Window,
10093        cx: &mut Context<Self>,
10094    ) {
10095        self.manipulate_text(window, cx, |text| text.to_uppercase())
10096    }
10097
10098    pub fn convert_to_lower_case(
10099        &mut self,
10100        _: &ConvertToLowerCase,
10101        window: &mut Window,
10102        cx: &mut Context<Self>,
10103    ) {
10104        self.manipulate_text(window, cx, |text| text.to_lowercase())
10105    }
10106
10107    pub fn convert_to_title_case(
10108        &mut self,
10109        _: &ConvertToTitleCase,
10110        window: &mut Window,
10111        cx: &mut Context<Self>,
10112    ) {
10113        self.manipulate_text(window, cx, |text| {
10114            text.split('\n')
10115                .map(|line| line.to_case(Case::Title))
10116                .join("\n")
10117        })
10118    }
10119
10120    pub fn convert_to_snake_case(
10121        &mut self,
10122        _: &ConvertToSnakeCase,
10123        window: &mut Window,
10124        cx: &mut Context<Self>,
10125    ) {
10126        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10127    }
10128
10129    pub fn convert_to_kebab_case(
10130        &mut self,
10131        _: &ConvertToKebabCase,
10132        window: &mut Window,
10133        cx: &mut Context<Self>,
10134    ) {
10135        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10136    }
10137
10138    pub fn convert_to_upper_camel_case(
10139        &mut self,
10140        _: &ConvertToUpperCamelCase,
10141        window: &mut Window,
10142        cx: &mut Context<Self>,
10143    ) {
10144        self.manipulate_text(window, cx, |text| {
10145            text.split('\n')
10146                .map(|line| line.to_case(Case::UpperCamel))
10147                .join("\n")
10148        })
10149    }
10150
10151    pub fn convert_to_lower_camel_case(
10152        &mut self,
10153        _: &ConvertToLowerCamelCase,
10154        window: &mut Window,
10155        cx: &mut Context<Self>,
10156    ) {
10157        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10158    }
10159
10160    pub fn convert_to_opposite_case(
10161        &mut self,
10162        _: &ConvertToOppositeCase,
10163        window: &mut Window,
10164        cx: &mut Context<Self>,
10165    ) {
10166        self.manipulate_text(window, cx, |text| {
10167            text.chars()
10168                .fold(String::with_capacity(text.len()), |mut t, c| {
10169                    if c.is_uppercase() {
10170                        t.extend(c.to_lowercase());
10171                    } else {
10172                        t.extend(c.to_uppercase());
10173                    }
10174                    t
10175                })
10176        })
10177    }
10178
10179    pub fn convert_to_rot13(
10180        &mut self,
10181        _: &ConvertToRot13,
10182        window: &mut Window,
10183        cx: &mut Context<Self>,
10184    ) {
10185        self.manipulate_text(window, cx, |text| {
10186            text.chars()
10187                .map(|c| match c {
10188                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10189                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10190                    _ => c,
10191                })
10192                .collect()
10193        })
10194    }
10195
10196    pub fn convert_to_rot47(
10197        &mut self,
10198        _: &ConvertToRot47,
10199        window: &mut Window,
10200        cx: &mut Context<Self>,
10201    ) {
10202        self.manipulate_text(window, cx, |text| {
10203            text.chars()
10204                .map(|c| {
10205                    let code_point = c as u32;
10206                    if code_point >= 33 && code_point <= 126 {
10207                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10208                    }
10209                    c
10210                })
10211                .collect()
10212        })
10213    }
10214
10215    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10216    where
10217        Fn: FnMut(&str) -> String,
10218    {
10219        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10220        let buffer = self.buffer.read(cx).snapshot(cx);
10221
10222        let mut new_selections = Vec::new();
10223        let mut edits = Vec::new();
10224        let mut selection_adjustment = 0i32;
10225
10226        for selection in self.selections.all::<usize>(cx) {
10227            let selection_is_empty = selection.is_empty();
10228
10229            let (start, end) = if selection_is_empty {
10230                let word_range = movement::surrounding_word(
10231                    &display_map,
10232                    selection.start.to_display_point(&display_map),
10233                );
10234                let start = word_range.start.to_offset(&display_map, Bias::Left);
10235                let end = word_range.end.to_offset(&display_map, Bias::Left);
10236                (start, end)
10237            } else {
10238                (selection.start, selection.end)
10239            };
10240
10241            let text = buffer.text_for_range(start..end).collect::<String>();
10242            let old_length = text.len() as i32;
10243            let text = callback(&text);
10244
10245            new_selections.push(Selection {
10246                start: (start as i32 - selection_adjustment) as usize,
10247                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10248                goal: SelectionGoal::None,
10249                ..selection
10250            });
10251
10252            selection_adjustment += old_length - text.len() as i32;
10253
10254            edits.push((start..end, text));
10255        }
10256
10257        self.transact(window, cx, |this, window, cx| {
10258            this.buffer.update(cx, |buffer, cx| {
10259                buffer.edit(edits, None, cx);
10260            });
10261
10262            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10263                s.select(new_selections);
10264            });
10265
10266            this.request_autoscroll(Autoscroll::fit(), cx);
10267        });
10268    }
10269
10270    pub fn duplicate(
10271        &mut self,
10272        upwards: bool,
10273        whole_lines: bool,
10274        window: &mut Window,
10275        cx: &mut Context<Self>,
10276    ) {
10277        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10278
10279        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10280        let buffer = &display_map.buffer_snapshot;
10281        let selections = self.selections.all::<Point>(cx);
10282
10283        let mut edits = Vec::new();
10284        let mut selections_iter = selections.iter().peekable();
10285        while let Some(selection) = selections_iter.next() {
10286            let mut rows = selection.spanned_rows(false, &display_map);
10287            // duplicate line-wise
10288            if whole_lines || selection.start == selection.end {
10289                // Avoid duplicating the same lines twice.
10290                while let Some(next_selection) = selections_iter.peek() {
10291                    let next_rows = next_selection.spanned_rows(false, &display_map);
10292                    if next_rows.start < rows.end {
10293                        rows.end = next_rows.end;
10294                        selections_iter.next().unwrap();
10295                    } else {
10296                        break;
10297                    }
10298                }
10299
10300                // Copy the text from the selected row region and splice it either at the start
10301                // or end of the region.
10302                let start = Point::new(rows.start.0, 0);
10303                let end = Point::new(
10304                    rows.end.previous_row().0,
10305                    buffer.line_len(rows.end.previous_row()),
10306                );
10307                let text = buffer
10308                    .text_for_range(start..end)
10309                    .chain(Some("\n"))
10310                    .collect::<String>();
10311                let insert_location = if upwards {
10312                    Point::new(rows.end.0, 0)
10313                } else {
10314                    start
10315                };
10316                edits.push((insert_location..insert_location, text));
10317            } else {
10318                // duplicate character-wise
10319                let start = selection.start;
10320                let end = selection.end;
10321                let text = buffer.text_for_range(start..end).collect::<String>();
10322                edits.push((selection.end..selection.end, text));
10323            }
10324        }
10325
10326        self.transact(window, cx, |this, _, cx| {
10327            this.buffer.update(cx, |buffer, cx| {
10328                buffer.edit(edits, None, cx);
10329            });
10330
10331            this.request_autoscroll(Autoscroll::fit(), cx);
10332        });
10333    }
10334
10335    pub fn duplicate_line_up(
10336        &mut self,
10337        _: &DuplicateLineUp,
10338        window: &mut Window,
10339        cx: &mut Context<Self>,
10340    ) {
10341        self.duplicate(true, true, window, cx);
10342    }
10343
10344    pub fn duplicate_line_down(
10345        &mut self,
10346        _: &DuplicateLineDown,
10347        window: &mut Window,
10348        cx: &mut Context<Self>,
10349    ) {
10350        self.duplicate(false, true, window, cx);
10351    }
10352
10353    pub fn duplicate_selection(
10354        &mut self,
10355        _: &DuplicateSelection,
10356        window: &mut Window,
10357        cx: &mut Context<Self>,
10358    ) {
10359        self.duplicate(false, false, window, cx);
10360    }
10361
10362    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10363        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10364
10365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10366        let buffer = self.buffer.read(cx).snapshot(cx);
10367
10368        let mut edits = Vec::new();
10369        let mut unfold_ranges = Vec::new();
10370        let mut refold_creases = Vec::new();
10371
10372        let selections = self.selections.all::<Point>(cx);
10373        let mut selections = selections.iter().peekable();
10374        let mut contiguous_row_selections = Vec::new();
10375        let mut new_selections = Vec::new();
10376
10377        while let Some(selection) = selections.next() {
10378            // Find all the selections that span a contiguous row range
10379            let (start_row, end_row) = consume_contiguous_rows(
10380                &mut contiguous_row_selections,
10381                selection,
10382                &display_map,
10383                &mut selections,
10384            );
10385
10386            // Move the text spanned by the row range to be before the line preceding the row range
10387            if start_row.0 > 0 {
10388                let range_to_move = Point::new(
10389                    start_row.previous_row().0,
10390                    buffer.line_len(start_row.previous_row()),
10391                )
10392                    ..Point::new(
10393                        end_row.previous_row().0,
10394                        buffer.line_len(end_row.previous_row()),
10395                    );
10396                let insertion_point = display_map
10397                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10398                    .0;
10399
10400                // Don't move lines across excerpts
10401                if buffer
10402                    .excerpt_containing(insertion_point..range_to_move.end)
10403                    .is_some()
10404                {
10405                    let text = buffer
10406                        .text_for_range(range_to_move.clone())
10407                        .flat_map(|s| s.chars())
10408                        .skip(1)
10409                        .chain(['\n'])
10410                        .collect::<String>();
10411
10412                    edits.push((
10413                        buffer.anchor_after(range_to_move.start)
10414                            ..buffer.anchor_before(range_to_move.end),
10415                        String::new(),
10416                    ));
10417                    let insertion_anchor = buffer.anchor_after(insertion_point);
10418                    edits.push((insertion_anchor..insertion_anchor, text));
10419
10420                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10421
10422                    // Move selections up
10423                    new_selections.extend(contiguous_row_selections.drain(..).map(
10424                        |mut selection| {
10425                            selection.start.row -= row_delta;
10426                            selection.end.row -= row_delta;
10427                            selection
10428                        },
10429                    ));
10430
10431                    // Move folds up
10432                    unfold_ranges.push(range_to_move.clone());
10433                    for fold in display_map.folds_in_range(
10434                        buffer.anchor_before(range_to_move.start)
10435                            ..buffer.anchor_after(range_to_move.end),
10436                    ) {
10437                        let mut start = fold.range.start.to_point(&buffer);
10438                        let mut end = fold.range.end.to_point(&buffer);
10439                        start.row -= row_delta;
10440                        end.row -= row_delta;
10441                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10442                    }
10443                }
10444            }
10445
10446            // If we didn't move line(s), preserve the existing selections
10447            new_selections.append(&mut contiguous_row_selections);
10448        }
10449
10450        self.transact(window, cx, |this, window, cx| {
10451            this.unfold_ranges(&unfold_ranges, true, true, cx);
10452            this.buffer.update(cx, |buffer, cx| {
10453                for (range, text) in edits {
10454                    buffer.edit([(range, text)], None, cx);
10455                }
10456            });
10457            this.fold_creases(refold_creases, true, window, cx);
10458            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10459                s.select(new_selections);
10460            })
10461        });
10462    }
10463
10464    pub fn move_line_down(
10465        &mut self,
10466        _: &MoveLineDown,
10467        window: &mut Window,
10468        cx: &mut Context<Self>,
10469    ) {
10470        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10471
10472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10473        let buffer = self.buffer.read(cx).snapshot(cx);
10474
10475        let mut edits = Vec::new();
10476        let mut unfold_ranges = Vec::new();
10477        let mut refold_creases = Vec::new();
10478
10479        let selections = self.selections.all::<Point>(cx);
10480        let mut selections = selections.iter().peekable();
10481        let mut contiguous_row_selections = Vec::new();
10482        let mut new_selections = Vec::new();
10483
10484        while let Some(selection) = selections.next() {
10485            // Find all the selections that span a contiguous row range
10486            let (start_row, end_row) = consume_contiguous_rows(
10487                &mut contiguous_row_selections,
10488                selection,
10489                &display_map,
10490                &mut selections,
10491            );
10492
10493            // Move the text spanned by the row range to be after the last line of the row range
10494            if end_row.0 <= buffer.max_point().row {
10495                let range_to_move =
10496                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10497                let insertion_point = display_map
10498                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10499                    .0;
10500
10501                // Don't move lines across excerpt boundaries
10502                if buffer
10503                    .excerpt_containing(range_to_move.start..insertion_point)
10504                    .is_some()
10505                {
10506                    let mut text = String::from("\n");
10507                    text.extend(buffer.text_for_range(range_to_move.clone()));
10508                    text.pop(); // Drop trailing newline
10509                    edits.push((
10510                        buffer.anchor_after(range_to_move.start)
10511                            ..buffer.anchor_before(range_to_move.end),
10512                        String::new(),
10513                    ));
10514                    let insertion_anchor = buffer.anchor_after(insertion_point);
10515                    edits.push((insertion_anchor..insertion_anchor, text));
10516
10517                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10518
10519                    // Move selections down
10520                    new_selections.extend(contiguous_row_selections.drain(..).map(
10521                        |mut selection| {
10522                            selection.start.row += row_delta;
10523                            selection.end.row += row_delta;
10524                            selection
10525                        },
10526                    ));
10527
10528                    // Move folds down
10529                    unfold_ranges.push(range_to_move.clone());
10530                    for fold in display_map.folds_in_range(
10531                        buffer.anchor_before(range_to_move.start)
10532                            ..buffer.anchor_after(range_to_move.end),
10533                    ) {
10534                        let mut start = fold.range.start.to_point(&buffer);
10535                        let mut end = fold.range.end.to_point(&buffer);
10536                        start.row += row_delta;
10537                        end.row += row_delta;
10538                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10539                    }
10540                }
10541            }
10542
10543            // If we didn't move line(s), preserve the existing selections
10544            new_selections.append(&mut contiguous_row_selections);
10545        }
10546
10547        self.transact(window, cx, |this, window, cx| {
10548            this.unfold_ranges(&unfold_ranges, true, true, cx);
10549            this.buffer.update(cx, |buffer, cx| {
10550                for (range, text) in edits {
10551                    buffer.edit([(range, text)], None, cx);
10552                }
10553            });
10554            this.fold_creases(refold_creases, true, window, cx);
10555            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10556                s.select(new_selections)
10557            });
10558        });
10559    }
10560
10561    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10562        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10563        let text_layout_details = &self.text_layout_details(window);
10564        self.transact(window, cx, |this, window, cx| {
10565            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10566                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10567                s.move_with(|display_map, selection| {
10568                    if !selection.is_empty() {
10569                        return;
10570                    }
10571
10572                    let mut head = selection.head();
10573                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10574                    if head.column() == display_map.line_len(head.row()) {
10575                        transpose_offset = display_map
10576                            .buffer_snapshot
10577                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10578                    }
10579
10580                    if transpose_offset == 0 {
10581                        return;
10582                    }
10583
10584                    *head.column_mut() += 1;
10585                    head = display_map.clip_point(head, Bias::Right);
10586                    let goal = SelectionGoal::HorizontalPosition(
10587                        display_map
10588                            .x_for_display_point(head, text_layout_details)
10589                            .into(),
10590                    );
10591                    selection.collapse_to(head, goal);
10592
10593                    let transpose_start = display_map
10594                        .buffer_snapshot
10595                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10596                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10597                        let transpose_end = display_map
10598                            .buffer_snapshot
10599                            .clip_offset(transpose_offset + 1, Bias::Right);
10600                        if let Some(ch) =
10601                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10602                        {
10603                            edits.push((transpose_start..transpose_offset, String::new()));
10604                            edits.push((transpose_end..transpose_end, ch.to_string()));
10605                        }
10606                    }
10607                });
10608                edits
10609            });
10610            this.buffer
10611                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10612            let selections = this.selections.all::<usize>(cx);
10613            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10614                s.select(selections);
10615            });
10616        });
10617    }
10618
10619    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10620        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10621        self.rewrap_impl(RewrapOptions::default(), cx)
10622    }
10623
10624    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10625        let buffer = self.buffer.read(cx).snapshot(cx);
10626        let selections = self.selections.all::<Point>(cx);
10627        let mut selections = selections.iter().peekable();
10628
10629        let mut edits = Vec::new();
10630        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10631
10632        while let Some(selection) = selections.next() {
10633            let mut start_row = selection.start.row;
10634            let mut end_row = selection.end.row;
10635
10636            // Skip selections that overlap with a range that has already been rewrapped.
10637            let selection_range = start_row..end_row;
10638            if rewrapped_row_ranges
10639                .iter()
10640                .any(|range| range.overlaps(&selection_range))
10641            {
10642                continue;
10643            }
10644
10645            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10646
10647            // Since not all lines in the selection may be at the same indent
10648            // level, choose the indent size that is the most common between all
10649            // of the lines.
10650            //
10651            // If there is a tie, we use the deepest indent.
10652            let (indent_size, indent_end) = {
10653                let mut indent_size_occurrences = HashMap::default();
10654                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10655
10656                for row in start_row..=end_row {
10657                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10658                    rows_by_indent_size.entry(indent).or_default().push(row);
10659                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10660                }
10661
10662                let indent_size = indent_size_occurrences
10663                    .into_iter()
10664                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10665                    .map(|(indent, _)| indent)
10666                    .unwrap_or_default();
10667                let row = rows_by_indent_size[&indent_size][0];
10668                let indent_end = Point::new(row, indent_size.len);
10669
10670                (indent_size, indent_end)
10671            };
10672
10673            let mut line_prefix = indent_size.chars().collect::<String>();
10674
10675            let mut inside_comment = false;
10676            if let Some(comment_prefix) =
10677                buffer
10678                    .language_scope_at(selection.head())
10679                    .and_then(|language| {
10680                        language
10681                            .line_comment_prefixes()
10682                            .iter()
10683                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10684                            .cloned()
10685                    })
10686            {
10687                line_prefix.push_str(&comment_prefix);
10688                inside_comment = true;
10689            }
10690
10691            let language_settings = buffer.language_settings_at(selection.head(), cx);
10692            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10693                RewrapBehavior::InComments => inside_comment,
10694                RewrapBehavior::InSelections => !selection.is_empty(),
10695                RewrapBehavior::Anywhere => true,
10696            };
10697
10698            let should_rewrap = options.override_language_settings
10699                || allow_rewrap_based_on_language
10700                || self.hard_wrap.is_some();
10701            if !should_rewrap {
10702                continue;
10703            }
10704
10705            if selection.is_empty() {
10706                'expand_upwards: while start_row > 0 {
10707                    let prev_row = start_row - 1;
10708                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10709                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10710                    {
10711                        start_row = prev_row;
10712                    } else {
10713                        break 'expand_upwards;
10714                    }
10715                }
10716
10717                'expand_downwards: while end_row < buffer.max_point().row {
10718                    let next_row = end_row + 1;
10719                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10720                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10721                    {
10722                        end_row = next_row;
10723                    } else {
10724                        break 'expand_downwards;
10725                    }
10726                }
10727            }
10728
10729            let start = Point::new(start_row, 0);
10730            let start_offset = start.to_offset(&buffer);
10731            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10732            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10733            let Some(lines_without_prefixes) = selection_text
10734                .lines()
10735                .map(|line| {
10736                    line.strip_prefix(&line_prefix)
10737                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10738                        .with_context(|| {
10739                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10740                        })
10741                })
10742                .collect::<Result<Vec<_>, _>>()
10743                .log_err()
10744            else {
10745                continue;
10746            };
10747
10748            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10749                buffer
10750                    .language_settings_at(Point::new(start_row, 0), cx)
10751                    .preferred_line_length as usize
10752            });
10753            let wrapped_text = wrap_with_prefix(
10754                line_prefix,
10755                lines_without_prefixes.join("\n"),
10756                wrap_column,
10757                tab_size,
10758                options.preserve_existing_whitespace,
10759            );
10760
10761            // TODO: should always use char-based diff while still supporting cursor behavior that
10762            // matches vim.
10763            let mut diff_options = DiffOptions::default();
10764            if options.override_language_settings {
10765                diff_options.max_word_diff_len = 0;
10766                diff_options.max_word_diff_line_count = 0;
10767            } else {
10768                diff_options.max_word_diff_len = usize::MAX;
10769                diff_options.max_word_diff_line_count = usize::MAX;
10770            }
10771
10772            for (old_range, new_text) in
10773                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10774            {
10775                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10776                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10777                edits.push((edit_start..edit_end, new_text));
10778            }
10779
10780            rewrapped_row_ranges.push(start_row..=end_row);
10781        }
10782
10783        self.buffer
10784            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10785    }
10786
10787    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10788        let mut text = String::new();
10789        let buffer = self.buffer.read(cx).snapshot(cx);
10790        let mut selections = self.selections.all::<Point>(cx);
10791        let mut clipboard_selections = Vec::with_capacity(selections.len());
10792        {
10793            let max_point = buffer.max_point();
10794            let mut is_first = true;
10795            for selection in &mut selections {
10796                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10797                if is_entire_line {
10798                    selection.start = Point::new(selection.start.row, 0);
10799                    if !selection.is_empty() && selection.end.column == 0 {
10800                        selection.end = cmp::min(max_point, selection.end);
10801                    } else {
10802                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10803                    }
10804                    selection.goal = SelectionGoal::None;
10805                }
10806                if is_first {
10807                    is_first = false;
10808                } else {
10809                    text += "\n";
10810                }
10811                let mut len = 0;
10812                for chunk in buffer.text_for_range(selection.start..selection.end) {
10813                    text.push_str(chunk);
10814                    len += chunk.len();
10815                }
10816                clipboard_selections.push(ClipboardSelection {
10817                    len,
10818                    is_entire_line,
10819                    first_line_indent: buffer
10820                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10821                        .len,
10822                });
10823            }
10824        }
10825
10826        self.transact(window, cx, |this, window, cx| {
10827            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10828                s.select(selections);
10829            });
10830            this.insert("", window, cx);
10831        });
10832        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10833    }
10834
10835    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10836        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10837        let item = self.cut_common(window, cx);
10838        cx.write_to_clipboard(item);
10839    }
10840
10841    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10842        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10843        self.change_selections(None, window, cx, |s| {
10844            s.move_with(|snapshot, sel| {
10845                if sel.is_empty() {
10846                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10847                }
10848            });
10849        });
10850        let item = self.cut_common(window, cx);
10851        cx.set_global(KillRing(item))
10852    }
10853
10854    pub fn kill_ring_yank(
10855        &mut self,
10856        _: &KillRingYank,
10857        window: &mut Window,
10858        cx: &mut Context<Self>,
10859    ) {
10860        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10861        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10862            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10863                (kill_ring.text().to_string(), kill_ring.metadata_json())
10864            } else {
10865                return;
10866            }
10867        } else {
10868            return;
10869        };
10870        self.do_paste(&text, metadata, false, window, cx);
10871    }
10872
10873    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10874        self.do_copy(true, cx);
10875    }
10876
10877    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10878        self.do_copy(false, cx);
10879    }
10880
10881    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10882        let selections = self.selections.all::<Point>(cx);
10883        let buffer = self.buffer.read(cx).read(cx);
10884        let mut text = String::new();
10885
10886        let mut clipboard_selections = Vec::with_capacity(selections.len());
10887        {
10888            let max_point = buffer.max_point();
10889            let mut is_first = true;
10890            for selection in &selections {
10891                let mut start = selection.start;
10892                let mut end = selection.end;
10893                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10894                if is_entire_line {
10895                    start = Point::new(start.row, 0);
10896                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10897                }
10898
10899                let mut trimmed_selections = Vec::new();
10900                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10901                    let row = MultiBufferRow(start.row);
10902                    let first_indent = buffer.indent_size_for_line(row);
10903                    if first_indent.len == 0 || start.column > first_indent.len {
10904                        trimmed_selections.push(start..end);
10905                    } else {
10906                        trimmed_selections.push(
10907                            Point::new(row.0, first_indent.len)
10908                                ..Point::new(row.0, buffer.line_len(row)),
10909                        );
10910                        for row in start.row + 1..=end.row {
10911                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10912                            if row == end.row {
10913                                line_len = end.column;
10914                            }
10915                            if line_len == 0 {
10916                                trimmed_selections
10917                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10918                                continue;
10919                            }
10920                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10921                            if row_indent_size.len >= first_indent.len {
10922                                trimmed_selections.push(
10923                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10924                                );
10925                            } else {
10926                                trimmed_selections.clear();
10927                                trimmed_selections.push(start..end);
10928                                break;
10929                            }
10930                        }
10931                    }
10932                } else {
10933                    trimmed_selections.push(start..end);
10934                }
10935
10936                for trimmed_range in trimmed_selections {
10937                    if is_first {
10938                        is_first = false;
10939                    } else {
10940                        text += "\n";
10941                    }
10942                    let mut len = 0;
10943                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10944                        text.push_str(chunk);
10945                        len += chunk.len();
10946                    }
10947                    clipboard_selections.push(ClipboardSelection {
10948                        len,
10949                        is_entire_line,
10950                        first_line_indent: buffer
10951                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10952                            .len,
10953                    });
10954                }
10955            }
10956        }
10957
10958        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10959            text,
10960            clipboard_selections,
10961        ));
10962    }
10963
10964    pub fn do_paste(
10965        &mut self,
10966        text: &String,
10967        clipboard_selections: Option<Vec<ClipboardSelection>>,
10968        handle_entire_lines: bool,
10969        window: &mut Window,
10970        cx: &mut Context<Self>,
10971    ) {
10972        if self.read_only(cx) {
10973            return;
10974        }
10975
10976        let clipboard_text = Cow::Borrowed(text);
10977
10978        self.transact(window, cx, |this, window, cx| {
10979            if let Some(mut clipboard_selections) = clipboard_selections {
10980                let old_selections = this.selections.all::<usize>(cx);
10981                let all_selections_were_entire_line =
10982                    clipboard_selections.iter().all(|s| s.is_entire_line);
10983                let first_selection_indent_column =
10984                    clipboard_selections.first().map(|s| s.first_line_indent);
10985                if clipboard_selections.len() != old_selections.len() {
10986                    clipboard_selections.drain(..);
10987                }
10988                let cursor_offset = this.selections.last::<usize>(cx).head();
10989                let mut auto_indent_on_paste = true;
10990
10991                this.buffer.update(cx, |buffer, cx| {
10992                    let snapshot = buffer.read(cx);
10993                    auto_indent_on_paste = snapshot
10994                        .language_settings_at(cursor_offset, cx)
10995                        .auto_indent_on_paste;
10996
10997                    let mut start_offset = 0;
10998                    let mut edits = Vec::new();
10999                    let mut original_indent_columns = Vec::new();
11000                    for (ix, selection) in old_selections.iter().enumerate() {
11001                        let to_insert;
11002                        let entire_line;
11003                        let original_indent_column;
11004                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11005                            let end_offset = start_offset + clipboard_selection.len;
11006                            to_insert = &clipboard_text[start_offset..end_offset];
11007                            entire_line = clipboard_selection.is_entire_line;
11008                            start_offset = end_offset + 1;
11009                            original_indent_column = Some(clipboard_selection.first_line_indent);
11010                        } else {
11011                            to_insert = clipboard_text.as_str();
11012                            entire_line = all_selections_were_entire_line;
11013                            original_indent_column = first_selection_indent_column
11014                        }
11015
11016                        // If the corresponding selection was empty when this slice of the
11017                        // clipboard text was written, then the entire line containing the
11018                        // selection was copied. If this selection is also currently empty,
11019                        // then paste the line before the current line of the buffer.
11020                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11021                            let column = selection.start.to_point(&snapshot).column as usize;
11022                            let line_start = selection.start - column;
11023                            line_start..line_start
11024                        } else {
11025                            selection.range()
11026                        };
11027
11028                        edits.push((range, to_insert));
11029                        original_indent_columns.push(original_indent_column);
11030                    }
11031                    drop(snapshot);
11032
11033                    buffer.edit(
11034                        edits,
11035                        if auto_indent_on_paste {
11036                            Some(AutoindentMode::Block {
11037                                original_indent_columns,
11038                            })
11039                        } else {
11040                            None
11041                        },
11042                        cx,
11043                    );
11044                });
11045
11046                let selections = this.selections.all::<usize>(cx);
11047                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11048                    s.select(selections)
11049                });
11050            } else {
11051                this.insert(&clipboard_text, window, cx);
11052            }
11053        });
11054    }
11055
11056    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11057        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11058        if let Some(item) = cx.read_from_clipboard() {
11059            let entries = item.entries();
11060
11061            match entries.first() {
11062                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11063                // of all the pasted entries.
11064                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11065                    .do_paste(
11066                        clipboard_string.text(),
11067                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11068                        true,
11069                        window,
11070                        cx,
11071                    ),
11072                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11073            }
11074        }
11075    }
11076
11077    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11078        if self.read_only(cx) {
11079            return;
11080        }
11081
11082        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11083
11084        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11085            if let Some((selections, _)) =
11086                self.selection_history.transaction(transaction_id).cloned()
11087            {
11088                self.change_selections(None, window, cx, |s| {
11089                    s.select_anchors(selections.to_vec());
11090                });
11091            } else {
11092                log::error!(
11093                    "No entry in selection_history found for undo. \
11094                     This may correspond to a bug where undo does not update the selection. \
11095                     If this is occurring, please add details to \
11096                     https://github.com/zed-industries/zed/issues/22692"
11097                );
11098            }
11099            self.request_autoscroll(Autoscroll::fit(), cx);
11100            self.unmark_text(window, cx);
11101            self.refresh_inline_completion(true, false, window, cx);
11102            cx.emit(EditorEvent::Edited { transaction_id });
11103            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11104        }
11105    }
11106
11107    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11108        if self.read_only(cx) {
11109            return;
11110        }
11111
11112        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11113
11114        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11115            if let Some((_, Some(selections))) =
11116                self.selection_history.transaction(transaction_id).cloned()
11117            {
11118                self.change_selections(None, window, cx, |s| {
11119                    s.select_anchors(selections.to_vec());
11120                });
11121            } else {
11122                log::error!(
11123                    "No entry in selection_history found for redo. \
11124                     This may correspond to a bug where undo does not update the selection. \
11125                     If this is occurring, please add details to \
11126                     https://github.com/zed-industries/zed/issues/22692"
11127                );
11128            }
11129            self.request_autoscroll(Autoscroll::fit(), cx);
11130            self.unmark_text(window, cx);
11131            self.refresh_inline_completion(true, false, window, cx);
11132            cx.emit(EditorEvent::Edited { transaction_id });
11133        }
11134    }
11135
11136    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11137        self.buffer
11138            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11139    }
11140
11141    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11142        self.buffer
11143            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11144    }
11145
11146    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11147        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11148        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11149            s.move_with(|map, selection| {
11150                let cursor = if selection.is_empty() {
11151                    movement::left(map, selection.start)
11152                } else {
11153                    selection.start
11154                };
11155                selection.collapse_to(cursor, SelectionGoal::None);
11156            });
11157        })
11158    }
11159
11160    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11161        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11162        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11163            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11164        })
11165    }
11166
11167    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11168        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11169        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11170            s.move_with(|map, selection| {
11171                let cursor = if selection.is_empty() {
11172                    movement::right(map, selection.end)
11173                } else {
11174                    selection.end
11175                };
11176                selection.collapse_to(cursor, SelectionGoal::None)
11177            });
11178        })
11179    }
11180
11181    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11182        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11183        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11184            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11185        })
11186    }
11187
11188    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11189        if self.take_rename(true, window, cx).is_some() {
11190            return;
11191        }
11192
11193        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11194            cx.propagate();
11195            return;
11196        }
11197
11198        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11199
11200        let text_layout_details = &self.text_layout_details(window);
11201        let selection_count = self.selections.count();
11202        let first_selection = self.selections.first_anchor();
11203
11204        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11205            s.move_with(|map, selection| {
11206                if !selection.is_empty() {
11207                    selection.goal = SelectionGoal::None;
11208                }
11209                let (cursor, goal) = movement::up(
11210                    map,
11211                    selection.start,
11212                    selection.goal,
11213                    false,
11214                    text_layout_details,
11215                );
11216                selection.collapse_to(cursor, goal);
11217            });
11218        });
11219
11220        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11221        {
11222            cx.propagate();
11223        }
11224    }
11225
11226    pub fn move_up_by_lines(
11227        &mut self,
11228        action: &MoveUpByLines,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        if self.take_rename(true, window, cx).is_some() {
11233            return;
11234        }
11235
11236        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11237            cx.propagate();
11238            return;
11239        }
11240
11241        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11242
11243        let text_layout_details = &self.text_layout_details(window);
11244
11245        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11246            s.move_with(|map, selection| {
11247                if !selection.is_empty() {
11248                    selection.goal = SelectionGoal::None;
11249                }
11250                let (cursor, goal) = movement::up_by_rows(
11251                    map,
11252                    selection.start,
11253                    action.lines,
11254                    selection.goal,
11255                    false,
11256                    text_layout_details,
11257                );
11258                selection.collapse_to(cursor, goal);
11259            });
11260        })
11261    }
11262
11263    pub fn move_down_by_lines(
11264        &mut self,
11265        action: &MoveDownByLines,
11266        window: &mut Window,
11267        cx: &mut Context<Self>,
11268    ) {
11269        if self.take_rename(true, window, cx).is_some() {
11270            return;
11271        }
11272
11273        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11274            cx.propagate();
11275            return;
11276        }
11277
11278        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11279
11280        let text_layout_details = &self.text_layout_details(window);
11281
11282        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11283            s.move_with(|map, selection| {
11284                if !selection.is_empty() {
11285                    selection.goal = SelectionGoal::None;
11286                }
11287                let (cursor, goal) = movement::down_by_rows(
11288                    map,
11289                    selection.start,
11290                    action.lines,
11291                    selection.goal,
11292                    false,
11293                    text_layout_details,
11294                );
11295                selection.collapse_to(cursor, goal);
11296            });
11297        })
11298    }
11299
11300    pub fn select_down_by_lines(
11301        &mut self,
11302        action: &SelectDownByLines,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11307        let text_layout_details = &self.text_layout_details(window);
11308        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11309            s.move_heads_with(|map, head, goal| {
11310                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11311            })
11312        })
11313    }
11314
11315    pub fn select_up_by_lines(
11316        &mut self,
11317        action: &SelectUpByLines,
11318        window: &mut Window,
11319        cx: &mut Context<Self>,
11320    ) {
11321        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11322        let text_layout_details = &self.text_layout_details(window);
11323        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11324            s.move_heads_with(|map, head, goal| {
11325                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11326            })
11327        })
11328    }
11329
11330    pub fn select_page_up(
11331        &mut self,
11332        _: &SelectPageUp,
11333        window: &mut Window,
11334        cx: &mut Context<Self>,
11335    ) {
11336        let Some(row_count) = self.visible_row_count() else {
11337            return;
11338        };
11339
11340        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11341
11342        let text_layout_details = &self.text_layout_details(window);
11343
11344        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11345            s.move_heads_with(|map, head, goal| {
11346                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11347            })
11348        })
11349    }
11350
11351    pub fn move_page_up(
11352        &mut self,
11353        action: &MovePageUp,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        if self.take_rename(true, window, cx).is_some() {
11358            return;
11359        }
11360
11361        if self
11362            .context_menu
11363            .borrow_mut()
11364            .as_mut()
11365            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11366            .unwrap_or(false)
11367        {
11368            return;
11369        }
11370
11371        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11372            cx.propagate();
11373            return;
11374        }
11375
11376        let Some(row_count) = self.visible_row_count() else {
11377            return;
11378        };
11379
11380        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11381
11382        let autoscroll = if action.center_cursor {
11383            Autoscroll::center()
11384        } else {
11385            Autoscroll::fit()
11386        };
11387
11388        let text_layout_details = &self.text_layout_details(window);
11389
11390        self.change_selections(Some(autoscroll), window, cx, |s| {
11391            s.move_with(|map, selection| {
11392                if !selection.is_empty() {
11393                    selection.goal = SelectionGoal::None;
11394                }
11395                let (cursor, goal) = movement::up_by_rows(
11396                    map,
11397                    selection.end,
11398                    row_count,
11399                    selection.goal,
11400                    false,
11401                    text_layout_details,
11402                );
11403                selection.collapse_to(cursor, goal);
11404            });
11405        });
11406    }
11407
11408    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11409        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11410        let text_layout_details = &self.text_layout_details(window);
11411        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11412            s.move_heads_with(|map, head, goal| {
11413                movement::up(map, head, goal, false, text_layout_details)
11414            })
11415        })
11416    }
11417
11418    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11419        self.take_rename(true, window, cx);
11420
11421        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11422            cx.propagate();
11423            return;
11424        }
11425
11426        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11427
11428        let text_layout_details = &self.text_layout_details(window);
11429        let selection_count = self.selections.count();
11430        let first_selection = self.selections.first_anchor();
11431
11432        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11433            s.move_with(|map, selection| {
11434                if !selection.is_empty() {
11435                    selection.goal = SelectionGoal::None;
11436                }
11437                let (cursor, goal) = movement::down(
11438                    map,
11439                    selection.end,
11440                    selection.goal,
11441                    false,
11442                    text_layout_details,
11443                );
11444                selection.collapse_to(cursor, goal);
11445            });
11446        });
11447
11448        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11449        {
11450            cx.propagate();
11451        }
11452    }
11453
11454    pub fn select_page_down(
11455        &mut self,
11456        _: &SelectPageDown,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        let Some(row_count) = self.visible_row_count() else {
11461            return;
11462        };
11463
11464        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11465
11466        let text_layout_details = &self.text_layout_details(window);
11467
11468        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11469            s.move_heads_with(|map, head, goal| {
11470                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11471            })
11472        })
11473    }
11474
11475    pub fn move_page_down(
11476        &mut self,
11477        action: &MovePageDown,
11478        window: &mut Window,
11479        cx: &mut Context<Self>,
11480    ) {
11481        if self.take_rename(true, window, cx).is_some() {
11482            return;
11483        }
11484
11485        if self
11486            .context_menu
11487            .borrow_mut()
11488            .as_mut()
11489            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11490            .unwrap_or(false)
11491        {
11492            return;
11493        }
11494
11495        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11496            cx.propagate();
11497            return;
11498        }
11499
11500        let Some(row_count) = self.visible_row_count() else {
11501            return;
11502        };
11503
11504        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11505
11506        let autoscroll = if action.center_cursor {
11507            Autoscroll::center()
11508        } else {
11509            Autoscroll::fit()
11510        };
11511
11512        let text_layout_details = &self.text_layout_details(window);
11513        self.change_selections(Some(autoscroll), window, cx, |s| {
11514            s.move_with(|map, selection| {
11515                if !selection.is_empty() {
11516                    selection.goal = SelectionGoal::None;
11517                }
11518                let (cursor, goal) = movement::down_by_rows(
11519                    map,
11520                    selection.end,
11521                    row_count,
11522                    selection.goal,
11523                    false,
11524                    text_layout_details,
11525                );
11526                selection.collapse_to(cursor, goal);
11527            });
11528        });
11529    }
11530
11531    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11532        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11533        let text_layout_details = &self.text_layout_details(window);
11534        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11535            s.move_heads_with(|map, head, goal| {
11536                movement::down(map, head, goal, false, text_layout_details)
11537            })
11538        });
11539    }
11540
11541    pub fn context_menu_first(
11542        &mut self,
11543        _: &ContextMenuFirst,
11544        window: &mut Window,
11545        cx: &mut Context<Self>,
11546    ) {
11547        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11548            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11549        }
11550    }
11551
11552    pub fn context_menu_prev(
11553        &mut self,
11554        _: &ContextMenuPrevious,
11555        window: &mut Window,
11556        cx: &mut Context<Self>,
11557    ) {
11558        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11559            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11560        }
11561    }
11562
11563    pub fn context_menu_next(
11564        &mut self,
11565        _: &ContextMenuNext,
11566        window: &mut Window,
11567        cx: &mut Context<Self>,
11568    ) {
11569        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11570            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11571        }
11572    }
11573
11574    pub fn context_menu_last(
11575        &mut self,
11576        _: &ContextMenuLast,
11577        window: &mut Window,
11578        cx: &mut Context<Self>,
11579    ) {
11580        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11581            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11582        }
11583    }
11584
11585    pub fn move_to_previous_word_start(
11586        &mut self,
11587        _: &MoveToPreviousWordStart,
11588        window: &mut Window,
11589        cx: &mut Context<Self>,
11590    ) {
11591        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11592        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11593            s.move_cursors_with(|map, head, _| {
11594                (
11595                    movement::previous_word_start(map, head),
11596                    SelectionGoal::None,
11597                )
11598            });
11599        })
11600    }
11601
11602    pub fn move_to_previous_subword_start(
11603        &mut self,
11604        _: &MoveToPreviousSubwordStart,
11605        window: &mut Window,
11606        cx: &mut Context<Self>,
11607    ) {
11608        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11609        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11610            s.move_cursors_with(|map, head, _| {
11611                (
11612                    movement::previous_subword_start(map, head),
11613                    SelectionGoal::None,
11614                )
11615            });
11616        })
11617    }
11618
11619    pub fn select_to_previous_word_start(
11620        &mut self,
11621        _: &SelectToPreviousWordStart,
11622        window: &mut Window,
11623        cx: &mut Context<Self>,
11624    ) {
11625        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11626        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11627            s.move_heads_with(|map, head, _| {
11628                (
11629                    movement::previous_word_start(map, head),
11630                    SelectionGoal::None,
11631                )
11632            });
11633        })
11634    }
11635
11636    pub fn select_to_previous_subword_start(
11637        &mut self,
11638        _: &SelectToPreviousSubwordStart,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641    ) {
11642        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.move_heads_with(|map, head, _| {
11645                (
11646                    movement::previous_subword_start(map, head),
11647                    SelectionGoal::None,
11648                )
11649            });
11650        })
11651    }
11652
11653    pub fn delete_to_previous_word_start(
11654        &mut self,
11655        action: &DeleteToPreviousWordStart,
11656        window: &mut Window,
11657        cx: &mut Context<Self>,
11658    ) {
11659        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11660        self.transact(window, cx, |this, window, cx| {
11661            this.select_autoclose_pair(window, cx);
11662            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11663                s.move_with(|map, selection| {
11664                    if selection.is_empty() {
11665                        let cursor = if action.ignore_newlines {
11666                            movement::previous_word_start(map, selection.head())
11667                        } else {
11668                            movement::previous_word_start_or_newline(map, selection.head())
11669                        };
11670                        selection.set_head(cursor, SelectionGoal::None);
11671                    }
11672                });
11673            });
11674            this.insert("", window, cx);
11675        });
11676    }
11677
11678    pub fn delete_to_previous_subword_start(
11679        &mut self,
11680        _: &DeleteToPreviousSubwordStart,
11681        window: &mut Window,
11682        cx: &mut Context<Self>,
11683    ) {
11684        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11685        self.transact(window, cx, |this, window, cx| {
11686            this.select_autoclose_pair(window, cx);
11687            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11688                s.move_with(|map, selection| {
11689                    if selection.is_empty() {
11690                        let cursor = movement::previous_subword_start(map, selection.head());
11691                        selection.set_head(cursor, SelectionGoal::None);
11692                    }
11693                });
11694            });
11695            this.insert("", window, cx);
11696        });
11697    }
11698
11699    pub fn move_to_next_word_end(
11700        &mut self,
11701        _: &MoveToNextWordEnd,
11702        window: &mut Window,
11703        cx: &mut Context<Self>,
11704    ) {
11705        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11706        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11707            s.move_cursors_with(|map, head, _| {
11708                (movement::next_word_end(map, head), SelectionGoal::None)
11709            });
11710        })
11711    }
11712
11713    pub fn move_to_next_subword_end(
11714        &mut self,
11715        _: &MoveToNextSubwordEnd,
11716        window: &mut Window,
11717        cx: &mut Context<Self>,
11718    ) {
11719        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11720        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11721            s.move_cursors_with(|map, head, _| {
11722                (movement::next_subword_end(map, head), SelectionGoal::None)
11723            });
11724        })
11725    }
11726
11727    pub fn select_to_next_word_end(
11728        &mut self,
11729        _: &SelectToNextWordEnd,
11730        window: &mut Window,
11731        cx: &mut Context<Self>,
11732    ) {
11733        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11734        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11735            s.move_heads_with(|map, head, _| {
11736                (movement::next_word_end(map, head), SelectionGoal::None)
11737            });
11738        })
11739    }
11740
11741    pub fn select_to_next_subword_end(
11742        &mut self,
11743        _: &SelectToNextSubwordEnd,
11744        window: &mut Window,
11745        cx: &mut Context<Self>,
11746    ) {
11747        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11748        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11749            s.move_heads_with(|map, head, _| {
11750                (movement::next_subword_end(map, head), SelectionGoal::None)
11751            });
11752        })
11753    }
11754
11755    pub fn delete_to_next_word_end(
11756        &mut self,
11757        action: &DeleteToNextWordEnd,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11762        self.transact(window, cx, |this, window, cx| {
11763            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11764                s.move_with(|map, selection| {
11765                    if selection.is_empty() {
11766                        let cursor = if action.ignore_newlines {
11767                            movement::next_word_end(map, selection.head())
11768                        } else {
11769                            movement::next_word_end_or_newline(map, selection.head())
11770                        };
11771                        selection.set_head(cursor, SelectionGoal::None);
11772                    }
11773                });
11774            });
11775            this.insert("", window, cx);
11776        });
11777    }
11778
11779    pub fn delete_to_next_subword_end(
11780        &mut self,
11781        _: &DeleteToNextSubwordEnd,
11782        window: &mut Window,
11783        cx: &mut Context<Self>,
11784    ) {
11785        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11786        self.transact(window, cx, |this, window, cx| {
11787            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11788                s.move_with(|map, selection| {
11789                    if selection.is_empty() {
11790                        let cursor = movement::next_subword_end(map, selection.head());
11791                        selection.set_head(cursor, SelectionGoal::None);
11792                    }
11793                });
11794            });
11795            this.insert("", window, cx);
11796        });
11797    }
11798
11799    pub fn move_to_beginning_of_line(
11800        &mut self,
11801        action: &MoveToBeginningOfLine,
11802        window: &mut Window,
11803        cx: &mut Context<Self>,
11804    ) {
11805        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11806        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11807            s.move_cursors_with(|map, head, _| {
11808                (
11809                    movement::indented_line_beginning(
11810                        map,
11811                        head,
11812                        action.stop_at_soft_wraps,
11813                        action.stop_at_indent,
11814                    ),
11815                    SelectionGoal::None,
11816                )
11817            });
11818        })
11819    }
11820
11821    pub fn select_to_beginning_of_line(
11822        &mut self,
11823        action: &SelectToBeginningOfLine,
11824        window: &mut Window,
11825        cx: &mut Context<Self>,
11826    ) {
11827        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11828        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11829            s.move_heads_with(|map, head, _| {
11830                (
11831                    movement::indented_line_beginning(
11832                        map,
11833                        head,
11834                        action.stop_at_soft_wraps,
11835                        action.stop_at_indent,
11836                    ),
11837                    SelectionGoal::None,
11838                )
11839            });
11840        });
11841    }
11842
11843    pub fn delete_to_beginning_of_line(
11844        &mut self,
11845        action: &DeleteToBeginningOfLine,
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.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11852                s.move_with(|_, selection| {
11853                    selection.reversed = true;
11854                });
11855            });
11856
11857            this.select_to_beginning_of_line(
11858                &SelectToBeginningOfLine {
11859                    stop_at_soft_wraps: false,
11860                    stop_at_indent: action.stop_at_indent,
11861                },
11862                window,
11863                cx,
11864            );
11865            this.backspace(&Backspace, window, cx);
11866        });
11867    }
11868
11869    pub fn move_to_end_of_line(
11870        &mut self,
11871        action: &MoveToEndOfLine,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874    ) {
11875        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11876        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11877            s.move_cursors_with(|map, head, _| {
11878                (
11879                    movement::line_end(map, head, action.stop_at_soft_wraps),
11880                    SelectionGoal::None,
11881                )
11882            });
11883        })
11884    }
11885
11886    pub fn select_to_end_of_line(
11887        &mut self,
11888        action: &SelectToEndOfLine,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11893        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11894            s.move_heads_with(|map, head, _| {
11895                (
11896                    movement::line_end(map, head, action.stop_at_soft_wraps),
11897                    SelectionGoal::None,
11898                )
11899            });
11900        })
11901    }
11902
11903    pub fn delete_to_end_of_line(
11904        &mut self,
11905        _: &DeleteToEndOfLine,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11910        self.transact(window, cx, |this, window, cx| {
11911            this.select_to_end_of_line(
11912                &SelectToEndOfLine {
11913                    stop_at_soft_wraps: false,
11914                },
11915                window,
11916                cx,
11917            );
11918            this.delete(&Delete, window, cx);
11919        });
11920    }
11921
11922    pub fn cut_to_end_of_line(
11923        &mut self,
11924        _: &CutToEndOfLine,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927    ) {
11928        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11929        self.transact(window, cx, |this, window, cx| {
11930            this.select_to_end_of_line(
11931                &SelectToEndOfLine {
11932                    stop_at_soft_wraps: false,
11933                },
11934                window,
11935                cx,
11936            );
11937            this.cut(&Cut, window, cx);
11938        });
11939    }
11940
11941    pub fn move_to_start_of_paragraph(
11942        &mut self,
11943        _: &MoveToStartOfParagraph,
11944        window: &mut Window,
11945        cx: &mut Context<Self>,
11946    ) {
11947        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11948            cx.propagate();
11949            return;
11950        }
11951        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11952        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11953            s.move_with(|map, selection| {
11954                selection.collapse_to(
11955                    movement::start_of_paragraph(map, selection.head(), 1),
11956                    SelectionGoal::None,
11957                )
11958            });
11959        })
11960    }
11961
11962    pub fn move_to_end_of_paragraph(
11963        &mut self,
11964        _: &MoveToEndOfParagraph,
11965        window: &mut Window,
11966        cx: &mut Context<Self>,
11967    ) {
11968        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11969            cx.propagate();
11970            return;
11971        }
11972        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11973        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11974            s.move_with(|map, selection| {
11975                selection.collapse_to(
11976                    movement::end_of_paragraph(map, selection.head(), 1),
11977                    SelectionGoal::None,
11978                )
11979            });
11980        })
11981    }
11982
11983    pub fn select_to_start_of_paragraph(
11984        &mut self,
11985        _: &SelectToStartOfParagraph,
11986        window: &mut Window,
11987        cx: &mut Context<Self>,
11988    ) {
11989        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11990            cx.propagate();
11991            return;
11992        }
11993        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11994        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11995            s.move_heads_with(|map, head, _| {
11996                (
11997                    movement::start_of_paragraph(map, head, 1),
11998                    SelectionGoal::None,
11999                )
12000            });
12001        })
12002    }
12003
12004    pub fn select_to_end_of_paragraph(
12005        &mut self,
12006        _: &SelectToEndOfParagraph,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12011            cx.propagate();
12012            return;
12013        }
12014        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12015        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12016            s.move_heads_with(|map, head, _| {
12017                (
12018                    movement::end_of_paragraph(map, head, 1),
12019                    SelectionGoal::None,
12020                )
12021            });
12022        })
12023    }
12024
12025    pub fn move_to_start_of_excerpt(
12026        &mut self,
12027        _: &MoveToStartOfExcerpt,
12028        window: &mut Window,
12029        cx: &mut Context<Self>,
12030    ) {
12031        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12032            cx.propagate();
12033            return;
12034        }
12035        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12036        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12037            s.move_with(|map, selection| {
12038                selection.collapse_to(
12039                    movement::start_of_excerpt(
12040                        map,
12041                        selection.head(),
12042                        workspace::searchable::Direction::Prev,
12043                    ),
12044                    SelectionGoal::None,
12045                )
12046            });
12047        })
12048    }
12049
12050    pub fn move_to_start_of_next_excerpt(
12051        &mut self,
12052        _: &MoveToStartOfNextExcerpt,
12053        window: &mut Window,
12054        cx: &mut Context<Self>,
12055    ) {
12056        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12057            cx.propagate();
12058            return;
12059        }
12060
12061        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12062            s.move_with(|map, selection| {
12063                selection.collapse_to(
12064                    movement::start_of_excerpt(
12065                        map,
12066                        selection.head(),
12067                        workspace::searchable::Direction::Next,
12068                    ),
12069                    SelectionGoal::None,
12070                )
12071            });
12072        })
12073    }
12074
12075    pub fn move_to_end_of_excerpt(
12076        &mut self,
12077        _: &MoveToEndOfExcerpt,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12082            cx.propagate();
12083            return;
12084        }
12085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12086        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12087            s.move_with(|map, selection| {
12088                selection.collapse_to(
12089                    movement::end_of_excerpt(
12090                        map,
12091                        selection.head(),
12092                        workspace::searchable::Direction::Next,
12093                    ),
12094                    SelectionGoal::None,
12095                )
12096            });
12097        })
12098    }
12099
12100    pub fn move_to_end_of_previous_excerpt(
12101        &mut self,
12102        _: &MoveToEndOfPreviousExcerpt,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12107            cx.propagate();
12108            return;
12109        }
12110        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12112            s.move_with(|map, selection| {
12113                selection.collapse_to(
12114                    movement::end_of_excerpt(
12115                        map,
12116                        selection.head(),
12117                        workspace::searchable::Direction::Prev,
12118                    ),
12119                    SelectionGoal::None,
12120                )
12121            });
12122        })
12123    }
12124
12125    pub fn select_to_start_of_excerpt(
12126        &mut self,
12127        _: &SelectToStartOfExcerpt,
12128        window: &mut Window,
12129        cx: &mut Context<Self>,
12130    ) {
12131        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12132            cx.propagate();
12133            return;
12134        }
12135        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12136        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12137            s.move_heads_with(|map, head, _| {
12138                (
12139                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12140                    SelectionGoal::None,
12141                )
12142            });
12143        })
12144    }
12145
12146    pub fn select_to_start_of_next_excerpt(
12147        &mut self,
12148        _: &SelectToStartOfNextExcerpt,
12149        window: &mut Window,
12150        cx: &mut Context<Self>,
12151    ) {
12152        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12153            cx.propagate();
12154            return;
12155        }
12156        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12157        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12158            s.move_heads_with(|map, head, _| {
12159                (
12160                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12161                    SelectionGoal::None,
12162                )
12163            });
12164        })
12165    }
12166
12167    pub fn select_to_end_of_excerpt(
12168        &mut self,
12169        _: &SelectToEndOfExcerpt,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) {
12173        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12174            cx.propagate();
12175            return;
12176        }
12177        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12178        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12179            s.move_heads_with(|map, head, _| {
12180                (
12181                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12182                    SelectionGoal::None,
12183                )
12184            });
12185        })
12186    }
12187
12188    pub fn select_to_end_of_previous_excerpt(
12189        &mut self,
12190        _: &SelectToEndOfPreviousExcerpt,
12191        window: &mut Window,
12192        cx: &mut Context<Self>,
12193    ) {
12194        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12195            cx.propagate();
12196            return;
12197        }
12198        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12199        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12200            s.move_heads_with(|map, head, _| {
12201                (
12202                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12203                    SelectionGoal::None,
12204                )
12205            });
12206        })
12207    }
12208
12209    pub fn move_to_beginning(
12210        &mut self,
12211        _: &MoveToBeginning,
12212        window: &mut Window,
12213        cx: &mut Context<Self>,
12214    ) {
12215        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12216            cx.propagate();
12217            return;
12218        }
12219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12220        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12221            s.select_ranges(vec![0..0]);
12222        });
12223    }
12224
12225    pub fn select_to_beginning(
12226        &mut self,
12227        _: &SelectToBeginning,
12228        window: &mut Window,
12229        cx: &mut Context<Self>,
12230    ) {
12231        let mut selection = self.selections.last::<Point>(cx);
12232        selection.set_head(Point::zero(), SelectionGoal::None);
12233        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12234        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12235            s.select(vec![selection]);
12236        });
12237    }
12238
12239    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12240        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12241            cx.propagate();
12242            return;
12243        }
12244        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12245        let cursor = self.buffer.read(cx).read(cx).len();
12246        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12247            s.select_ranges(vec![cursor..cursor])
12248        });
12249    }
12250
12251    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12252        self.nav_history = nav_history;
12253    }
12254
12255    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12256        self.nav_history.as_ref()
12257    }
12258
12259    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12260        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12261    }
12262
12263    fn push_to_nav_history(
12264        &mut self,
12265        cursor_anchor: Anchor,
12266        new_position: Option<Point>,
12267        is_deactivate: bool,
12268        cx: &mut Context<Self>,
12269    ) {
12270        if let Some(nav_history) = self.nav_history.as_mut() {
12271            let buffer = self.buffer.read(cx).read(cx);
12272            let cursor_position = cursor_anchor.to_point(&buffer);
12273            let scroll_state = self.scroll_manager.anchor();
12274            let scroll_top_row = scroll_state.top_row(&buffer);
12275            drop(buffer);
12276
12277            if let Some(new_position) = new_position {
12278                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12279                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12280                    return;
12281                }
12282            }
12283
12284            nav_history.push(
12285                Some(NavigationData {
12286                    cursor_anchor,
12287                    cursor_position,
12288                    scroll_anchor: scroll_state,
12289                    scroll_top_row,
12290                }),
12291                cx,
12292            );
12293            cx.emit(EditorEvent::PushedToNavHistory {
12294                anchor: cursor_anchor,
12295                is_deactivate,
12296            })
12297        }
12298    }
12299
12300    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12301        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12302        let buffer = self.buffer.read(cx).snapshot(cx);
12303        let mut selection = self.selections.first::<usize>(cx);
12304        selection.set_head(buffer.len(), SelectionGoal::None);
12305        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12306            s.select(vec![selection]);
12307        });
12308    }
12309
12310    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12311        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12312        let end = self.buffer.read(cx).read(cx).len();
12313        self.change_selections(None, window, cx, |s| {
12314            s.select_ranges(vec![0..end]);
12315        });
12316    }
12317
12318    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12319        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12320        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12321        let mut selections = self.selections.all::<Point>(cx);
12322        let max_point = display_map.buffer_snapshot.max_point();
12323        for selection in &mut selections {
12324            let rows = selection.spanned_rows(true, &display_map);
12325            selection.start = Point::new(rows.start.0, 0);
12326            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12327            selection.reversed = false;
12328        }
12329        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12330            s.select(selections);
12331        });
12332    }
12333
12334    pub fn split_selection_into_lines(
12335        &mut self,
12336        _: &SplitSelectionIntoLines,
12337        window: &mut Window,
12338        cx: &mut Context<Self>,
12339    ) {
12340        let selections = self
12341            .selections
12342            .all::<Point>(cx)
12343            .into_iter()
12344            .map(|selection| selection.start..selection.end)
12345            .collect::<Vec<_>>();
12346        self.unfold_ranges(&selections, true, true, cx);
12347
12348        let mut new_selection_ranges = Vec::new();
12349        {
12350            let buffer = self.buffer.read(cx).read(cx);
12351            for selection in selections {
12352                for row in selection.start.row..selection.end.row {
12353                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12354                    new_selection_ranges.push(cursor..cursor);
12355                }
12356
12357                let is_multiline_selection = selection.start.row != selection.end.row;
12358                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12359                // so this action feels more ergonomic when paired with other selection operations
12360                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12361                if !should_skip_last {
12362                    new_selection_ranges.push(selection.end..selection.end);
12363                }
12364            }
12365        }
12366        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12367            s.select_ranges(new_selection_ranges);
12368        });
12369    }
12370
12371    pub fn add_selection_above(
12372        &mut self,
12373        _: &AddSelectionAbove,
12374        window: &mut Window,
12375        cx: &mut Context<Self>,
12376    ) {
12377        self.add_selection(true, window, cx);
12378    }
12379
12380    pub fn add_selection_below(
12381        &mut self,
12382        _: &AddSelectionBelow,
12383        window: &mut Window,
12384        cx: &mut Context<Self>,
12385    ) {
12386        self.add_selection(false, window, cx);
12387    }
12388
12389    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12390        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12391
12392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12393        let mut selections = self.selections.all::<Point>(cx);
12394        let text_layout_details = self.text_layout_details(window);
12395        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12396            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12397            let range = oldest_selection.display_range(&display_map).sorted();
12398
12399            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12400            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12401            let positions = start_x.min(end_x)..start_x.max(end_x);
12402
12403            selections.clear();
12404            let mut stack = Vec::new();
12405            for row in range.start.row().0..=range.end.row().0 {
12406                if let Some(selection) = self.selections.build_columnar_selection(
12407                    &display_map,
12408                    DisplayRow(row),
12409                    &positions,
12410                    oldest_selection.reversed,
12411                    &text_layout_details,
12412                ) {
12413                    stack.push(selection.id);
12414                    selections.push(selection);
12415                }
12416            }
12417
12418            if above {
12419                stack.reverse();
12420            }
12421
12422            AddSelectionsState { above, stack }
12423        });
12424
12425        let last_added_selection = *state.stack.last().unwrap();
12426        let mut new_selections = Vec::new();
12427        if above == state.above {
12428            let end_row = if above {
12429                DisplayRow(0)
12430            } else {
12431                display_map.max_point().row()
12432            };
12433
12434            'outer: for selection in selections {
12435                if selection.id == last_added_selection {
12436                    let range = selection.display_range(&display_map).sorted();
12437                    debug_assert_eq!(range.start.row(), range.end.row());
12438                    let mut row = range.start.row();
12439                    let positions =
12440                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12441                            px(start)..px(end)
12442                        } else {
12443                            let start_x =
12444                                display_map.x_for_display_point(range.start, &text_layout_details);
12445                            let end_x =
12446                                display_map.x_for_display_point(range.end, &text_layout_details);
12447                            start_x.min(end_x)..start_x.max(end_x)
12448                        };
12449
12450                    while row != end_row {
12451                        if above {
12452                            row.0 -= 1;
12453                        } else {
12454                            row.0 += 1;
12455                        }
12456
12457                        if let Some(new_selection) = self.selections.build_columnar_selection(
12458                            &display_map,
12459                            row,
12460                            &positions,
12461                            selection.reversed,
12462                            &text_layout_details,
12463                        ) {
12464                            state.stack.push(new_selection.id);
12465                            if above {
12466                                new_selections.push(new_selection);
12467                                new_selections.push(selection);
12468                            } else {
12469                                new_selections.push(selection);
12470                                new_selections.push(new_selection);
12471                            }
12472
12473                            continue 'outer;
12474                        }
12475                    }
12476                }
12477
12478                new_selections.push(selection);
12479            }
12480        } else {
12481            new_selections = selections;
12482            new_selections.retain(|s| s.id != last_added_selection);
12483            state.stack.pop();
12484        }
12485
12486        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12487            s.select(new_selections);
12488        });
12489        if state.stack.len() > 1 {
12490            self.add_selections_state = Some(state);
12491        }
12492    }
12493
12494    fn select_match_ranges(
12495        &mut self,
12496        range: Range<usize>,
12497        reversed: bool,
12498        replace_newest: bool,
12499        auto_scroll: Option<Autoscroll>,
12500        window: &mut Window,
12501        cx: &mut Context<Editor>,
12502    ) {
12503        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12504        self.change_selections(auto_scroll, window, cx, |s| {
12505            if replace_newest {
12506                s.delete(s.newest_anchor().id);
12507            }
12508            if reversed {
12509                s.insert_range(range.end..range.start);
12510            } else {
12511                s.insert_range(range);
12512            }
12513        });
12514    }
12515
12516    pub fn select_next_match_internal(
12517        &mut self,
12518        display_map: &DisplaySnapshot,
12519        replace_newest: bool,
12520        autoscroll: Option<Autoscroll>,
12521        window: &mut Window,
12522        cx: &mut Context<Self>,
12523    ) -> Result<()> {
12524        let buffer = &display_map.buffer_snapshot;
12525        let mut selections = self.selections.all::<usize>(cx);
12526        if let Some(mut select_next_state) = self.select_next_state.take() {
12527            let query = &select_next_state.query;
12528            if !select_next_state.done {
12529                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12530                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12531                let mut next_selected_range = None;
12532
12533                let bytes_after_last_selection =
12534                    buffer.bytes_in_range(last_selection.end..buffer.len());
12535                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12536                let query_matches = query
12537                    .stream_find_iter(bytes_after_last_selection)
12538                    .map(|result| (last_selection.end, result))
12539                    .chain(
12540                        query
12541                            .stream_find_iter(bytes_before_first_selection)
12542                            .map(|result| (0, result)),
12543                    );
12544
12545                for (start_offset, query_match) in query_matches {
12546                    let query_match = query_match.unwrap(); // can only fail due to I/O
12547                    let offset_range =
12548                        start_offset + query_match.start()..start_offset + query_match.end();
12549                    let display_range = offset_range.start.to_display_point(display_map)
12550                        ..offset_range.end.to_display_point(display_map);
12551
12552                    if !select_next_state.wordwise
12553                        || (!movement::is_inside_word(display_map, display_range.start)
12554                            && !movement::is_inside_word(display_map, display_range.end))
12555                    {
12556                        // TODO: This is n^2, because we might check all the selections
12557                        if !selections
12558                            .iter()
12559                            .any(|selection| selection.range().overlaps(&offset_range))
12560                        {
12561                            next_selected_range = Some(offset_range);
12562                            break;
12563                        }
12564                    }
12565                }
12566
12567                if let Some(next_selected_range) = next_selected_range {
12568                    self.select_match_ranges(
12569                        next_selected_range,
12570                        last_selection.reversed,
12571                        replace_newest,
12572                        autoscroll,
12573                        window,
12574                        cx,
12575                    );
12576                } else {
12577                    select_next_state.done = true;
12578                }
12579            }
12580
12581            self.select_next_state = Some(select_next_state);
12582        } else {
12583            let mut only_carets = true;
12584            let mut same_text_selected = true;
12585            let mut selected_text = None;
12586
12587            let mut selections_iter = selections.iter().peekable();
12588            while let Some(selection) = selections_iter.next() {
12589                if selection.start != selection.end {
12590                    only_carets = false;
12591                }
12592
12593                if same_text_selected {
12594                    if selected_text.is_none() {
12595                        selected_text =
12596                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12597                    }
12598
12599                    if let Some(next_selection) = selections_iter.peek() {
12600                        if next_selection.range().len() == selection.range().len() {
12601                            let next_selected_text = buffer
12602                                .text_for_range(next_selection.range())
12603                                .collect::<String>();
12604                            if Some(next_selected_text) != selected_text {
12605                                same_text_selected = false;
12606                                selected_text = None;
12607                            }
12608                        } else {
12609                            same_text_selected = false;
12610                            selected_text = None;
12611                        }
12612                    }
12613                }
12614            }
12615
12616            if only_carets {
12617                for selection in &mut selections {
12618                    let word_range = movement::surrounding_word(
12619                        display_map,
12620                        selection.start.to_display_point(display_map),
12621                    );
12622                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12623                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12624                    selection.goal = SelectionGoal::None;
12625                    selection.reversed = false;
12626                    self.select_match_ranges(
12627                        selection.start..selection.end,
12628                        selection.reversed,
12629                        replace_newest,
12630                        autoscroll,
12631                        window,
12632                        cx,
12633                    );
12634                }
12635
12636                if selections.len() == 1 {
12637                    let selection = selections
12638                        .last()
12639                        .expect("ensured that there's only one selection");
12640                    let query = buffer
12641                        .text_for_range(selection.start..selection.end)
12642                        .collect::<String>();
12643                    let is_empty = query.is_empty();
12644                    let select_state = SelectNextState {
12645                        query: AhoCorasick::new(&[query])?,
12646                        wordwise: true,
12647                        done: is_empty,
12648                    };
12649                    self.select_next_state = Some(select_state);
12650                } else {
12651                    self.select_next_state = None;
12652                }
12653            } else if let Some(selected_text) = selected_text {
12654                self.select_next_state = Some(SelectNextState {
12655                    query: AhoCorasick::new(&[selected_text])?,
12656                    wordwise: false,
12657                    done: false,
12658                });
12659                self.select_next_match_internal(
12660                    display_map,
12661                    replace_newest,
12662                    autoscroll,
12663                    window,
12664                    cx,
12665                )?;
12666            }
12667        }
12668        Ok(())
12669    }
12670
12671    pub fn select_all_matches(
12672        &mut self,
12673        _action: &SelectAllMatches,
12674        window: &mut Window,
12675        cx: &mut Context<Self>,
12676    ) -> Result<()> {
12677        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12678
12679        self.push_to_selection_history();
12680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12681
12682        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12683        let Some(select_next_state) = self.select_next_state.as_mut() else {
12684            return Ok(());
12685        };
12686        if select_next_state.done {
12687            return Ok(());
12688        }
12689
12690        let mut new_selections = Vec::new();
12691
12692        let reversed = self.selections.oldest::<usize>(cx).reversed;
12693        let buffer = &display_map.buffer_snapshot;
12694        let query_matches = select_next_state
12695            .query
12696            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12697
12698        for query_match in query_matches.into_iter() {
12699            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12700            let offset_range = if reversed {
12701                query_match.end()..query_match.start()
12702            } else {
12703                query_match.start()..query_match.end()
12704            };
12705            let display_range = offset_range.start.to_display_point(&display_map)
12706                ..offset_range.end.to_display_point(&display_map);
12707
12708            if !select_next_state.wordwise
12709                || (!movement::is_inside_word(&display_map, display_range.start)
12710                    && !movement::is_inside_word(&display_map, display_range.end))
12711            {
12712                new_selections.push(offset_range.start..offset_range.end);
12713            }
12714        }
12715
12716        select_next_state.done = true;
12717        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12718        self.change_selections(None, window, cx, |selections| {
12719            selections.select_ranges(new_selections)
12720        });
12721
12722        Ok(())
12723    }
12724
12725    pub fn select_next(
12726        &mut self,
12727        action: &SelectNext,
12728        window: &mut Window,
12729        cx: &mut Context<Self>,
12730    ) -> Result<()> {
12731        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12732        self.push_to_selection_history();
12733        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12734        self.select_next_match_internal(
12735            &display_map,
12736            action.replace_newest,
12737            Some(Autoscroll::newest()),
12738            window,
12739            cx,
12740        )?;
12741        Ok(())
12742    }
12743
12744    pub fn select_previous(
12745        &mut self,
12746        action: &SelectPrevious,
12747        window: &mut Window,
12748        cx: &mut Context<Self>,
12749    ) -> Result<()> {
12750        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12751        self.push_to_selection_history();
12752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12753        let buffer = &display_map.buffer_snapshot;
12754        let mut selections = self.selections.all::<usize>(cx);
12755        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12756            let query = &select_prev_state.query;
12757            if !select_prev_state.done {
12758                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12759                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12760                let mut next_selected_range = None;
12761                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12762                let bytes_before_last_selection =
12763                    buffer.reversed_bytes_in_range(0..last_selection.start);
12764                let bytes_after_first_selection =
12765                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12766                let query_matches = query
12767                    .stream_find_iter(bytes_before_last_selection)
12768                    .map(|result| (last_selection.start, result))
12769                    .chain(
12770                        query
12771                            .stream_find_iter(bytes_after_first_selection)
12772                            .map(|result| (buffer.len(), result)),
12773                    );
12774                for (end_offset, query_match) in query_matches {
12775                    let query_match = query_match.unwrap(); // can only fail due to I/O
12776                    let offset_range =
12777                        end_offset - query_match.end()..end_offset - query_match.start();
12778                    let display_range = offset_range.start.to_display_point(&display_map)
12779                        ..offset_range.end.to_display_point(&display_map);
12780
12781                    if !select_prev_state.wordwise
12782                        || (!movement::is_inside_word(&display_map, display_range.start)
12783                            && !movement::is_inside_word(&display_map, display_range.end))
12784                    {
12785                        next_selected_range = Some(offset_range);
12786                        break;
12787                    }
12788                }
12789
12790                if let Some(next_selected_range) = next_selected_range {
12791                    self.select_match_ranges(
12792                        next_selected_range,
12793                        last_selection.reversed,
12794                        action.replace_newest,
12795                        Some(Autoscroll::newest()),
12796                        window,
12797                        cx,
12798                    );
12799                } else {
12800                    select_prev_state.done = true;
12801                }
12802            }
12803
12804            self.select_prev_state = Some(select_prev_state);
12805        } else {
12806            let mut only_carets = true;
12807            let mut same_text_selected = true;
12808            let mut selected_text = None;
12809
12810            let mut selections_iter = selections.iter().peekable();
12811            while let Some(selection) = selections_iter.next() {
12812                if selection.start != selection.end {
12813                    only_carets = false;
12814                }
12815
12816                if same_text_selected {
12817                    if selected_text.is_none() {
12818                        selected_text =
12819                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12820                    }
12821
12822                    if let Some(next_selection) = selections_iter.peek() {
12823                        if next_selection.range().len() == selection.range().len() {
12824                            let next_selected_text = buffer
12825                                .text_for_range(next_selection.range())
12826                                .collect::<String>();
12827                            if Some(next_selected_text) != selected_text {
12828                                same_text_selected = false;
12829                                selected_text = None;
12830                            }
12831                        } else {
12832                            same_text_selected = false;
12833                            selected_text = None;
12834                        }
12835                    }
12836                }
12837            }
12838
12839            if only_carets {
12840                for selection in &mut selections {
12841                    let word_range = movement::surrounding_word(
12842                        &display_map,
12843                        selection.start.to_display_point(&display_map),
12844                    );
12845                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12846                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12847                    selection.goal = SelectionGoal::None;
12848                    selection.reversed = false;
12849                    self.select_match_ranges(
12850                        selection.start..selection.end,
12851                        selection.reversed,
12852                        action.replace_newest,
12853                        Some(Autoscroll::newest()),
12854                        window,
12855                        cx,
12856                    );
12857                }
12858                if selections.len() == 1 {
12859                    let selection = selections
12860                        .last()
12861                        .expect("ensured that there's only one selection");
12862                    let query = buffer
12863                        .text_for_range(selection.start..selection.end)
12864                        .collect::<String>();
12865                    let is_empty = query.is_empty();
12866                    let select_state = SelectNextState {
12867                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12868                        wordwise: true,
12869                        done: is_empty,
12870                    };
12871                    self.select_prev_state = Some(select_state);
12872                } else {
12873                    self.select_prev_state = None;
12874                }
12875            } else if let Some(selected_text) = selected_text {
12876                self.select_prev_state = Some(SelectNextState {
12877                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12878                    wordwise: false,
12879                    done: false,
12880                });
12881                self.select_previous(action, window, cx)?;
12882            }
12883        }
12884        Ok(())
12885    }
12886
12887    pub fn find_next_match(
12888        &mut self,
12889        _: &FindNextMatch,
12890        window: &mut Window,
12891        cx: &mut Context<Self>,
12892    ) -> Result<()> {
12893        let selections = self.selections.disjoint_anchors();
12894        match selections.first() {
12895            Some(first) if selections.len() >= 2 => {
12896                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12897                    s.select_ranges([first.range()]);
12898                });
12899            }
12900            _ => self.select_next(
12901                &SelectNext {
12902                    replace_newest: true,
12903                },
12904                window,
12905                cx,
12906            )?,
12907        }
12908        Ok(())
12909    }
12910
12911    pub fn find_previous_match(
12912        &mut self,
12913        _: &FindPreviousMatch,
12914        window: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) -> Result<()> {
12917        let selections = self.selections.disjoint_anchors();
12918        match selections.last() {
12919            Some(last) if selections.len() >= 2 => {
12920                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12921                    s.select_ranges([last.range()]);
12922                });
12923            }
12924            _ => self.select_previous(
12925                &SelectPrevious {
12926                    replace_newest: true,
12927                },
12928                window,
12929                cx,
12930            )?,
12931        }
12932        Ok(())
12933    }
12934
12935    pub fn toggle_comments(
12936        &mut self,
12937        action: &ToggleComments,
12938        window: &mut Window,
12939        cx: &mut Context<Self>,
12940    ) {
12941        if self.read_only(cx) {
12942            return;
12943        }
12944        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12945        let text_layout_details = &self.text_layout_details(window);
12946        self.transact(window, cx, |this, window, cx| {
12947            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12948            let mut edits = Vec::new();
12949            let mut selection_edit_ranges = Vec::new();
12950            let mut last_toggled_row = None;
12951            let snapshot = this.buffer.read(cx).read(cx);
12952            let empty_str: Arc<str> = Arc::default();
12953            let mut suffixes_inserted = Vec::new();
12954            let ignore_indent = action.ignore_indent;
12955
12956            fn comment_prefix_range(
12957                snapshot: &MultiBufferSnapshot,
12958                row: MultiBufferRow,
12959                comment_prefix: &str,
12960                comment_prefix_whitespace: &str,
12961                ignore_indent: bool,
12962            ) -> Range<Point> {
12963                let indent_size = if ignore_indent {
12964                    0
12965                } else {
12966                    snapshot.indent_size_for_line(row).len
12967                };
12968
12969                let start = Point::new(row.0, indent_size);
12970
12971                let mut line_bytes = snapshot
12972                    .bytes_in_range(start..snapshot.max_point())
12973                    .flatten()
12974                    .copied();
12975
12976                // If this line currently begins with the line comment prefix, then record
12977                // the range containing the prefix.
12978                if line_bytes
12979                    .by_ref()
12980                    .take(comment_prefix.len())
12981                    .eq(comment_prefix.bytes())
12982                {
12983                    // Include any whitespace that matches the comment prefix.
12984                    let matching_whitespace_len = line_bytes
12985                        .zip(comment_prefix_whitespace.bytes())
12986                        .take_while(|(a, b)| a == b)
12987                        .count() as u32;
12988                    let end = Point::new(
12989                        start.row,
12990                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12991                    );
12992                    start..end
12993                } else {
12994                    start..start
12995                }
12996            }
12997
12998            fn comment_suffix_range(
12999                snapshot: &MultiBufferSnapshot,
13000                row: MultiBufferRow,
13001                comment_suffix: &str,
13002                comment_suffix_has_leading_space: bool,
13003            ) -> Range<Point> {
13004                let end = Point::new(row.0, snapshot.line_len(row));
13005                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13006
13007                let mut line_end_bytes = snapshot
13008                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13009                    .flatten()
13010                    .copied();
13011
13012                let leading_space_len = if suffix_start_column > 0
13013                    && line_end_bytes.next() == Some(b' ')
13014                    && comment_suffix_has_leading_space
13015                {
13016                    1
13017                } else {
13018                    0
13019                };
13020
13021                // If this line currently begins with the line comment prefix, then record
13022                // the range containing the prefix.
13023                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13024                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13025                    start..end
13026                } else {
13027                    end..end
13028                }
13029            }
13030
13031            // TODO: Handle selections that cross excerpts
13032            for selection in &mut selections {
13033                let start_column = snapshot
13034                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13035                    .len;
13036                let language = if let Some(language) =
13037                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13038                {
13039                    language
13040                } else {
13041                    continue;
13042                };
13043
13044                selection_edit_ranges.clear();
13045
13046                // If multiple selections contain a given row, avoid processing that
13047                // row more than once.
13048                let mut start_row = MultiBufferRow(selection.start.row);
13049                if last_toggled_row == Some(start_row) {
13050                    start_row = start_row.next_row();
13051                }
13052                let end_row =
13053                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13054                        MultiBufferRow(selection.end.row - 1)
13055                    } else {
13056                        MultiBufferRow(selection.end.row)
13057                    };
13058                last_toggled_row = Some(end_row);
13059
13060                if start_row > end_row {
13061                    continue;
13062                }
13063
13064                // If the language has line comments, toggle those.
13065                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13066
13067                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13068                if ignore_indent {
13069                    full_comment_prefixes = full_comment_prefixes
13070                        .into_iter()
13071                        .map(|s| Arc::from(s.trim_end()))
13072                        .collect();
13073                }
13074
13075                if !full_comment_prefixes.is_empty() {
13076                    let first_prefix = full_comment_prefixes
13077                        .first()
13078                        .expect("prefixes is non-empty");
13079                    let prefix_trimmed_lengths = full_comment_prefixes
13080                        .iter()
13081                        .map(|p| p.trim_end_matches(' ').len())
13082                        .collect::<SmallVec<[usize; 4]>>();
13083
13084                    let mut all_selection_lines_are_comments = true;
13085
13086                    for row in start_row.0..=end_row.0 {
13087                        let row = MultiBufferRow(row);
13088                        if start_row < end_row && snapshot.is_line_blank(row) {
13089                            continue;
13090                        }
13091
13092                        let prefix_range = full_comment_prefixes
13093                            .iter()
13094                            .zip(prefix_trimmed_lengths.iter().copied())
13095                            .map(|(prefix, trimmed_prefix_len)| {
13096                                comment_prefix_range(
13097                                    snapshot.deref(),
13098                                    row,
13099                                    &prefix[..trimmed_prefix_len],
13100                                    &prefix[trimmed_prefix_len..],
13101                                    ignore_indent,
13102                                )
13103                            })
13104                            .max_by_key(|range| range.end.column - range.start.column)
13105                            .expect("prefixes is non-empty");
13106
13107                        if prefix_range.is_empty() {
13108                            all_selection_lines_are_comments = false;
13109                        }
13110
13111                        selection_edit_ranges.push(prefix_range);
13112                    }
13113
13114                    if all_selection_lines_are_comments {
13115                        edits.extend(
13116                            selection_edit_ranges
13117                                .iter()
13118                                .cloned()
13119                                .map(|range| (range, empty_str.clone())),
13120                        );
13121                    } else {
13122                        let min_column = selection_edit_ranges
13123                            .iter()
13124                            .map(|range| range.start.column)
13125                            .min()
13126                            .unwrap_or(0);
13127                        edits.extend(selection_edit_ranges.iter().map(|range| {
13128                            let position = Point::new(range.start.row, min_column);
13129                            (position..position, first_prefix.clone())
13130                        }));
13131                    }
13132                } else if let Some((full_comment_prefix, comment_suffix)) =
13133                    language.block_comment_delimiters()
13134                {
13135                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13136                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13137                    let prefix_range = comment_prefix_range(
13138                        snapshot.deref(),
13139                        start_row,
13140                        comment_prefix,
13141                        comment_prefix_whitespace,
13142                        ignore_indent,
13143                    );
13144                    let suffix_range = comment_suffix_range(
13145                        snapshot.deref(),
13146                        end_row,
13147                        comment_suffix.trim_start_matches(' '),
13148                        comment_suffix.starts_with(' '),
13149                    );
13150
13151                    if prefix_range.is_empty() || suffix_range.is_empty() {
13152                        edits.push((
13153                            prefix_range.start..prefix_range.start,
13154                            full_comment_prefix.clone(),
13155                        ));
13156                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13157                        suffixes_inserted.push((end_row, comment_suffix.len()));
13158                    } else {
13159                        edits.push((prefix_range, empty_str.clone()));
13160                        edits.push((suffix_range, empty_str.clone()));
13161                    }
13162                } else {
13163                    continue;
13164                }
13165            }
13166
13167            drop(snapshot);
13168            this.buffer.update(cx, |buffer, cx| {
13169                buffer.edit(edits, None, cx);
13170            });
13171
13172            // Adjust selections so that they end before any comment suffixes that
13173            // were inserted.
13174            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13175            let mut selections = this.selections.all::<Point>(cx);
13176            let snapshot = this.buffer.read(cx).read(cx);
13177            for selection in &mut selections {
13178                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13179                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13180                        Ordering::Less => {
13181                            suffixes_inserted.next();
13182                            continue;
13183                        }
13184                        Ordering::Greater => break,
13185                        Ordering::Equal => {
13186                            if selection.end.column == snapshot.line_len(row) {
13187                                if selection.is_empty() {
13188                                    selection.start.column -= suffix_len as u32;
13189                                }
13190                                selection.end.column -= suffix_len as u32;
13191                            }
13192                            break;
13193                        }
13194                    }
13195                }
13196            }
13197
13198            drop(snapshot);
13199            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13200                s.select(selections)
13201            });
13202
13203            let selections = this.selections.all::<Point>(cx);
13204            let selections_on_single_row = selections.windows(2).all(|selections| {
13205                selections[0].start.row == selections[1].start.row
13206                    && selections[0].end.row == selections[1].end.row
13207                    && selections[0].start.row == selections[0].end.row
13208            });
13209            let selections_selecting = selections
13210                .iter()
13211                .any(|selection| selection.start != selection.end);
13212            let advance_downwards = action.advance_downwards
13213                && selections_on_single_row
13214                && !selections_selecting
13215                && !matches!(this.mode, EditorMode::SingleLine { .. });
13216
13217            if advance_downwards {
13218                let snapshot = this.buffer.read(cx).snapshot(cx);
13219
13220                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13221                    s.move_cursors_with(|display_snapshot, display_point, _| {
13222                        let mut point = display_point.to_point(display_snapshot);
13223                        point.row += 1;
13224                        point = snapshot.clip_point(point, Bias::Left);
13225                        let display_point = point.to_display_point(display_snapshot);
13226                        let goal = SelectionGoal::HorizontalPosition(
13227                            display_snapshot
13228                                .x_for_display_point(display_point, text_layout_details)
13229                                .into(),
13230                        );
13231                        (display_point, goal)
13232                    })
13233                });
13234            }
13235        });
13236    }
13237
13238    pub fn select_enclosing_symbol(
13239        &mut self,
13240        _: &SelectEnclosingSymbol,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13245
13246        let buffer = self.buffer.read(cx).snapshot(cx);
13247        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13248
13249        fn update_selection(
13250            selection: &Selection<usize>,
13251            buffer_snap: &MultiBufferSnapshot,
13252        ) -> Option<Selection<usize>> {
13253            let cursor = selection.head();
13254            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13255            for symbol in symbols.iter().rev() {
13256                let start = symbol.range.start.to_offset(buffer_snap);
13257                let end = symbol.range.end.to_offset(buffer_snap);
13258                let new_range = start..end;
13259                if start < selection.start || end > selection.end {
13260                    return Some(Selection {
13261                        id: selection.id,
13262                        start: new_range.start,
13263                        end: new_range.end,
13264                        goal: SelectionGoal::None,
13265                        reversed: selection.reversed,
13266                    });
13267                }
13268            }
13269            None
13270        }
13271
13272        let mut selected_larger_symbol = false;
13273        let new_selections = old_selections
13274            .iter()
13275            .map(|selection| match update_selection(selection, &buffer) {
13276                Some(new_selection) => {
13277                    if new_selection.range() != selection.range() {
13278                        selected_larger_symbol = true;
13279                    }
13280                    new_selection
13281                }
13282                None => selection.clone(),
13283            })
13284            .collect::<Vec<_>>();
13285
13286        if selected_larger_symbol {
13287            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13288                s.select(new_selections);
13289            });
13290        }
13291    }
13292
13293    pub fn select_larger_syntax_node(
13294        &mut self,
13295        _: &SelectLargerSyntaxNode,
13296        window: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        let Some(visible_row_count) = self.visible_row_count() else {
13300            return;
13301        };
13302        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13303        if old_selections.is_empty() {
13304            return;
13305        }
13306
13307        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13308
13309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13310        let buffer = self.buffer.read(cx).snapshot(cx);
13311
13312        let mut selected_larger_node = false;
13313        let mut new_selections = old_selections
13314            .iter()
13315            .map(|selection| {
13316                let old_range = selection.start..selection.end;
13317
13318                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13319                    // manually select word at selection
13320                    if ["string_content", "inline"].contains(&node.kind()) {
13321                        let word_range = {
13322                            let display_point = buffer
13323                                .offset_to_point(old_range.start)
13324                                .to_display_point(&display_map);
13325                            let Range { start, end } =
13326                                movement::surrounding_word(&display_map, display_point);
13327                            start.to_point(&display_map).to_offset(&buffer)
13328                                ..end.to_point(&display_map).to_offset(&buffer)
13329                        };
13330                        // ignore if word is already selected
13331                        if !word_range.is_empty() && old_range != word_range {
13332                            let last_word_range = {
13333                                let display_point = buffer
13334                                    .offset_to_point(old_range.end)
13335                                    .to_display_point(&display_map);
13336                                let Range { start, end } =
13337                                    movement::surrounding_word(&display_map, display_point);
13338                                start.to_point(&display_map).to_offset(&buffer)
13339                                    ..end.to_point(&display_map).to_offset(&buffer)
13340                            };
13341                            // only select word if start and end point belongs to same word
13342                            if word_range == last_word_range {
13343                                selected_larger_node = true;
13344                                return Selection {
13345                                    id: selection.id,
13346                                    start: word_range.start,
13347                                    end: word_range.end,
13348                                    goal: SelectionGoal::None,
13349                                    reversed: selection.reversed,
13350                                };
13351                            }
13352                        }
13353                    }
13354                }
13355
13356                let mut new_range = old_range.clone();
13357                while let Some((_node, containing_range)) =
13358                    buffer.syntax_ancestor(new_range.clone())
13359                {
13360                    new_range = match containing_range {
13361                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13362                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13363                    };
13364                    if !display_map.intersects_fold(new_range.start)
13365                        && !display_map.intersects_fold(new_range.end)
13366                    {
13367                        break;
13368                    }
13369                }
13370
13371                selected_larger_node |= new_range != old_range;
13372                Selection {
13373                    id: selection.id,
13374                    start: new_range.start,
13375                    end: new_range.end,
13376                    goal: SelectionGoal::None,
13377                    reversed: selection.reversed,
13378                }
13379            })
13380            .collect::<Vec<_>>();
13381
13382        if !selected_larger_node {
13383            return; // don't put this call in the history
13384        }
13385
13386        // scroll based on transformation done to the last selection created by the user
13387        let (last_old, last_new) = old_selections
13388            .last()
13389            .zip(new_selections.last().cloned())
13390            .expect("old_selections isn't empty");
13391
13392        // revert selection
13393        let is_selection_reversed = {
13394            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13395            new_selections.last_mut().expect("checked above").reversed =
13396                should_newest_selection_be_reversed;
13397            should_newest_selection_be_reversed
13398        };
13399
13400        if selected_larger_node {
13401            self.select_syntax_node_history.disable_clearing = true;
13402            self.change_selections(None, window, cx, |s| {
13403                s.select(new_selections.clone());
13404            });
13405            self.select_syntax_node_history.disable_clearing = false;
13406        }
13407
13408        let start_row = last_new.start.to_display_point(&display_map).row().0;
13409        let end_row = last_new.end.to_display_point(&display_map).row().0;
13410        let selection_height = end_row - start_row + 1;
13411        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13412
13413        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13414        let scroll_behavior = if fits_on_the_screen {
13415            self.request_autoscroll(Autoscroll::fit(), cx);
13416            SelectSyntaxNodeScrollBehavior::FitSelection
13417        } else if is_selection_reversed {
13418            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13419            SelectSyntaxNodeScrollBehavior::CursorTop
13420        } else {
13421            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13422            SelectSyntaxNodeScrollBehavior::CursorBottom
13423        };
13424
13425        self.select_syntax_node_history.push((
13426            old_selections,
13427            scroll_behavior,
13428            is_selection_reversed,
13429        ));
13430    }
13431
13432    pub fn select_smaller_syntax_node(
13433        &mut self,
13434        _: &SelectSmallerSyntaxNode,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) {
13438        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13439
13440        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13441            self.select_syntax_node_history.pop()
13442        {
13443            if let Some(selection) = selections.last_mut() {
13444                selection.reversed = is_selection_reversed;
13445            }
13446
13447            self.select_syntax_node_history.disable_clearing = true;
13448            self.change_selections(None, window, cx, |s| {
13449                s.select(selections.to_vec());
13450            });
13451            self.select_syntax_node_history.disable_clearing = false;
13452
13453            match scroll_behavior {
13454                SelectSyntaxNodeScrollBehavior::CursorTop => {
13455                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13456                }
13457                SelectSyntaxNodeScrollBehavior::FitSelection => {
13458                    self.request_autoscroll(Autoscroll::fit(), cx);
13459                }
13460                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13461                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13462                }
13463            }
13464        }
13465    }
13466
13467    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13468        if !EditorSettings::get_global(cx).gutter.runnables {
13469            self.clear_tasks();
13470            return Task::ready(());
13471        }
13472        let project = self.project.as_ref().map(Entity::downgrade);
13473        let task_sources = self.lsp_task_sources(cx);
13474        cx.spawn_in(window, async move |editor, cx| {
13475            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13476            let Some(project) = project.and_then(|p| p.upgrade()) else {
13477                return;
13478            };
13479            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13480                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13481            }) else {
13482                return;
13483            };
13484
13485            let hide_runnables = project
13486                .update(cx, |project, cx| {
13487                    // Do not display any test indicators in non-dev server remote projects.
13488                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13489                })
13490                .unwrap_or(true);
13491            if hide_runnables {
13492                return;
13493            }
13494            let new_rows =
13495                cx.background_spawn({
13496                    let snapshot = display_snapshot.clone();
13497                    async move {
13498                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13499                    }
13500                })
13501                    .await;
13502            let Ok(lsp_tasks) =
13503                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13504            else {
13505                return;
13506            };
13507            let lsp_tasks = lsp_tasks.await;
13508
13509            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13510                lsp_tasks
13511                    .into_iter()
13512                    .flat_map(|(kind, tasks)| {
13513                        tasks.into_iter().filter_map(move |(location, task)| {
13514                            Some((kind.clone(), location?, task))
13515                        })
13516                    })
13517                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13518                        let buffer = location.target.buffer;
13519                        let buffer_snapshot = buffer.read(cx).snapshot();
13520                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13521                            |(excerpt_id, snapshot, _)| {
13522                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13523                                    display_snapshot
13524                                        .buffer_snapshot
13525                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13526                                } else {
13527                                    None
13528                                }
13529                            },
13530                        );
13531                        if let Some(offset) = offset {
13532                            let task_buffer_range =
13533                                location.target.range.to_point(&buffer_snapshot);
13534                            let context_buffer_range =
13535                                task_buffer_range.to_offset(&buffer_snapshot);
13536                            let context_range = BufferOffset(context_buffer_range.start)
13537                                ..BufferOffset(context_buffer_range.end);
13538
13539                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13540                                .or_insert_with(|| RunnableTasks {
13541                                    templates: Vec::new(),
13542                                    offset,
13543                                    column: task_buffer_range.start.column,
13544                                    extra_variables: HashMap::default(),
13545                                    context_range,
13546                                })
13547                                .templates
13548                                .push((kind, task.original_task().clone()));
13549                        }
13550
13551                        acc
13552                    })
13553            }) else {
13554                return;
13555            };
13556
13557            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13558            editor
13559                .update(cx, |editor, _| {
13560                    editor.clear_tasks();
13561                    for (key, mut value) in rows {
13562                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13563                            value.templates.extend(lsp_tasks.templates);
13564                        }
13565
13566                        editor.insert_tasks(key, value);
13567                    }
13568                    for (key, value) in lsp_tasks_by_rows {
13569                        editor.insert_tasks(key, value);
13570                    }
13571                })
13572                .ok();
13573        })
13574    }
13575    fn fetch_runnable_ranges(
13576        snapshot: &DisplaySnapshot,
13577        range: Range<Anchor>,
13578    ) -> Vec<language::RunnableRange> {
13579        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13580    }
13581
13582    fn runnable_rows(
13583        project: Entity<Project>,
13584        snapshot: DisplaySnapshot,
13585        runnable_ranges: Vec<RunnableRange>,
13586        mut cx: AsyncWindowContext,
13587    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13588        runnable_ranges
13589            .into_iter()
13590            .filter_map(|mut runnable| {
13591                let tasks = cx
13592                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13593                    .ok()?;
13594                if tasks.is_empty() {
13595                    return None;
13596                }
13597
13598                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13599
13600                let row = snapshot
13601                    .buffer_snapshot
13602                    .buffer_line_for_row(MultiBufferRow(point.row))?
13603                    .1
13604                    .start
13605                    .row;
13606
13607                let context_range =
13608                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13609                Some((
13610                    (runnable.buffer_id, row),
13611                    RunnableTasks {
13612                        templates: tasks,
13613                        offset: snapshot
13614                            .buffer_snapshot
13615                            .anchor_before(runnable.run_range.start),
13616                        context_range,
13617                        column: point.column,
13618                        extra_variables: runnable.extra_captures,
13619                    },
13620                ))
13621            })
13622            .collect()
13623    }
13624
13625    fn templates_with_tags(
13626        project: &Entity<Project>,
13627        runnable: &mut Runnable,
13628        cx: &mut App,
13629    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13630        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13631            let (worktree_id, file) = project
13632                .buffer_for_id(runnable.buffer, cx)
13633                .and_then(|buffer| buffer.read(cx).file())
13634                .map(|file| (file.worktree_id(cx), file.clone()))
13635                .unzip();
13636
13637            (
13638                project.task_store().read(cx).task_inventory().cloned(),
13639                worktree_id,
13640                file,
13641            )
13642        });
13643
13644        let mut templates_with_tags = mem::take(&mut runnable.tags)
13645            .into_iter()
13646            .flat_map(|RunnableTag(tag)| {
13647                inventory
13648                    .as_ref()
13649                    .into_iter()
13650                    .flat_map(|inventory| {
13651                        inventory.read(cx).list_tasks(
13652                            file.clone(),
13653                            Some(runnable.language.clone()),
13654                            worktree_id,
13655                            cx,
13656                        )
13657                    })
13658                    .filter(move |(_, template)| {
13659                        template.tags.iter().any(|source_tag| source_tag == &tag)
13660                    })
13661            })
13662            .sorted_by_key(|(kind, _)| kind.to_owned())
13663            .collect::<Vec<_>>();
13664        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13665            // Strongest source wins; if we have worktree tag binding, prefer that to
13666            // global and language bindings;
13667            // if we have a global binding, prefer that to language binding.
13668            let first_mismatch = templates_with_tags
13669                .iter()
13670                .position(|(tag_source, _)| tag_source != leading_tag_source);
13671            if let Some(index) = first_mismatch {
13672                templates_with_tags.truncate(index);
13673            }
13674        }
13675
13676        templates_with_tags
13677    }
13678
13679    pub fn move_to_enclosing_bracket(
13680        &mut self,
13681        _: &MoveToEnclosingBracket,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13686        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13687            s.move_offsets_with(|snapshot, selection| {
13688                let Some(enclosing_bracket_ranges) =
13689                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13690                else {
13691                    return;
13692                };
13693
13694                let mut best_length = usize::MAX;
13695                let mut best_inside = false;
13696                let mut best_in_bracket_range = false;
13697                let mut best_destination = None;
13698                for (open, close) in enclosing_bracket_ranges {
13699                    let close = close.to_inclusive();
13700                    let length = close.end() - open.start;
13701                    let inside = selection.start >= open.end && selection.end <= *close.start();
13702                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13703                        || close.contains(&selection.head());
13704
13705                    // If best is next to a bracket and current isn't, skip
13706                    if !in_bracket_range && best_in_bracket_range {
13707                        continue;
13708                    }
13709
13710                    // Prefer smaller lengths unless best is inside and current isn't
13711                    if length > best_length && (best_inside || !inside) {
13712                        continue;
13713                    }
13714
13715                    best_length = length;
13716                    best_inside = inside;
13717                    best_in_bracket_range = in_bracket_range;
13718                    best_destination = Some(
13719                        if close.contains(&selection.start) && close.contains(&selection.end) {
13720                            if inside { open.end } else { open.start }
13721                        } else if inside {
13722                            *close.start()
13723                        } else {
13724                            *close.end()
13725                        },
13726                    );
13727                }
13728
13729                if let Some(destination) = best_destination {
13730                    selection.collapse_to(destination, SelectionGoal::None);
13731                }
13732            })
13733        });
13734    }
13735
13736    pub fn undo_selection(
13737        &mut self,
13738        _: &UndoSelection,
13739        window: &mut Window,
13740        cx: &mut Context<Self>,
13741    ) {
13742        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13743        self.end_selection(window, cx);
13744        self.selection_history.mode = SelectionHistoryMode::Undoing;
13745        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13746            self.change_selections(None, window, cx, |s| {
13747                s.select_anchors(entry.selections.to_vec())
13748            });
13749            self.select_next_state = entry.select_next_state;
13750            self.select_prev_state = entry.select_prev_state;
13751            self.add_selections_state = entry.add_selections_state;
13752            self.request_autoscroll(Autoscroll::newest(), cx);
13753        }
13754        self.selection_history.mode = SelectionHistoryMode::Normal;
13755    }
13756
13757    pub fn redo_selection(
13758        &mut self,
13759        _: &RedoSelection,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13764        self.end_selection(window, cx);
13765        self.selection_history.mode = SelectionHistoryMode::Redoing;
13766        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13767            self.change_selections(None, window, cx, |s| {
13768                s.select_anchors(entry.selections.to_vec())
13769            });
13770            self.select_next_state = entry.select_next_state;
13771            self.select_prev_state = entry.select_prev_state;
13772            self.add_selections_state = entry.add_selections_state;
13773            self.request_autoscroll(Autoscroll::newest(), cx);
13774        }
13775        self.selection_history.mode = SelectionHistoryMode::Normal;
13776    }
13777
13778    pub fn expand_excerpts(
13779        &mut self,
13780        action: &ExpandExcerpts,
13781        _: &mut Window,
13782        cx: &mut Context<Self>,
13783    ) {
13784        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13785    }
13786
13787    pub fn expand_excerpts_down(
13788        &mut self,
13789        action: &ExpandExcerptsDown,
13790        _: &mut Window,
13791        cx: &mut Context<Self>,
13792    ) {
13793        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13794    }
13795
13796    pub fn expand_excerpts_up(
13797        &mut self,
13798        action: &ExpandExcerptsUp,
13799        _: &mut Window,
13800        cx: &mut Context<Self>,
13801    ) {
13802        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13803    }
13804
13805    pub fn expand_excerpts_for_direction(
13806        &mut self,
13807        lines: u32,
13808        direction: ExpandExcerptDirection,
13809
13810        cx: &mut Context<Self>,
13811    ) {
13812        let selections = self.selections.disjoint_anchors();
13813
13814        let lines = if lines == 0 {
13815            EditorSettings::get_global(cx).expand_excerpt_lines
13816        } else {
13817            lines
13818        };
13819
13820        self.buffer.update(cx, |buffer, cx| {
13821            let snapshot = buffer.snapshot(cx);
13822            let mut excerpt_ids = selections
13823                .iter()
13824                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13825                .collect::<Vec<_>>();
13826            excerpt_ids.sort();
13827            excerpt_ids.dedup();
13828            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13829        })
13830    }
13831
13832    pub fn expand_excerpt(
13833        &mut self,
13834        excerpt: ExcerptId,
13835        direction: ExpandExcerptDirection,
13836        window: &mut Window,
13837        cx: &mut Context<Self>,
13838    ) {
13839        let current_scroll_position = self.scroll_position(cx);
13840        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13841        let mut should_scroll_up = false;
13842
13843        if direction == ExpandExcerptDirection::Down {
13844            let multi_buffer = self.buffer.read(cx);
13845            let snapshot = multi_buffer.snapshot(cx);
13846            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13847                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13848                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13849                        let buffer_snapshot = buffer.read(cx).snapshot();
13850                        let excerpt_end_row =
13851                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13852                        let last_row = buffer_snapshot.max_point().row;
13853                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13854                        should_scroll_up = lines_below >= lines_to_expand;
13855                    }
13856                }
13857            }
13858        }
13859
13860        self.buffer.update(cx, |buffer, cx| {
13861            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13862        });
13863
13864        if should_scroll_up {
13865            let new_scroll_position =
13866                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13867            self.set_scroll_position(new_scroll_position, window, cx);
13868        }
13869    }
13870
13871    pub fn go_to_singleton_buffer_point(
13872        &mut self,
13873        point: Point,
13874        window: &mut Window,
13875        cx: &mut Context<Self>,
13876    ) {
13877        self.go_to_singleton_buffer_range(point..point, window, cx);
13878    }
13879
13880    pub fn go_to_singleton_buffer_range(
13881        &mut self,
13882        range: Range<Point>,
13883        window: &mut Window,
13884        cx: &mut Context<Self>,
13885    ) {
13886        let multibuffer = self.buffer().read(cx);
13887        let Some(buffer) = multibuffer.as_singleton() else {
13888            return;
13889        };
13890        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13891            return;
13892        };
13893        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13894            return;
13895        };
13896        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13897            s.select_anchor_ranges([start..end])
13898        });
13899    }
13900
13901    pub fn go_to_diagnostic(
13902        &mut self,
13903        _: &GoToDiagnostic,
13904        window: &mut Window,
13905        cx: &mut Context<Self>,
13906    ) {
13907        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13908        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13909    }
13910
13911    pub fn go_to_prev_diagnostic(
13912        &mut self,
13913        _: &GoToPreviousDiagnostic,
13914        window: &mut Window,
13915        cx: &mut Context<Self>,
13916    ) {
13917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13918        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13919    }
13920
13921    pub fn go_to_diagnostic_impl(
13922        &mut self,
13923        direction: Direction,
13924        window: &mut Window,
13925        cx: &mut Context<Self>,
13926    ) {
13927        let buffer = self.buffer.read(cx).snapshot(cx);
13928        let selection = self.selections.newest::<usize>(cx);
13929
13930        let mut active_group_id = None;
13931        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13932            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13933                active_group_id = Some(active_group.group_id);
13934            }
13935        }
13936
13937        fn filtered(
13938            snapshot: EditorSnapshot,
13939            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13940        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13941            diagnostics
13942                .filter(|entry| entry.range.start != entry.range.end)
13943                .filter(|entry| !entry.diagnostic.is_unnecessary)
13944                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13945        }
13946
13947        let snapshot = self.snapshot(window, cx);
13948        let before = filtered(
13949            snapshot.clone(),
13950            buffer
13951                .diagnostics_in_range(0..selection.start)
13952                .filter(|entry| entry.range.start <= selection.start),
13953        );
13954        let after = filtered(
13955            snapshot,
13956            buffer
13957                .diagnostics_in_range(selection.start..buffer.len())
13958                .filter(|entry| entry.range.start >= selection.start),
13959        );
13960
13961        let mut found: Option<DiagnosticEntry<usize>> = None;
13962        if direction == Direction::Prev {
13963            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13964            {
13965                for diagnostic in prev_diagnostics.into_iter().rev() {
13966                    if diagnostic.range.start != selection.start
13967                        || active_group_id
13968                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13969                    {
13970                        found = Some(diagnostic);
13971                        break 'outer;
13972                    }
13973                }
13974            }
13975        } else {
13976            for diagnostic in after.chain(before) {
13977                if diagnostic.range.start != selection.start
13978                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13979                {
13980                    found = Some(diagnostic);
13981                    break;
13982                }
13983            }
13984        }
13985        let Some(next_diagnostic) = found else {
13986            return;
13987        };
13988
13989        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13990            return;
13991        };
13992        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13993            s.select_ranges(vec![
13994                next_diagnostic.range.start..next_diagnostic.range.start,
13995            ])
13996        });
13997        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13998        self.refresh_inline_completion(false, true, window, cx);
13999    }
14000
14001    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14002        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14003        let snapshot = self.snapshot(window, cx);
14004        let selection = self.selections.newest::<Point>(cx);
14005        self.go_to_hunk_before_or_after_position(
14006            &snapshot,
14007            selection.head(),
14008            Direction::Next,
14009            window,
14010            cx,
14011        );
14012    }
14013
14014    pub fn go_to_hunk_before_or_after_position(
14015        &mut self,
14016        snapshot: &EditorSnapshot,
14017        position: Point,
14018        direction: Direction,
14019        window: &mut Window,
14020        cx: &mut Context<Editor>,
14021    ) {
14022        let row = if direction == Direction::Next {
14023            self.hunk_after_position(snapshot, position)
14024                .map(|hunk| hunk.row_range.start)
14025        } else {
14026            self.hunk_before_position(snapshot, position)
14027        };
14028
14029        if let Some(row) = row {
14030            let destination = Point::new(row.0, 0);
14031            let autoscroll = Autoscroll::center();
14032
14033            self.unfold_ranges(&[destination..destination], false, false, cx);
14034            self.change_selections(Some(autoscroll), window, cx, |s| {
14035                s.select_ranges([destination..destination]);
14036            });
14037        }
14038    }
14039
14040    fn hunk_after_position(
14041        &mut self,
14042        snapshot: &EditorSnapshot,
14043        position: Point,
14044    ) -> Option<MultiBufferDiffHunk> {
14045        snapshot
14046            .buffer_snapshot
14047            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14048            .find(|hunk| hunk.row_range.start.0 > position.row)
14049            .or_else(|| {
14050                snapshot
14051                    .buffer_snapshot
14052                    .diff_hunks_in_range(Point::zero()..position)
14053                    .find(|hunk| hunk.row_range.end.0 < position.row)
14054            })
14055    }
14056
14057    fn go_to_prev_hunk(
14058        &mut self,
14059        _: &GoToPreviousHunk,
14060        window: &mut Window,
14061        cx: &mut Context<Self>,
14062    ) {
14063        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14064        let snapshot = self.snapshot(window, cx);
14065        let selection = self.selections.newest::<Point>(cx);
14066        self.go_to_hunk_before_or_after_position(
14067            &snapshot,
14068            selection.head(),
14069            Direction::Prev,
14070            window,
14071            cx,
14072        );
14073    }
14074
14075    fn hunk_before_position(
14076        &mut self,
14077        snapshot: &EditorSnapshot,
14078        position: Point,
14079    ) -> Option<MultiBufferRow> {
14080        snapshot
14081            .buffer_snapshot
14082            .diff_hunk_before(position)
14083            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14084    }
14085
14086    fn go_to_next_change(
14087        &mut self,
14088        _: &GoToNextChange,
14089        window: &mut Window,
14090        cx: &mut Context<Self>,
14091    ) {
14092        if let Some(selections) = self
14093            .change_list
14094            .next_change(1, Direction::Next)
14095            .map(|s| s.to_vec())
14096        {
14097            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14098                let map = s.display_map();
14099                s.select_display_ranges(selections.iter().map(|a| {
14100                    let point = a.to_display_point(&map);
14101                    point..point
14102                }))
14103            })
14104        }
14105    }
14106
14107    fn go_to_previous_change(
14108        &mut self,
14109        _: &GoToPreviousChange,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) {
14113        if let Some(selections) = self
14114            .change_list
14115            .next_change(1, Direction::Prev)
14116            .map(|s| s.to_vec())
14117        {
14118            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14119                let map = s.display_map();
14120                s.select_display_ranges(selections.iter().map(|a| {
14121                    let point = a.to_display_point(&map);
14122                    point..point
14123                }))
14124            })
14125        }
14126    }
14127
14128    fn go_to_line<T: 'static>(
14129        &mut self,
14130        position: Anchor,
14131        highlight_color: Option<Hsla>,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        let snapshot = self.snapshot(window, cx).display_snapshot;
14136        let position = position.to_point(&snapshot.buffer_snapshot);
14137        let start = snapshot
14138            .buffer_snapshot
14139            .clip_point(Point::new(position.row, 0), Bias::Left);
14140        let end = start + Point::new(1, 0);
14141        let start = snapshot.buffer_snapshot.anchor_before(start);
14142        let end = snapshot.buffer_snapshot.anchor_before(end);
14143
14144        self.highlight_rows::<T>(
14145            start..end,
14146            highlight_color
14147                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14148            Default::default(),
14149            cx,
14150        );
14151
14152        if self.buffer.read(cx).is_singleton() {
14153            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14154        }
14155    }
14156
14157    pub fn go_to_definition(
14158        &mut self,
14159        _: &GoToDefinition,
14160        window: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) -> Task<Result<Navigated>> {
14163        let definition =
14164            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14165        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14166        cx.spawn_in(window, async move |editor, cx| {
14167            if definition.await? == Navigated::Yes {
14168                return Ok(Navigated::Yes);
14169            }
14170            match fallback_strategy {
14171                GoToDefinitionFallback::None => Ok(Navigated::No),
14172                GoToDefinitionFallback::FindAllReferences => {
14173                    match editor.update_in(cx, |editor, window, cx| {
14174                        editor.find_all_references(&FindAllReferences, window, cx)
14175                    })? {
14176                        Some(references) => references.await,
14177                        None => Ok(Navigated::No),
14178                    }
14179                }
14180            }
14181        })
14182    }
14183
14184    pub fn go_to_declaration(
14185        &mut self,
14186        _: &GoToDeclaration,
14187        window: &mut Window,
14188        cx: &mut Context<Self>,
14189    ) -> Task<Result<Navigated>> {
14190        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14191    }
14192
14193    pub fn go_to_declaration_split(
14194        &mut self,
14195        _: &GoToDeclaration,
14196        window: &mut Window,
14197        cx: &mut Context<Self>,
14198    ) -> Task<Result<Navigated>> {
14199        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14200    }
14201
14202    pub fn go_to_implementation(
14203        &mut self,
14204        _: &GoToImplementation,
14205        window: &mut Window,
14206        cx: &mut Context<Self>,
14207    ) -> Task<Result<Navigated>> {
14208        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14209    }
14210
14211    pub fn go_to_implementation_split(
14212        &mut self,
14213        _: &GoToImplementationSplit,
14214        window: &mut Window,
14215        cx: &mut Context<Self>,
14216    ) -> Task<Result<Navigated>> {
14217        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14218    }
14219
14220    pub fn go_to_type_definition(
14221        &mut self,
14222        _: &GoToTypeDefinition,
14223        window: &mut Window,
14224        cx: &mut Context<Self>,
14225    ) -> Task<Result<Navigated>> {
14226        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14227    }
14228
14229    pub fn go_to_definition_split(
14230        &mut self,
14231        _: &GoToDefinitionSplit,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) -> Task<Result<Navigated>> {
14235        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14236    }
14237
14238    pub fn go_to_type_definition_split(
14239        &mut self,
14240        _: &GoToTypeDefinitionSplit,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Task<Result<Navigated>> {
14244        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14245    }
14246
14247    fn go_to_definition_of_kind(
14248        &mut self,
14249        kind: GotoDefinitionKind,
14250        split: bool,
14251        window: &mut Window,
14252        cx: &mut Context<Self>,
14253    ) -> Task<Result<Navigated>> {
14254        let Some(provider) = self.semantics_provider.clone() else {
14255            return Task::ready(Ok(Navigated::No));
14256        };
14257        let head = self.selections.newest::<usize>(cx).head();
14258        let buffer = self.buffer.read(cx);
14259        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14260            text_anchor
14261        } else {
14262            return Task::ready(Ok(Navigated::No));
14263        };
14264
14265        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14266            return Task::ready(Ok(Navigated::No));
14267        };
14268
14269        cx.spawn_in(window, async move |editor, cx| {
14270            let definitions = definitions.await?;
14271            let navigated = editor
14272                .update_in(cx, |editor, window, cx| {
14273                    editor.navigate_to_hover_links(
14274                        Some(kind),
14275                        definitions
14276                            .into_iter()
14277                            .filter(|location| {
14278                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14279                            })
14280                            .map(HoverLink::Text)
14281                            .collect::<Vec<_>>(),
14282                        split,
14283                        window,
14284                        cx,
14285                    )
14286                })?
14287                .await?;
14288            anyhow::Ok(navigated)
14289        })
14290    }
14291
14292    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14293        let selection = self.selections.newest_anchor();
14294        let head = selection.head();
14295        let tail = selection.tail();
14296
14297        let Some((buffer, start_position)) =
14298            self.buffer.read(cx).text_anchor_for_position(head, cx)
14299        else {
14300            return;
14301        };
14302
14303        let end_position = if head != tail {
14304            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14305                return;
14306            };
14307            Some(pos)
14308        } else {
14309            None
14310        };
14311
14312        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14313            let url = if let Some(end_pos) = end_position {
14314                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14315            } else {
14316                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14317            };
14318
14319            if let Some(url) = url {
14320                editor.update(cx, |_, cx| {
14321                    cx.open_url(&url);
14322                })
14323            } else {
14324                Ok(())
14325            }
14326        });
14327
14328        url_finder.detach();
14329    }
14330
14331    pub fn open_selected_filename(
14332        &mut self,
14333        _: &OpenSelectedFilename,
14334        window: &mut Window,
14335        cx: &mut Context<Self>,
14336    ) {
14337        let Some(workspace) = self.workspace() else {
14338            return;
14339        };
14340
14341        let position = self.selections.newest_anchor().head();
14342
14343        let Some((buffer, buffer_position)) =
14344            self.buffer.read(cx).text_anchor_for_position(position, cx)
14345        else {
14346            return;
14347        };
14348
14349        let project = self.project.clone();
14350
14351        cx.spawn_in(window, async move |_, cx| {
14352            let result = find_file(&buffer, project, buffer_position, cx).await;
14353
14354            if let Some((_, path)) = result {
14355                workspace
14356                    .update_in(cx, |workspace, window, cx| {
14357                        workspace.open_resolved_path(path, window, cx)
14358                    })?
14359                    .await?;
14360            }
14361            anyhow::Ok(())
14362        })
14363        .detach();
14364    }
14365
14366    pub(crate) fn navigate_to_hover_links(
14367        &mut self,
14368        kind: Option<GotoDefinitionKind>,
14369        mut definitions: Vec<HoverLink>,
14370        split: bool,
14371        window: &mut Window,
14372        cx: &mut Context<Editor>,
14373    ) -> Task<Result<Navigated>> {
14374        // If there is one definition, just open it directly
14375        if definitions.len() == 1 {
14376            let definition = definitions.pop().unwrap();
14377
14378            enum TargetTaskResult {
14379                Location(Option<Location>),
14380                AlreadyNavigated,
14381            }
14382
14383            let target_task = match definition {
14384                HoverLink::Text(link) => {
14385                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14386                }
14387                HoverLink::InlayHint(lsp_location, server_id) => {
14388                    let computation =
14389                        self.compute_target_location(lsp_location, server_id, window, cx);
14390                    cx.background_spawn(async move {
14391                        let location = computation.await?;
14392                        Ok(TargetTaskResult::Location(location))
14393                    })
14394                }
14395                HoverLink::Url(url) => {
14396                    cx.open_url(&url);
14397                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14398                }
14399                HoverLink::File(path) => {
14400                    if let Some(workspace) = self.workspace() {
14401                        cx.spawn_in(window, async move |_, cx| {
14402                            workspace
14403                                .update_in(cx, |workspace, window, cx| {
14404                                    workspace.open_resolved_path(path, window, cx)
14405                                })?
14406                                .await
14407                                .map(|_| TargetTaskResult::AlreadyNavigated)
14408                        })
14409                    } else {
14410                        Task::ready(Ok(TargetTaskResult::Location(None)))
14411                    }
14412                }
14413            };
14414            cx.spawn_in(window, async move |editor, cx| {
14415                let target = match target_task.await.context("target resolution task")? {
14416                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14417                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14418                    TargetTaskResult::Location(Some(target)) => target,
14419                };
14420
14421                editor.update_in(cx, |editor, window, cx| {
14422                    let Some(workspace) = editor.workspace() else {
14423                        return Navigated::No;
14424                    };
14425                    let pane = workspace.read(cx).active_pane().clone();
14426
14427                    let range = target.range.to_point(target.buffer.read(cx));
14428                    let range = editor.range_for_match(&range);
14429                    let range = collapse_multiline_range(range);
14430
14431                    if !split
14432                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14433                    {
14434                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14435                    } else {
14436                        window.defer(cx, move |window, cx| {
14437                            let target_editor: Entity<Self> =
14438                                workspace.update(cx, |workspace, cx| {
14439                                    let pane = if split {
14440                                        workspace.adjacent_pane(window, cx)
14441                                    } else {
14442                                        workspace.active_pane().clone()
14443                                    };
14444
14445                                    workspace.open_project_item(
14446                                        pane,
14447                                        target.buffer.clone(),
14448                                        true,
14449                                        true,
14450                                        window,
14451                                        cx,
14452                                    )
14453                                });
14454                            target_editor.update(cx, |target_editor, cx| {
14455                                // When selecting a definition in a different buffer, disable the nav history
14456                                // to avoid creating a history entry at the previous cursor location.
14457                                pane.update(cx, |pane, _| pane.disable_history());
14458                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14459                                pane.update(cx, |pane, _| pane.enable_history());
14460                            });
14461                        });
14462                    }
14463                    Navigated::Yes
14464                })
14465            })
14466        } else if !definitions.is_empty() {
14467            cx.spawn_in(window, async move |editor, cx| {
14468                let (title, location_tasks, workspace) = editor
14469                    .update_in(cx, |editor, window, cx| {
14470                        let tab_kind = match kind {
14471                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14472                            _ => "Definitions",
14473                        };
14474                        let title = definitions
14475                            .iter()
14476                            .find_map(|definition| match definition {
14477                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14478                                    let buffer = origin.buffer.read(cx);
14479                                    format!(
14480                                        "{} for {}",
14481                                        tab_kind,
14482                                        buffer
14483                                            .text_for_range(origin.range.clone())
14484                                            .collect::<String>()
14485                                    )
14486                                }),
14487                                HoverLink::InlayHint(_, _) => None,
14488                                HoverLink::Url(_) => None,
14489                                HoverLink::File(_) => None,
14490                            })
14491                            .unwrap_or(tab_kind.to_string());
14492                        let location_tasks = definitions
14493                            .into_iter()
14494                            .map(|definition| match definition {
14495                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14496                                HoverLink::InlayHint(lsp_location, server_id) => editor
14497                                    .compute_target_location(lsp_location, server_id, window, cx),
14498                                HoverLink::Url(_) => Task::ready(Ok(None)),
14499                                HoverLink::File(_) => Task::ready(Ok(None)),
14500                            })
14501                            .collect::<Vec<_>>();
14502                        (title, location_tasks, editor.workspace().clone())
14503                    })
14504                    .context("location tasks preparation")?;
14505
14506                let locations = future::join_all(location_tasks)
14507                    .await
14508                    .into_iter()
14509                    .filter_map(|location| location.transpose())
14510                    .collect::<Result<_>>()
14511                    .context("location tasks")?;
14512
14513                let Some(workspace) = workspace else {
14514                    return Ok(Navigated::No);
14515                };
14516                let opened = workspace
14517                    .update_in(cx, |workspace, window, cx| {
14518                        Self::open_locations_in_multibuffer(
14519                            workspace,
14520                            locations,
14521                            title,
14522                            split,
14523                            MultibufferSelectionMode::First,
14524                            window,
14525                            cx,
14526                        )
14527                    })
14528                    .ok();
14529
14530                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14531            })
14532        } else {
14533            Task::ready(Ok(Navigated::No))
14534        }
14535    }
14536
14537    fn compute_target_location(
14538        &self,
14539        lsp_location: lsp::Location,
14540        server_id: LanguageServerId,
14541        window: &mut Window,
14542        cx: &mut Context<Self>,
14543    ) -> Task<anyhow::Result<Option<Location>>> {
14544        let Some(project) = self.project.clone() else {
14545            return Task::ready(Ok(None));
14546        };
14547
14548        cx.spawn_in(window, async move |editor, cx| {
14549            let location_task = editor.update(cx, |_, cx| {
14550                project.update(cx, |project, cx| {
14551                    let language_server_name = project
14552                        .language_server_statuses(cx)
14553                        .find(|(id, _)| server_id == *id)
14554                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14555                    language_server_name.map(|language_server_name| {
14556                        project.open_local_buffer_via_lsp(
14557                            lsp_location.uri.clone(),
14558                            server_id,
14559                            language_server_name,
14560                            cx,
14561                        )
14562                    })
14563                })
14564            })?;
14565            let location = match location_task {
14566                Some(task) => Some({
14567                    let target_buffer_handle = task.await.context("open local buffer")?;
14568                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14569                        let target_start = target_buffer
14570                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14571                        let target_end = target_buffer
14572                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14573                        target_buffer.anchor_after(target_start)
14574                            ..target_buffer.anchor_before(target_end)
14575                    })?;
14576                    Location {
14577                        buffer: target_buffer_handle,
14578                        range,
14579                    }
14580                }),
14581                None => None,
14582            };
14583            Ok(location)
14584        })
14585    }
14586
14587    pub fn find_all_references(
14588        &mut self,
14589        _: &FindAllReferences,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) -> Option<Task<Result<Navigated>>> {
14593        let selection = self.selections.newest::<usize>(cx);
14594        let multi_buffer = self.buffer.read(cx);
14595        let head = selection.head();
14596
14597        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14598        let head_anchor = multi_buffer_snapshot.anchor_at(
14599            head,
14600            if head < selection.tail() {
14601                Bias::Right
14602            } else {
14603                Bias::Left
14604            },
14605        );
14606
14607        match self
14608            .find_all_references_task_sources
14609            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14610        {
14611            Ok(_) => {
14612                log::info!(
14613                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14614                );
14615                return None;
14616            }
14617            Err(i) => {
14618                self.find_all_references_task_sources.insert(i, head_anchor);
14619            }
14620        }
14621
14622        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14623        let workspace = self.workspace()?;
14624        let project = workspace.read(cx).project().clone();
14625        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14626        Some(cx.spawn_in(window, async move |editor, cx| {
14627            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14628                if let Ok(i) = editor
14629                    .find_all_references_task_sources
14630                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14631                {
14632                    editor.find_all_references_task_sources.remove(i);
14633                }
14634            });
14635
14636            let locations = references.await?;
14637            if locations.is_empty() {
14638                return anyhow::Ok(Navigated::No);
14639            }
14640
14641            workspace.update_in(cx, |workspace, window, cx| {
14642                let title = locations
14643                    .first()
14644                    .as_ref()
14645                    .map(|location| {
14646                        let buffer = location.buffer.read(cx);
14647                        format!(
14648                            "References to `{}`",
14649                            buffer
14650                                .text_for_range(location.range.clone())
14651                                .collect::<String>()
14652                        )
14653                    })
14654                    .unwrap();
14655                Self::open_locations_in_multibuffer(
14656                    workspace,
14657                    locations,
14658                    title,
14659                    false,
14660                    MultibufferSelectionMode::First,
14661                    window,
14662                    cx,
14663                );
14664                Navigated::Yes
14665            })
14666        }))
14667    }
14668
14669    /// Opens a multibuffer with the given project locations in it
14670    pub fn open_locations_in_multibuffer(
14671        workspace: &mut Workspace,
14672        mut locations: Vec<Location>,
14673        title: String,
14674        split: bool,
14675        multibuffer_selection_mode: MultibufferSelectionMode,
14676        window: &mut Window,
14677        cx: &mut Context<Workspace>,
14678    ) {
14679        // If there are multiple definitions, open them in a multibuffer
14680        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14681        let mut locations = locations.into_iter().peekable();
14682        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14683        let capability = workspace.project().read(cx).capability();
14684
14685        let excerpt_buffer = cx.new(|cx| {
14686            let mut multibuffer = MultiBuffer::new(capability);
14687            while let Some(location) = locations.next() {
14688                let buffer = location.buffer.read(cx);
14689                let mut ranges_for_buffer = Vec::new();
14690                let range = location.range.to_point(buffer);
14691                ranges_for_buffer.push(range.clone());
14692
14693                while let Some(next_location) = locations.peek() {
14694                    if next_location.buffer == location.buffer {
14695                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14696                        locations.next();
14697                    } else {
14698                        break;
14699                    }
14700                }
14701
14702                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14703                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14704                    PathKey::for_buffer(&location.buffer, cx),
14705                    location.buffer.clone(),
14706                    ranges_for_buffer,
14707                    DEFAULT_MULTIBUFFER_CONTEXT,
14708                    cx,
14709                );
14710                ranges.extend(new_ranges)
14711            }
14712
14713            multibuffer.with_title(title)
14714        });
14715
14716        let editor = cx.new(|cx| {
14717            Editor::for_multibuffer(
14718                excerpt_buffer,
14719                Some(workspace.project().clone()),
14720                window,
14721                cx,
14722            )
14723        });
14724        editor.update(cx, |editor, cx| {
14725            match multibuffer_selection_mode {
14726                MultibufferSelectionMode::First => {
14727                    if let Some(first_range) = ranges.first() {
14728                        editor.change_selections(None, window, cx, |selections| {
14729                            selections.clear_disjoint();
14730                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14731                        });
14732                    }
14733                    editor.highlight_background::<Self>(
14734                        &ranges,
14735                        |theme| theme.editor_highlighted_line_background,
14736                        cx,
14737                    );
14738                }
14739                MultibufferSelectionMode::All => {
14740                    editor.change_selections(None, window, cx, |selections| {
14741                        selections.clear_disjoint();
14742                        selections.select_anchor_ranges(ranges);
14743                    });
14744                }
14745            }
14746            editor.register_buffers_with_language_servers(cx);
14747        });
14748
14749        let item = Box::new(editor);
14750        let item_id = item.item_id();
14751
14752        if split {
14753            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14754        } else {
14755            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14756                let (preview_item_id, preview_item_idx) =
14757                    workspace.active_pane().update(cx, |pane, _| {
14758                        (pane.preview_item_id(), pane.preview_item_idx())
14759                    });
14760
14761                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14762
14763                if let Some(preview_item_id) = preview_item_id {
14764                    workspace.active_pane().update(cx, |pane, cx| {
14765                        pane.remove_item(preview_item_id, false, false, window, cx);
14766                    });
14767                }
14768            } else {
14769                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14770            }
14771        }
14772        workspace.active_pane().update(cx, |pane, cx| {
14773            pane.set_preview_item_id(Some(item_id), cx);
14774        });
14775    }
14776
14777    pub fn rename(
14778        &mut self,
14779        _: &Rename,
14780        window: &mut Window,
14781        cx: &mut Context<Self>,
14782    ) -> Option<Task<Result<()>>> {
14783        use language::ToOffset as _;
14784
14785        let provider = self.semantics_provider.clone()?;
14786        let selection = self.selections.newest_anchor().clone();
14787        let (cursor_buffer, cursor_buffer_position) = self
14788            .buffer
14789            .read(cx)
14790            .text_anchor_for_position(selection.head(), cx)?;
14791        let (tail_buffer, cursor_buffer_position_end) = self
14792            .buffer
14793            .read(cx)
14794            .text_anchor_for_position(selection.tail(), cx)?;
14795        if tail_buffer != cursor_buffer {
14796            return None;
14797        }
14798
14799        let snapshot = cursor_buffer.read(cx).snapshot();
14800        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14801        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14802        let prepare_rename = provider
14803            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14804            .unwrap_or_else(|| Task::ready(Ok(None)));
14805        drop(snapshot);
14806
14807        Some(cx.spawn_in(window, async move |this, cx| {
14808            let rename_range = if let Some(range) = prepare_rename.await? {
14809                Some(range)
14810            } else {
14811                this.update(cx, |this, cx| {
14812                    let buffer = this.buffer.read(cx).snapshot(cx);
14813                    let mut buffer_highlights = this
14814                        .document_highlights_for_position(selection.head(), &buffer)
14815                        .filter(|highlight| {
14816                            highlight.start.excerpt_id == selection.head().excerpt_id
14817                                && highlight.end.excerpt_id == selection.head().excerpt_id
14818                        });
14819                    buffer_highlights
14820                        .next()
14821                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14822                })?
14823            };
14824            if let Some(rename_range) = rename_range {
14825                this.update_in(cx, |this, window, cx| {
14826                    let snapshot = cursor_buffer.read(cx).snapshot();
14827                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14828                    let cursor_offset_in_rename_range =
14829                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14830                    let cursor_offset_in_rename_range_end =
14831                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14832
14833                    this.take_rename(false, window, cx);
14834                    let buffer = this.buffer.read(cx).read(cx);
14835                    let cursor_offset = selection.head().to_offset(&buffer);
14836                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14837                    let rename_end = rename_start + rename_buffer_range.len();
14838                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14839                    let mut old_highlight_id = None;
14840                    let old_name: Arc<str> = buffer
14841                        .chunks(rename_start..rename_end, true)
14842                        .map(|chunk| {
14843                            if old_highlight_id.is_none() {
14844                                old_highlight_id = chunk.syntax_highlight_id;
14845                            }
14846                            chunk.text
14847                        })
14848                        .collect::<String>()
14849                        .into();
14850
14851                    drop(buffer);
14852
14853                    // Position the selection in the rename editor so that it matches the current selection.
14854                    this.show_local_selections = false;
14855                    let rename_editor = cx.new(|cx| {
14856                        let mut editor = Editor::single_line(window, cx);
14857                        editor.buffer.update(cx, |buffer, cx| {
14858                            buffer.edit([(0..0, old_name.clone())], None, cx)
14859                        });
14860                        let rename_selection_range = match cursor_offset_in_rename_range
14861                            .cmp(&cursor_offset_in_rename_range_end)
14862                        {
14863                            Ordering::Equal => {
14864                                editor.select_all(&SelectAll, window, cx);
14865                                return editor;
14866                            }
14867                            Ordering::Less => {
14868                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14869                            }
14870                            Ordering::Greater => {
14871                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14872                            }
14873                        };
14874                        if rename_selection_range.end > old_name.len() {
14875                            editor.select_all(&SelectAll, window, cx);
14876                        } else {
14877                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14878                                s.select_ranges([rename_selection_range]);
14879                            });
14880                        }
14881                        editor
14882                    });
14883                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14884                        if e == &EditorEvent::Focused {
14885                            cx.emit(EditorEvent::FocusedIn)
14886                        }
14887                    })
14888                    .detach();
14889
14890                    let write_highlights =
14891                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14892                    let read_highlights =
14893                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14894                    let ranges = write_highlights
14895                        .iter()
14896                        .flat_map(|(_, ranges)| ranges.iter())
14897                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14898                        .cloned()
14899                        .collect();
14900
14901                    this.highlight_text::<Rename>(
14902                        ranges,
14903                        HighlightStyle {
14904                            fade_out: Some(0.6),
14905                            ..Default::default()
14906                        },
14907                        cx,
14908                    );
14909                    let rename_focus_handle = rename_editor.focus_handle(cx);
14910                    window.focus(&rename_focus_handle);
14911                    let block_id = this.insert_blocks(
14912                        [BlockProperties {
14913                            style: BlockStyle::Flex,
14914                            placement: BlockPlacement::Below(range.start),
14915                            height: Some(1),
14916                            render: Arc::new({
14917                                let rename_editor = rename_editor.clone();
14918                                move |cx: &mut BlockContext| {
14919                                    let mut text_style = cx.editor_style.text.clone();
14920                                    if let Some(highlight_style) = old_highlight_id
14921                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14922                                    {
14923                                        text_style = text_style.highlight(highlight_style);
14924                                    }
14925                                    div()
14926                                        .block_mouse_down()
14927                                        .pl(cx.anchor_x)
14928                                        .child(EditorElement::new(
14929                                            &rename_editor,
14930                                            EditorStyle {
14931                                                background: cx.theme().system().transparent,
14932                                                local_player: cx.editor_style.local_player,
14933                                                text: text_style,
14934                                                scrollbar_width: cx.editor_style.scrollbar_width,
14935                                                syntax: cx.editor_style.syntax.clone(),
14936                                                status: cx.editor_style.status.clone(),
14937                                                inlay_hints_style: HighlightStyle {
14938                                                    font_weight: Some(FontWeight::BOLD),
14939                                                    ..make_inlay_hints_style(cx.app)
14940                                                },
14941                                                inline_completion_styles: make_suggestion_styles(
14942                                                    cx.app,
14943                                                ),
14944                                                ..EditorStyle::default()
14945                                            },
14946                                        ))
14947                                        .into_any_element()
14948                                }
14949                            }),
14950                            priority: 0,
14951                            render_in_minimap: true,
14952                        }],
14953                        Some(Autoscroll::fit()),
14954                        cx,
14955                    )[0];
14956                    this.pending_rename = Some(RenameState {
14957                        range,
14958                        old_name,
14959                        editor: rename_editor,
14960                        block_id,
14961                    });
14962                })?;
14963            }
14964
14965            Ok(())
14966        }))
14967    }
14968
14969    pub fn confirm_rename(
14970        &mut self,
14971        _: &ConfirmRename,
14972        window: &mut Window,
14973        cx: &mut Context<Self>,
14974    ) -> Option<Task<Result<()>>> {
14975        let rename = self.take_rename(false, window, cx)?;
14976        let workspace = self.workspace()?.downgrade();
14977        let (buffer, start) = self
14978            .buffer
14979            .read(cx)
14980            .text_anchor_for_position(rename.range.start, cx)?;
14981        let (end_buffer, _) = self
14982            .buffer
14983            .read(cx)
14984            .text_anchor_for_position(rename.range.end, cx)?;
14985        if buffer != end_buffer {
14986            return None;
14987        }
14988
14989        let old_name = rename.old_name;
14990        let new_name = rename.editor.read(cx).text(cx);
14991
14992        let rename = self.semantics_provider.as_ref()?.perform_rename(
14993            &buffer,
14994            start,
14995            new_name.clone(),
14996            cx,
14997        )?;
14998
14999        Some(cx.spawn_in(window, async move |editor, cx| {
15000            let project_transaction = rename.await?;
15001            Self::open_project_transaction(
15002                &editor,
15003                workspace,
15004                project_transaction,
15005                format!("Rename: {}{}", old_name, new_name),
15006                cx,
15007            )
15008            .await?;
15009
15010            editor.update(cx, |editor, cx| {
15011                editor.refresh_document_highlights(cx);
15012            })?;
15013            Ok(())
15014        }))
15015    }
15016
15017    fn take_rename(
15018        &mut self,
15019        moving_cursor: bool,
15020        window: &mut Window,
15021        cx: &mut Context<Self>,
15022    ) -> Option<RenameState> {
15023        let rename = self.pending_rename.take()?;
15024        if rename.editor.focus_handle(cx).is_focused(window) {
15025            window.focus(&self.focus_handle);
15026        }
15027
15028        self.remove_blocks(
15029            [rename.block_id].into_iter().collect(),
15030            Some(Autoscroll::fit()),
15031            cx,
15032        );
15033        self.clear_highlights::<Rename>(cx);
15034        self.show_local_selections = true;
15035
15036        if moving_cursor {
15037            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15038                editor.selections.newest::<usize>(cx).head()
15039            });
15040
15041            // Update the selection to match the position of the selection inside
15042            // the rename editor.
15043            let snapshot = self.buffer.read(cx).read(cx);
15044            let rename_range = rename.range.to_offset(&snapshot);
15045            let cursor_in_editor = snapshot
15046                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15047                .min(rename_range.end);
15048            drop(snapshot);
15049
15050            self.change_selections(None, window, cx, |s| {
15051                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15052            });
15053        } else {
15054            self.refresh_document_highlights(cx);
15055        }
15056
15057        Some(rename)
15058    }
15059
15060    pub fn pending_rename(&self) -> Option<&RenameState> {
15061        self.pending_rename.as_ref()
15062    }
15063
15064    fn format(
15065        &mut self,
15066        _: &Format,
15067        window: &mut Window,
15068        cx: &mut Context<Self>,
15069    ) -> Option<Task<Result<()>>> {
15070        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15071
15072        let project = match &self.project {
15073            Some(project) => project.clone(),
15074            None => return None,
15075        };
15076
15077        Some(self.perform_format(
15078            project,
15079            FormatTrigger::Manual,
15080            FormatTarget::Buffers,
15081            window,
15082            cx,
15083        ))
15084    }
15085
15086    fn format_selections(
15087        &mut self,
15088        _: &FormatSelections,
15089        window: &mut Window,
15090        cx: &mut Context<Self>,
15091    ) -> Option<Task<Result<()>>> {
15092        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15093
15094        let project = match &self.project {
15095            Some(project) => project.clone(),
15096            None => return None,
15097        };
15098
15099        let ranges = self
15100            .selections
15101            .all_adjusted(cx)
15102            .into_iter()
15103            .map(|selection| selection.range())
15104            .collect_vec();
15105
15106        Some(self.perform_format(
15107            project,
15108            FormatTrigger::Manual,
15109            FormatTarget::Ranges(ranges),
15110            window,
15111            cx,
15112        ))
15113    }
15114
15115    fn perform_format(
15116        &mut self,
15117        project: Entity<Project>,
15118        trigger: FormatTrigger,
15119        target: FormatTarget,
15120        window: &mut Window,
15121        cx: &mut Context<Self>,
15122    ) -> Task<Result<()>> {
15123        let buffer = self.buffer.clone();
15124        let (buffers, target) = match target {
15125            FormatTarget::Buffers => {
15126                let mut buffers = buffer.read(cx).all_buffers();
15127                if trigger == FormatTrigger::Save {
15128                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15129                }
15130                (buffers, LspFormatTarget::Buffers)
15131            }
15132            FormatTarget::Ranges(selection_ranges) => {
15133                let multi_buffer = buffer.read(cx);
15134                let snapshot = multi_buffer.read(cx);
15135                let mut buffers = HashSet::default();
15136                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15137                    BTreeMap::new();
15138                for selection_range in selection_ranges {
15139                    for (buffer, buffer_range, _) in
15140                        snapshot.range_to_buffer_ranges(selection_range)
15141                    {
15142                        let buffer_id = buffer.remote_id();
15143                        let start = buffer.anchor_before(buffer_range.start);
15144                        let end = buffer.anchor_after(buffer_range.end);
15145                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15146                        buffer_id_to_ranges
15147                            .entry(buffer_id)
15148                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15149                            .or_insert_with(|| vec![start..end]);
15150                    }
15151                }
15152                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15153            }
15154        };
15155
15156        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15157        let selections_prev = transaction_id_prev
15158            .and_then(|transaction_id_prev| {
15159                // default to selections as they were after the last edit, if we have them,
15160                // instead of how they are now.
15161                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15162                // will take you back to where you made the last edit, instead of staying where you scrolled
15163                self.selection_history
15164                    .transaction(transaction_id_prev)
15165                    .map(|t| t.0.clone())
15166            })
15167            .unwrap_or_else(|| {
15168                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15169                self.selections.disjoint_anchors()
15170            });
15171
15172        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15173        let format = project.update(cx, |project, cx| {
15174            project.format(buffers, target, true, trigger, cx)
15175        });
15176
15177        cx.spawn_in(window, async move |editor, cx| {
15178            let transaction = futures::select_biased! {
15179                transaction = format.log_err().fuse() => transaction,
15180                () = timeout => {
15181                    log::warn!("timed out waiting for formatting");
15182                    None
15183                }
15184            };
15185
15186            buffer
15187                .update(cx, |buffer, cx| {
15188                    if let Some(transaction) = transaction {
15189                        if !buffer.is_singleton() {
15190                            buffer.push_transaction(&transaction.0, cx);
15191                        }
15192                    }
15193                    cx.notify();
15194                })
15195                .ok();
15196
15197            if let Some(transaction_id_now) =
15198                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15199            {
15200                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15201                if has_new_transaction {
15202                    _ = editor.update(cx, |editor, _| {
15203                        editor
15204                            .selection_history
15205                            .insert_transaction(transaction_id_now, selections_prev);
15206                    });
15207                }
15208            }
15209
15210            Ok(())
15211        })
15212    }
15213
15214    fn organize_imports(
15215        &mut self,
15216        _: &OrganizeImports,
15217        window: &mut Window,
15218        cx: &mut Context<Self>,
15219    ) -> Option<Task<Result<()>>> {
15220        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15221        let project = match &self.project {
15222            Some(project) => project.clone(),
15223            None => return None,
15224        };
15225        Some(self.perform_code_action_kind(
15226            project,
15227            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15228            window,
15229            cx,
15230        ))
15231    }
15232
15233    fn perform_code_action_kind(
15234        &mut self,
15235        project: Entity<Project>,
15236        kind: CodeActionKind,
15237        window: &mut Window,
15238        cx: &mut Context<Self>,
15239    ) -> Task<Result<()>> {
15240        let buffer = self.buffer.clone();
15241        let buffers = buffer.read(cx).all_buffers();
15242        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15243        let apply_action = project.update(cx, |project, cx| {
15244            project.apply_code_action_kind(buffers, kind, true, cx)
15245        });
15246        cx.spawn_in(window, async move |_, cx| {
15247            let transaction = futures::select_biased! {
15248                () = timeout => {
15249                    log::warn!("timed out waiting for executing code action");
15250                    None
15251                }
15252                transaction = apply_action.log_err().fuse() => transaction,
15253            };
15254            buffer
15255                .update(cx, |buffer, cx| {
15256                    // check if we need this
15257                    if let Some(transaction) = transaction {
15258                        if !buffer.is_singleton() {
15259                            buffer.push_transaction(&transaction.0, cx);
15260                        }
15261                    }
15262                    cx.notify();
15263                })
15264                .ok();
15265            Ok(())
15266        })
15267    }
15268
15269    fn restart_language_server(
15270        &mut self,
15271        _: &RestartLanguageServer,
15272        _: &mut Window,
15273        cx: &mut Context<Self>,
15274    ) {
15275        if let Some(project) = self.project.clone() {
15276            self.buffer.update(cx, |multi_buffer, cx| {
15277                project.update(cx, |project, cx| {
15278                    project.restart_language_servers_for_buffers(
15279                        multi_buffer.all_buffers().into_iter().collect(),
15280                        cx,
15281                    );
15282                });
15283            })
15284        }
15285    }
15286
15287    fn stop_language_server(
15288        &mut self,
15289        _: &StopLanguageServer,
15290        _: &mut Window,
15291        cx: &mut Context<Self>,
15292    ) {
15293        if let Some(project) = self.project.clone() {
15294            self.buffer.update(cx, |multi_buffer, cx| {
15295                project.update(cx, |project, cx| {
15296                    project.stop_language_servers_for_buffers(
15297                        multi_buffer.all_buffers().into_iter().collect(),
15298                        cx,
15299                    );
15300                    cx.emit(project::Event::RefreshInlayHints);
15301                });
15302            });
15303        }
15304    }
15305
15306    fn cancel_language_server_work(
15307        workspace: &mut Workspace,
15308        _: &actions::CancelLanguageServerWork,
15309        _: &mut Window,
15310        cx: &mut Context<Workspace>,
15311    ) {
15312        let project = workspace.project();
15313        let buffers = workspace
15314            .active_item(cx)
15315            .and_then(|item| item.act_as::<Editor>(cx))
15316            .map_or(HashSet::default(), |editor| {
15317                editor.read(cx).buffer.read(cx).all_buffers()
15318            });
15319        project.update(cx, |project, cx| {
15320            project.cancel_language_server_work_for_buffers(buffers, cx);
15321        });
15322    }
15323
15324    fn show_character_palette(
15325        &mut self,
15326        _: &ShowCharacterPalette,
15327        window: &mut Window,
15328        _: &mut Context<Self>,
15329    ) {
15330        window.show_character_palette();
15331    }
15332
15333    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15334        if self.mode.is_minimap() {
15335            return;
15336        }
15337
15338        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15339            let buffer = self.buffer.read(cx).snapshot(cx);
15340            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15341            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15342            let is_valid = buffer
15343                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15344                .any(|entry| {
15345                    entry.diagnostic.is_primary
15346                        && !entry.range.is_empty()
15347                        && entry.range.start == primary_range_start
15348                        && entry.diagnostic.message == active_diagnostics.active_message
15349                });
15350
15351            if !is_valid {
15352                self.dismiss_diagnostics(cx);
15353            }
15354        }
15355    }
15356
15357    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15358        match &self.active_diagnostics {
15359            ActiveDiagnostic::Group(group) => Some(group),
15360            _ => None,
15361        }
15362    }
15363
15364    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15365        self.dismiss_diagnostics(cx);
15366        self.active_diagnostics = ActiveDiagnostic::All;
15367    }
15368
15369    fn activate_diagnostics(
15370        &mut self,
15371        buffer_id: BufferId,
15372        diagnostic: DiagnosticEntry<usize>,
15373        window: &mut Window,
15374        cx: &mut Context<Self>,
15375    ) {
15376        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15377            return;
15378        }
15379        self.dismiss_diagnostics(cx);
15380        let snapshot = self.snapshot(window, cx);
15381        let buffer = self.buffer.read(cx).snapshot(cx);
15382        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15383            return;
15384        };
15385
15386        let diagnostic_group = buffer
15387            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15388            .collect::<Vec<_>>();
15389
15390        let blocks =
15391            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15392
15393        let blocks = self.display_map.update(cx, |display_map, cx| {
15394            display_map.insert_blocks(blocks, cx).into_iter().collect()
15395        });
15396        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15397            active_range: buffer.anchor_before(diagnostic.range.start)
15398                ..buffer.anchor_after(diagnostic.range.end),
15399            active_message: diagnostic.diagnostic.message.clone(),
15400            group_id: diagnostic.diagnostic.group_id,
15401            blocks,
15402        });
15403        cx.notify();
15404    }
15405
15406    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15407        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15408            return;
15409        };
15410
15411        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15412        if let ActiveDiagnostic::Group(group) = prev {
15413            self.display_map.update(cx, |display_map, cx| {
15414                display_map.remove_blocks(group.blocks, cx);
15415            });
15416            cx.notify();
15417        }
15418    }
15419
15420    /// Disable inline diagnostics rendering for this editor.
15421    pub fn disable_inline_diagnostics(&mut self) {
15422        self.inline_diagnostics_enabled = false;
15423        self.inline_diagnostics_update = Task::ready(());
15424        self.inline_diagnostics.clear();
15425    }
15426
15427    pub fn diagnostics_enabled(&self) -> bool {
15428        self.mode.is_full()
15429    }
15430
15431    pub fn inline_diagnostics_enabled(&self) -> bool {
15432        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15433    }
15434
15435    pub fn show_inline_diagnostics(&self) -> bool {
15436        self.show_inline_diagnostics
15437    }
15438
15439    pub fn toggle_inline_diagnostics(
15440        &mut self,
15441        _: &ToggleInlineDiagnostics,
15442        window: &mut Window,
15443        cx: &mut Context<Editor>,
15444    ) {
15445        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15446        self.refresh_inline_diagnostics(false, window, cx);
15447    }
15448
15449    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15450        self.diagnostics_max_severity = severity;
15451        self.display_map.update(cx, |display_map, _| {
15452            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15453        });
15454    }
15455
15456    pub fn toggle_diagnostics(
15457        &mut self,
15458        _: &ToggleDiagnostics,
15459        window: &mut Window,
15460        cx: &mut Context<Editor>,
15461    ) {
15462        if !self.diagnostics_enabled() {
15463            return;
15464        }
15465
15466        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15467            EditorSettings::get_global(cx)
15468                .diagnostics_max_severity
15469                .filter(|severity| severity != &DiagnosticSeverity::Off)
15470                .unwrap_or(DiagnosticSeverity::Hint)
15471        } else {
15472            DiagnosticSeverity::Off
15473        };
15474        self.set_max_diagnostics_severity(new_severity, cx);
15475        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15476            self.active_diagnostics = ActiveDiagnostic::None;
15477            self.inline_diagnostics_update = Task::ready(());
15478            self.inline_diagnostics.clear();
15479        } else {
15480            self.refresh_inline_diagnostics(false, window, cx);
15481        }
15482
15483        cx.notify();
15484    }
15485
15486    pub fn toggle_minimap(
15487        &mut self,
15488        _: &ToggleMinimap,
15489        window: &mut Window,
15490        cx: &mut Context<Editor>,
15491    ) {
15492        if self.supports_minimap(cx) {
15493            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15494        }
15495    }
15496
15497    fn refresh_inline_diagnostics(
15498        &mut self,
15499        debounce: bool,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) {
15503        let max_severity = ProjectSettings::get_global(cx)
15504            .diagnostics
15505            .inline
15506            .max_severity
15507            .unwrap_or(self.diagnostics_max_severity);
15508
15509        if !self.inline_diagnostics_enabled()
15510            || !self.show_inline_diagnostics
15511            || max_severity == DiagnosticSeverity::Off
15512        {
15513            self.inline_diagnostics_update = Task::ready(());
15514            self.inline_diagnostics.clear();
15515            return;
15516        }
15517
15518        let debounce_ms = ProjectSettings::get_global(cx)
15519            .diagnostics
15520            .inline
15521            .update_debounce_ms;
15522        let debounce = if debounce && debounce_ms > 0 {
15523            Some(Duration::from_millis(debounce_ms))
15524        } else {
15525            None
15526        };
15527        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15528            let editor = editor.upgrade().unwrap();
15529
15530            if let Some(debounce) = debounce {
15531                cx.background_executor().timer(debounce).await;
15532            }
15533            let Some(snapshot) = editor
15534                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15535                .ok()
15536            else {
15537                return;
15538            };
15539
15540            let new_inline_diagnostics = cx
15541                .background_spawn(async move {
15542                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15543                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15544                        let message = diagnostic_entry
15545                            .diagnostic
15546                            .message
15547                            .split_once('\n')
15548                            .map(|(line, _)| line)
15549                            .map(SharedString::new)
15550                            .unwrap_or_else(|| {
15551                                SharedString::from(diagnostic_entry.diagnostic.message)
15552                            });
15553                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15554                        let (Ok(i) | Err(i)) = inline_diagnostics
15555                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15556                        inline_diagnostics.insert(
15557                            i,
15558                            (
15559                                start_anchor,
15560                                InlineDiagnostic {
15561                                    message,
15562                                    group_id: diagnostic_entry.diagnostic.group_id,
15563                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15564                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15565                                    severity: diagnostic_entry.diagnostic.severity,
15566                                },
15567                            ),
15568                        );
15569                    }
15570                    inline_diagnostics
15571                })
15572                .await;
15573
15574            editor
15575                .update(cx, |editor, cx| {
15576                    editor.inline_diagnostics = new_inline_diagnostics;
15577                    cx.notify();
15578                })
15579                .ok();
15580        });
15581    }
15582
15583    pub fn set_selections_from_remote(
15584        &mut self,
15585        selections: Vec<Selection<Anchor>>,
15586        pending_selection: Option<Selection<Anchor>>,
15587        window: &mut Window,
15588        cx: &mut Context<Self>,
15589    ) {
15590        let old_cursor_position = self.selections.newest_anchor().head();
15591        self.selections.change_with(cx, |s| {
15592            s.select_anchors(selections);
15593            if let Some(pending_selection) = pending_selection {
15594                s.set_pending(pending_selection, SelectMode::Character);
15595            } else {
15596                s.clear_pending();
15597            }
15598        });
15599        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15600    }
15601
15602    fn push_to_selection_history(&mut self) {
15603        self.selection_history.push(SelectionHistoryEntry {
15604            selections: self.selections.disjoint_anchors(),
15605            select_next_state: self.select_next_state.clone(),
15606            select_prev_state: self.select_prev_state.clone(),
15607            add_selections_state: self.add_selections_state.clone(),
15608        });
15609    }
15610
15611    pub fn transact(
15612        &mut self,
15613        window: &mut Window,
15614        cx: &mut Context<Self>,
15615        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15616    ) -> Option<TransactionId> {
15617        self.start_transaction_at(Instant::now(), window, cx);
15618        update(self, window, cx);
15619        self.end_transaction_at(Instant::now(), cx)
15620    }
15621
15622    pub fn start_transaction_at(
15623        &mut self,
15624        now: Instant,
15625        window: &mut Window,
15626        cx: &mut Context<Self>,
15627    ) {
15628        self.end_selection(window, cx);
15629        if let Some(tx_id) = self
15630            .buffer
15631            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15632        {
15633            self.selection_history
15634                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15635            cx.emit(EditorEvent::TransactionBegun {
15636                transaction_id: tx_id,
15637            })
15638        }
15639    }
15640
15641    pub fn end_transaction_at(
15642        &mut self,
15643        now: Instant,
15644        cx: &mut Context<Self>,
15645    ) -> Option<TransactionId> {
15646        if let Some(transaction_id) = self
15647            .buffer
15648            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15649        {
15650            if let Some((_, end_selections)) =
15651                self.selection_history.transaction_mut(transaction_id)
15652            {
15653                *end_selections = Some(self.selections.disjoint_anchors());
15654            } else {
15655                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15656            }
15657
15658            cx.emit(EditorEvent::Edited { transaction_id });
15659            Some(transaction_id)
15660        } else {
15661            None
15662        }
15663    }
15664
15665    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15666        if self.selection_mark_mode {
15667            self.change_selections(None, window, cx, |s| {
15668                s.move_with(|_, sel| {
15669                    sel.collapse_to(sel.head(), SelectionGoal::None);
15670                });
15671            })
15672        }
15673        self.selection_mark_mode = true;
15674        cx.notify();
15675    }
15676
15677    pub fn swap_selection_ends(
15678        &mut self,
15679        _: &actions::SwapSelectionEnds,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) {
15683        self.change_selections(None, window, cx, |s| {
15684            s.move_with(|_, sel| {
15685                if sel.start != sel.end {
15686                    sel.reversed = !sel.reversed
15687                }
15688            });
15689        });
15690        self.request_autoscroll(Autoscroll::newest(), cx);
15691        cx.notify();
15692    }
15693
15694    pub fn toggle_fold(
15695        &mut self,
15696        _: &actions::ToggleFold,
15697        window: &mut Window,
15698        cx: &mut Context<Self>,
15699    ) {
15700        if self.is_singleton(cx) {
15701            let selection = self.selections.newest::<Point>(cx);
15702
15703            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15704            let range = if selection.is_empty() {
15705                let point = selection.head().to_display_point(&display_map);
15706                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15707                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15708                    .to_point(&display_map);
15709                start..end
15710            } else {
15711                selection.range()
15712            };
15713            if display_map.folds_in_range(range).next().is_some() {
15714                self.unfold_lines(&Default::default(), window, cx)
15715            } else {
15716                self.fold(&Default::default(), window, cx)
15717            }
15718        } else {
15719            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15720            let buffer_ids: HashSet<_> = self
15721                .selections
15722                .disjoint_anchor_ranges()
15723                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15724                .collect();
15725
15726            let should_unfold = buffer_ids
15727                .iter()
15728                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15729
15730            for buffer_id in buffer_ids {
15731                if should_unfold {
15732                    self.unfold_buffer(buffer_id, cx);
15733                } else {
15734                    self.fold_buffer(buffer_id, cx);
15735                }
15736            }
15737        }
15738    }
15739
15740    pub fn toggle_fold_recursive(
15741        &mut self,
15742        _: &actions::ToggleFoldRecursive,
15743        window: &mut Window,
15744        cx: &mut Context<Self>,
15745    ) {
15746        let selection = self.selections.newest::<Point>(cx);
15747
15748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15749        let range = if selection.is_empty() {
15750            let point = selection.head().to_display_point(&display_map);
15751            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15752            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15753                .to_point(&display_map);
15754            start..end
15755        } else {
15756            selection.range()
15757        };
15758        if display_map.folds_in_range(range).next().is_some() {
15759            self.unfold_recursive(&Default::default(), window, cx)
15760        } else {
15761            self.fold_recursive(&Default::default(), window, cx)
15762        }
15763    }
15764
15765    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15766        if self.is_singleton(cx) {
15767            let mut to_fold = Vec::new();
15768            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15769            let selections = self.selections.all_adjusted(cx);
15770
15771            for selection in selections {
15772                let range = selection.range().sorted();
15773                let buffer_start_row = range.start.row;
15774
15775                if range.start.row != range.end.row {
15776                    let mut found = false;
15777                    let mut row = range.start.row;
15778                    while row <= range.end.row {
15779                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15780                        {
15781                            found = true;
15782                            row = crease.range().end.row + 1;
15783                            to_fold.push(crease);
15784                        } else {
15785                            row += 1
15786                        }
15787                    }
15788                    if found {
15789                        continue;
15790                    }
15791                }
15792
15793                for row in (0..=range.start.row).rev() {
15794                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15795                        if crease.range().end.row >= buffer_start_row {
15796                            to_fold.push(crease);
15797                            if row <= range.start.row {
15798                                break;
15799                            }
15800                        }
15801                    }
15802                }
15803            }
15804
15805            self.fold_creases(to_fold, true, window, cx);
15806        } else {
15807            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15808            let buffer_ids = self
15809                .selections
15810                .disjoint_anchor_ranges()
15811                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15812                .collect::<HashSet<_>>();
15813            for buffer_id in buffer_ids {
15814                self.fold_buffer(buffer_id, cx);
15815            }
15816        }
15817    }
15818
15819    fn fold_at_level(
15820        &mut self,
15821        fold_at: &FoldAtLevel,
15822        window: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        if !self.buffer.read(cx).is_singleton() {
15826            return;
15827        }
15828
15829        let fold_at_level = fold_at.0;
15830        let snapshot = self.buffer.read(cx).snapshot(cx);
15831        let mut to_fold = Vec::new();
15832        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15833
15834        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15835            while start_row < end_row {
15836                match self
15837                    .snapshot(window, cx)
15838                    .crease_for_buffer_row(MultiBufferRow(start_row))
15839                {
15840                    Some(crease) => {
15841                        let nested_start_row = crease.range().start.row + 1;
15842                        let nested_end_row = crease.range().end.row;
15843
15844                        if current_level < fold_at_level {
15845                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15846                        } else if current_level == fold_at_level {
15847                            to_fold.push(crease);
15848                        }
15849
15850                        start_row = nested_end_row + 1;
15851                    }
15852                    None => start_row += 1,
15853                }
15854            }
15855        }
15856
15857        self.fold_creases(to_fold, true, window, cx);
15858    }
15859
15860    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15861        if self.buffer.read(cx).is_singleton() {
15862            let mut fold_ranges = Vec::new();
15863            let snapshot = self.buffer.read(cx).snapshot(cx);
15864
15865            for row in 0..snapshot.max_row().0 {
15866                if let Some(foldable_range) = self
15867                    .snapshot(window, cx)
15868                    .crease_for_buffer_row(MultiBufferRow(row))
15869                {
15870                    fold_ranges.push(foldable_range);
15871                }
15872            }
15873
15874            self.fold_creases(fold_ranges, true, window, cx);
15875        } else {
15876            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15877                editor
15878                    .update_in(cx, |editor, _, cx| {
15879                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15880                            editor.fold_buffer(buffer_id, cx);
15881                        }
15882                    })
15883                    .ok();
15884            });
15885        }
15886    }
15887
15888    pub fn fold_function_bodies(
15889        &mut self,
15890        _: &actions::FoldFunctionBodies,
15891        window: &mut Window,
15892        cx: &mut Context<Self>,
15893    ) {
15894        let snapshot = self.buffer.read(cx).snapshot(cx);
15895
15896        let ranges = snapshot
15897            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15898            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15899            .collect::<Vec<_>>();
15900
15901        let creases = ranges
15902            .into_iter()
15903            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15904            .collect();
15905
15906        self.fold_creases(creases, true, window, cx);
15907    }
15908
15909    pub fn fold_recursive(
15910        &mut self,
15911        _: &actions::FoldRecursive,
15912        window: &mut Window,
15913        cx: &mut Context<Self>,
15914    ) {
15915        let mut to_fold = Vec::new();
15916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15917        let selections = self.selections.all_adjusted(cx);
15918
15919        for selection in selections {
15920            let range = selection.range().sorted();
15921            let buffer_start_row = range.start.row;
15922
15923            if range.start.row != range.end.row {
15924                let mut found = false;
15925                for row in range.start.row..=range.end.row {
15926                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15927                        found = true;
15928                        to_fold.push(crease);
15929                    }
15930                }
15931                if found {
15932                    continue;
15933                }
15934            }
15935
15936            for row in (0..=range.start.row).rev() {
15937                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15938                    if crease.range().end.row >= buffer_start_row {
15939                        to_fold.push(crease);
15940                    } else {
15941                        break;
15942                    }
15943                }
15944            }
15945        }
15946
15947        self.fold_creases(to_fold, true, window, cx);
15948    }
15949
15950    pub fn fold_at(
15951        &mut self,
15952        buffer_row: MultiBufferRow,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) {
15956        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15957
15958        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15959            let autoscroll = self
15960                .selections
15961                .all::<Point>(cx)
15962                .iter()
15963                .any(|selection| crease.range().overlaps(&selection.range()));
15964
15965            self.fold_creases(vec![crease], autoscroll, window, cx);
15966        }
15967    }
15968
15969    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15970        if self.is_singleton(cx) {
15971            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15972            let buffer = &display_map.buffer_snapshot;
15973            let selections = self.selections.all::<Point>(cx);
15974            let ranges = selections
15975                .iter()
15976                .map(|s| {
15977                    let range = s.display_range(&display_map).sorted();
15978                    let mut start = range.start.to_point(&display_map);
15979                    let mut end = range.end.to_point(&display_map);
15980                    start.column = 0;
15981                    end.column = buffer.line_len(MultiBufferRow(end.row));
15982                    start..end
15983                })
15984                .collect::<Vec<_>>();
15985
15986            self.unfold_ranges(&ranges, true, true, cx);
15987        } else {
15988            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15989            let buffer_ids = self
15990                .selections
15991                .disjoint_anchor_ranges()
15992                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15993                .collect::<HashSet<_>>();
15994            for buffer_id in buffer_ids {
15995                self.unfold_buffer(buffer_id, cx);
15996            }
15997        }
15998    }
15999
16000    pub fn unfold_recursive(
16001        &mut self,
16002        _: &UnfoldRecursive,
16003        _window: &mut Window,
16004        cx: &mut Context<Self>,
16005    ) {
16006        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16007        let selections = self.selections.all::<Point>(cx);
16008        let ranges = selections
16009            .iter()
16010            .map(|s| {
16011                let mut range = s.display_range(&display_map).sorted();
16012                *range.start.column_mut() = 0;
16013                *range.end.column_mut() = display_map.line_len(range.end.row());
16014                let start = range.start.to_point(&display_map);
16015                let end = range.end.to_point(&display_map);
16016                start..end
16017            })
16018            .collect::<Vec<_>>();
16019
16020        self.unfold_ranges(&ranges, true, true, cx);
16021    }
16022
16023    pub fn unfold_at(
16024        &mut self,
16025        buffer_row: MultiBufferRow,
16026        _window: &mut Window,
16027        cx: &mut Context<Self>,
16028    ) {
16029        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16030
16031        let intersection_range = Point::new(buffer_row.0, 0)
16032            ..Point::new(
16033                buffer_row.0,
16034                display_map.buffer_snapshot.line_len(buffer_row),
16035            );
16036
16037        let autoscroll = self
16038            .selections
16039            .all::<Point>(cx)
16040            .iter()
16041            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16042
16043        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16044    }
16045
16046    pub fn unfold_all(
16047        &mut self,
16048        _: &actions::UnfoldAll,
16049        _window: &mut Window,
16050        cx: &mut Context<Self>,
16051    ) {
16052        if self.buffer.read(cx).is_singleton() {
16053            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16054            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16055        } else {
16056            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16057                editor
16058                    .update(cx, |editor, cx| {
16059                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16060                            editor.unfold_buffer(buffer_id, cx);
16061                        }
16062                    })
16063                    .ok();
16064            });
16065        }
16066    }
16067
16068    pub fn fold_selected_ranges(
16069        &mut self,
16070        _: &FoldSelectedRanges,
16071        window: &mut Window,
16072        cx: &mut Context<Self>,
16073    ) {
16074        let selections = self.selections.all_adjusted(cx);
16075        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16076        let ranges = selections
16077            .into_iter()
16078            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16079            .collect::<Vec<_>>();
16080        self.fold_creases(ranges, true, window, cx);
16081    }
16082
16083    pub fn fold_ranges<T: ToOffset + Clone>(
16084        &mut self,
16085        ranges: Vec<Range<T>>,
16086        auto_scroll: bool,
16087        window: &mut Window,
16088        cx: &mut Context<Self>,
16089    ) {
16090        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16091        let ranges = ranges
16092            .into_iter()
16093            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16094            .collect::<Vec<_>>();
16095        self.fold_creases(ranges, auto_scroll, window, cx);
16096    }
16097
16098    pub fn fold_creases<T: ToOffset + Clone>(
16099        &mut self,
16100        creases: Vec<Crease<T>>,
16101        auto_scroll: bool,
16102        _window: &mut Window,
16103        cx: &mut Context<Self>,
16104    ) {
16105        if creases.is_empty() {
16106            return;
16107        }
16108
16109        let mut buffers_affected = HashSet::default();
16110        let multi_buffer = self.buffer().read(cx);
16111        for crease in &creases {
16112            if let Some((_, buffer, _)) =
16113                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16114            {
16115                buffers_affected.insert(buffer.read(cx).remote_id());
16116            };
16117        }
16118
16119        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16120
16121        if auto_scroll {
16122            self.request_autoscroll(Autoscroll::fit(), cx);
16123        }
16124
16125        cx.notify();
16126
16127        self.scrollbar_marker_state.dirty = true;
16128        self.folds_did_change(cx);
16129    }
16130
16131    /// Removes any folds whose ranges intersect any of the given ranges.
16132    pub fn unfold_ranges<T: ToOffset + Clone>(
16133        &mut self,
16134        ranges: &[Range<T>],
16135        inclusive: bool,
16136        auto_scroll: bool,
16137        cx: &mut Context<Self>,
16138    ) {
16139        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16140            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16141        });
16142        self.folds_did_change(cx);
16143    }
16144
16145    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16146        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16147            return;
16148        }
16149        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16150        self.display_map.update(cx, |display_map, cx| {
16151            display_map.fold_buffers([buffer_id], cx)
16152        });
16153        cx.emit(EditorEvent::BufferFoldToggled {
16154            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16155            folded: true,
16156        });
16157        cx.notify();
16158    }
16159
16160    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16161        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16162            return;
16163        }
16164        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16165        self.display_map.update(cx, |display_map, cx| {
16166            display_map.unfold_buffers([buffer_id], cx);
16167        });
16168        cx.emit(EditorEvent::BufferFoldToggled {
16169            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16170            folded: false,
16171        });
16172        cx.notify();
16173    }
16174
16175    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16176        self.display_map.read(cx).is_buffer_folded(buffer)
16177    }
16178
16179    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16180        self.display_map.read(cx).folded_buffers()
16181    }
16182
16183    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16184        self.display_map.update(cx, |display_map, cx| {
16185            display_map.disable_header_for_buffer(buffer_id, cx);
16186        });
16187        cx.notify();
16188    }
16189
16190    /// Removes any folds with the given ranges.
16191    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16192        &mut self,
16193        ranges: &[Range<T>],
16194        type_id: TypeId,
16195        auto_scroll: bool,
16196        cx: &mut Context<Self>,
16197    ) {
16198        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16199            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16200        });
16201        self.folds_did_change(cx);
16202    }
16203
16204    fn remove_folds_with<T: ToOffset + Clone>(
16205        &mut self,
16206        ranges: &[Range<T>],
16207        auto_scroll: bool,
16208        cx: &mut Context<Self>,
16209        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16210    ) {
16211        if ranges.is_empty() {
16212            return;
16213        }
16214
16215        let mut buffers_affected = HashSet::default();
16216        let multi_buffer = self.buffer().read(cx);
16217        for range in ranges {
16218            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16219                buffers_affected.insert(buffer.read(cx).remote_id());
16220            };
16221        }
16222
16223        self.display_map.update(cx, update);
16224
16225        if auto_scroll {
16226            self.request_autoscroll(Autoscroll::fit(), cx);
16227        }
16228
16229        cx.notify();
16230        self.scrollbar_marker_state.dirty = true;
16231        self.active_indent_guides_state.dirty = true;
16232    }
16233
16234    pub fn update_fold_widths(
16235        &mut self,
16236        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16237        cx: &mut Context<Self>,
16238    ) -> bool {
16239        self.display_map
16240            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16241    }
16242
16243    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16244        self.display_map.read(cx).fold_placeholder.clone()
16245    }
16246
16247    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16248        self.buffer.update(cx, |buffer, cx| {
16249            buffer.set_all_diff_hunks_expanded(cx);
16250        });
16251    }
16252
16253    pub fn expand_all_diff_hunks(
16254        &mut self,
16255        _: &ExpandAllDiffHunks,
16256        _window: &mut Window,
16257        cx: &mut Context<Self>,
16258    ) {
16259        self.buffer.update(cx, |buffer, cx| {
16260            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16261        });
16262    }
16263
16264    pub fn toggle_selected_diff_hunks(
16265        &mut self,
16266        _: &ToggleSelectedDiffHunks,
16267        _window: &mut Window,
16268        cx: &mut Context<Self>,
16269    ) {
16270        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16271        self.toggle_diff_hunks_in_ranges(ranges, cx);
16272    }
16273
16274    pub fn diff_hunks_in_ranges<'a>(
16275        &'a self,
16276        ranges: &'a [Range<Anchor>],
16277        buffer: &'a MultiBufferSnapshot,
16278    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16279        ranges.iter().flat_map(move |range| {
16280            let end_excerpt_id = range.end.excerpt_id;
16281            let range = range.to_point(buffer);
16282            let mut peek_end = range.end;
16283            if range.end.row < buffer.max_row().0 {
16284                peek_end = Point::new(range.end.row + 1, 0);
16285            }
16286            buffer
16287                .diff_hunks_in_range(range.start..peek_end)
16288                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16289        })
16290    }
16291
16292    pub fn has_stageable_diff_hunks_in_ranges(
16293        &self,
16294        ranges: &[Range<Anchor>],
16295        snapshot: &MultiBufferSnapshot,
16296    ) -> bool {
16297        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16298        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16299    }
16300
16301    pub fn toggle_staged_selected_diff_hunks(
16302        &mut self,
16303        _: &::git::ToggleStaged,
16304        _: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) {
16307        let snapshot = self.buffer.read(cx).snapshot(cx);
16308        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16309        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16310        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16311    }
16312
16313    pub fn set_render_diff_hunk_controls(
16314        &mut self,
16315        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16316        cx: &mut Context<Self>,
16317    ) {
16318        self.render_diff_hunk_controls = render_diff_hunk_controls;
16319        cx.notify();
16320    }
16321
16322    pub fn stage_and_next(
16323        &mut self,
16324        _: &::git::StageAndNext,
16325        window: &mut Window,
16326        cx: &mut Context<Self>,
16327    ) {
16328        self.do_stage_or_unstage_and_next(true, window, cx);
16329    }
16330
16331    pub fn unstage_and_next(
16332        &mut self,
16333        _: &::git::UnstageAndNext,
16334        window: &mut Window,
16335        cx: &mut Context<Self>,
16336    ) {
16337        self.do_stage_or_unstage_and_next(false, window, cx);
16338    }
16339
16340    pub fn stage_or_unstage_diff_hunks(
16341        &mut self,
16342        stage: bool,
16343        ranges: Vec<Range<Anchor>>,
16344        cx: &mut Context<Self>,
16345    ) {
16346        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16347        cx.spawn(async move |this, cx| {
16348            task.await?;
16349            this.update(cx, |this, cx| {
16350                let snapshot = this.buffer.read(cx).snapshot(cx);
16351                let chunk_by = this
16352                    .diff_hunks_in_ranges(&ranges, &snapshot)
16353                    .chunk_by(|hunk| hunk.buffer_id);
16354                for (buffer_id, hunks) in &chunk_by {
16355                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16356                }
16357            })
16358        })
16359        .detach_and_log_err(cx);
16360    }
16361
16362    fn save_buffers_for_ranges_if_needed(
16363        &mut self,
16364        ranges: &[Range<Anchor>],
16365        cx: &mut Context<Editor>,
16366    ) -> Task<Result<()>> {
16367        let multibuffer = self.buffer.read(cx);
16368        let snapshot = multibuffer.read(cx);
16369        let buffer_ids: HashSet<_> = ranges
16370            .iter()
16371            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16372            .collect();
16373        drop(snapshot);
16374
16375        let mut buffers = HashSet::default();
16376        for buffer_id in buffer_ids {
16377            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16378                let buffer = buffer_entity.read(cx);
16379                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16380                {
16381                    buffers.insert(buffer_entity);
16382                }
16383            }
16384        }
16385
16386        if let Some(project) = &self.project {
16387            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16388        } else {
16389            Task::ready(Ok(()))
16390        }
16391    }
16392
16393    fn do_stage_or_unstage_and_next(
16394        &mut self,
16395        stage: bool,
16396        window: &mut Window,
16397        cx: &mut Context<Self>,
16398    ) {
16399        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16400
16401        if ranges.iter().any(|range| range.start != range.end) {
16402            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16403            return;
16404        }
16405
16406        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16407        let snapshot = self.snapshot(window, cx);
16408        let position = self.selections.newest::<Point>(cx).head();
16409        let mut row = snapshot
16410            .buffer_snapshot
16411            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16412            .find(|hunk| hunk.row_range.start.0 > position.row)
16413            .map(|hunk| hunk.row_range.start);
16414
16415        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16416        // Outside of the project diff editor, wrap around to the beginning.
16417        if !all_diff_hunks_expanded {
16418            row = row.or_else(|| {
16419                snapshot
16420                    .buffer_snapshot
16421                    .diff_hunks_in_range(Point::zero()..position)
16422                    .find(|hunk| hunk.row_range.end.0 < position.row)
16423                    .map(|hunk| hunk.row_range.start)
16424            });
16425        }
16426
16427        if let Some(row) = row {
16428            let destination = Point::new(row.0, 0);
16429            let autoscroll = Autoscroll::center();
16430
16431            self.unfold_ranges(&[destination..destination], false, false, cx);
16432            self.change_selections(Some(autoscroll), window, cx, |s| {
16433                s.select_ranges([destination..destination]);
16434            });
16435        }
16436    }
16437
16438    fn do_stage_or_unstage(
16439        &self,
16440        stage: bool,
16441        buffer_id: BufferId,
16442        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16443        cx: &mut App,
16444    ) -> Option<()> {
16445        let project = self.project.as_ref()?;
16446        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16447        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16448        let buffer_snapshot = buffer.read(cx).snapshot();
16449        let file_exists = buffer_snapshot
16450            .file()
16451            .is_some_and(|file| file.disk_state().exists());
16452        diff.update(cx, |diff, cx| {
16453            diff.stage_or_unstage_hunks(
16454                stage,
16455                &hunks
16456                    .map(|hunk| buffer_diff::DiffHunk {
16457                        buffer_range: hunk.buffer_range,
16458                        diff_base_byte_range: hunk.diff_base_byte_range,
16459                        secondary_status: hunk.secondary_status,
16460                        range: Point::zero()..Point::zero(), // unused
16461                    })
16462                    .collect::<Vec<_>>(),
16463                &buffer_snapshot,
16464                file_exists,
16465                cx,
16466            )
16467        });
16468        None
16469    }
16470
16471    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16472        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16473        self.buffer
16474            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16475    }
16476
16477    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16478        self.buffer.update(cx, |buffer, cx| {
16479            let ranges = vec![Anchor::min()..Anchor::max()];
16480            if !buffer.all_diff_hunks_expanded()
16481                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16482            {
16483                buffer.collapse_diff_hunks(ranges, cx);
16484                true
16485            } else {
16486                false
16487            }
16488        })
16489    }
16490
16491    fn toggle_diff_hunks_in_ranges(
16492        &mut self,
16493        ranges: Vec<Range<Anchor>>,
16494        cx: &mut Context<Editor>,
16495    ) {
16496        self.buffer.update(cx, |buffer, cx| {
16497            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16498            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16499        })
16500    }
16501
16502    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16503        self.buffer.update(cx, |buffer, cx| {
16504            let snapshot = buffer.snapshot(cx);
16505            let excerpt_id = range.end.excerpt_id;
16506            let point_range = range.to_point(&snapshot);
16507            let expand = !buffer.single_hunk_is_expanded(range, cx);
16508            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16509        })
16510    }
16511
16512    pub(crate) fn apply_all_diff_hunks(
16513        &mut self,
16514        _: &ApplyAllDiffHunks,
16515        window: &mut Window,
16516        cx: &mut Context<Self>,
16517    ) {
16518        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16519
16520        let buffers = self.buffer.read(cx).all_buffers();
16521        for branch_buffer in buffers {
16522            branch_buffer.update(cx, |branch_buffer, cx| {
16523                branch_buffer.merge_into_base(Vec::new(), cx);
16524            });
16525        }
16526
16527        if let Some(project) = self.project.clone() {
16528            self.save(true, project, window, cx).detach_and_log_err(cx);
16529        }
16530    }
16531
16532    pub(crate) fn apply_selected_diff_hunks(
16533        &mut self,
16534        _: &ApplyDiffHunk,
16535        window: &mut Window,
16536        cx: &mut Context<Self>,
16537    ) {
16538        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16539        let snapshot = self.snapshot(window, cx);
16540        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16541        let mut ranges_by_buffer = HashMap::default();
16542        self.transact(window, cx, |editor, _window, cx| {
16543            for hunk in hunks {
16544                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16545                    ranges_by_buffer
16546                        .entry(buffer.clone())
16547                        .or_insert_with(Vec::new)
16548                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16549                }
16550            }
16551
16552            for (buffer, ranges) in ranges_by_buffer {
16553                buffer.update(cx, |buffer, cx| {
16554                    buffer.merge_into_base(ranges, cx);
16555                });
16556            }
16557        });
16558
16559        if let Some(project) = self.project.clone() {
16560            self.save(true, project, window, cx).detach_and_log_err(cx);
16561        }
16562    }
16563
16564    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16565        if hovered != self.gutter_hovered {
16566            self.gutter_hovered = hovered;
16567            cx.notify();
16568        }
16569    }
16570
16571    pub fn insert_blocks(
16572        &mut self,
16573        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16574        autoscroll: Option<Autoscroll>,
16575        cx: &mut Context<Self>,
16576    ) -> Vec<CustomBlockId> {
16577        let blocks = self
16578            .display_map
16579            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16580        if let Some(autoscroll) = autoscroll {
16581            self.request_autoscroll(autoscroll, cx);
16582        }
16583        cx.notify();
16584        blocks
16585    }
16586
16587    pub fn resize_blocks(
16588        &mut self,
16589        heights: HashMap<CustomBlockId, u32>,
16590        autoscroll: Option<Autoscroll>,
16591        cx: &mut Context<Self>,
16592    ) {
16593        self.display_map
16594            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16595        if let Some(autoscroll) = autoscroll {
16596            self.request_autoscroll(autoscroll, cx);
16597        }
16598        cx.notify();
16599    }
16600
16601    pub fn replace_blocks(
16602        &mut self,
16603        renderers: HashMap<CustomBlockId, RenderBlock>,
16604        autoscroll: Option<Autoscroll>,
16605        cx: &mut Context<Self>,
16606    ) {
16607        self.display_map
16608            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16609        if let Some(autoscroll) = autoscroll {
16610            self.request_autoscroll(autoscroll, cx);
16611        }
16612        cx.notify();
16613    }
16614
16615    pub fn remove_blocks(
16616        &mut self,
16617        block_ids: HashSet<CustomBlockId>,
16618        autoscroll: Option<Autoscroll>,
16619        cx: &mut Context<Self>,
16620    ) {
16621        self.display_map.update(cx, |display_map, cx| {
16622            display_map.remove_blocks(block_ids, cx)
16623        });
16624        if let Some(autoscroll) = autoscroll {
16625            self.request_autoscroll(autoscroll, cx);
16626        }
16627        cx.notify();
16628    }
16629
16630    pub fn row_for_block(
16631        &self,
16632        block_id: CustomBlockId,
16633        cx: &mut Context<Self>,
16634    ) -> Option<DisplayRow> {
16635        self.display_map
16636            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16637    }
16638
16639    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16640        self.focused_block = Some(focused_block);
16641    }
16642
16643    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16644        self.focused_block.take()
16645    }
16646
16647    pub fn insert_creases(
16648        &mut self,
16649        creases: impl IntoIterator<Item = Crease<Anchor>>,
16650        cx: &mut Context<Self>,
16651    ) -> Vec<CreaseId> {
16652        self.display_map
16653            .update(cx, |map, cx| map.insert_creases(creases, cx))
16654    }
16655
16656    pub fn remove_creases(
16657        &mut self,
16658        ids: impl IntoIterator<Item = CreaseId>,
16659        cx: &mut Context<Self>,
16660    ) -> Vec<(CreaseId, Range<Anchor>)> {
16661        self.display_map
16662            .update(cx, |map, cx| map.remove_creases(ids, cx))
16663    }
16664
16665    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16666        self.display_map
16667            .update(cx, |map, cx| map.snapshot(cx))
16668            .longest_row()
16669    }
16670
16671    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16672        self.display_map
16673            .update(cx, |map, cx| map.snapshot(cx))
16674            .max_point()
16675    }
16676
16677    pub fn text(&self, cx: &App) -> String {
16678        self.buffer.read(cx).read(cx).text()
16679    }
16680
16681    pub fn is_empty(&self, cx: &App) -> bool {
16682        self.buffer.read(cx).read(cx).is_empty()
16683    }
16684
16685    pub fn text_option(&self, cx: &App) -> Option<String> {
16686        let text = self.text(cx);
16687        let text = text.trim();
16688
16689        if text.is_empty() {
16690            return None;
16691        }
16692
16693        Some(text.to_string())
16694    }
16695
16696    pub fn set_text(
16697        &mut self,
16698        text: impl Into<Arc<str>>,
16699        window: &mut Window,
16700        cx: &mut Context<Self>,
16701    ) {
16702        self.transact(window, cx, |this, _, cx| {
16703            this.buffer
16704                .read(cx)
16705                .as_singleton()
16706                .expect("you can only call set_text on editors for singleton buffers")
16707                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16708        });
16709    }
16710
16711    pub fn display_text(&self, cx: &mut App) -> String {
16712        self.display_map
16713            .update(cx, |map, cx| map.snapshot(cx))
16714            .text()
16715    }
16716
16717    fn create_minimap(
16718        &self,
16719        minimap_settings: MinimapSettings,
16720        window: &mut Window,
16721        cx: &mut Context<Self>,
16722    ) -> Option<Entity<Self>> {
16723        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16724            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16725    }
16726
16727    fn initialize_new_minimap(
16728        &self,
16729        minimap_settings: MinimapSettings,
16730        window: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) -> Entity<Self> {
16733        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16734
16735        let mut minimap = Editor::new_internal(
16736            EditorMode::Minimap {
16737                parent: cx.weak_entity(),
16738            },
16739            self.buffer.clone(),
16740            self.project.clone(),
16741            Some(self.display_map.clone()),
16742            window,
16743            cx,
16744        );
16745        minimap.scroll_manager.clone_state(&self.scroll_manager);
16746        minimap.set_text_style_refinement(TextStyleRefinement {
16747            font_size: Some(MINIMAP_FONT_SIZE),
16748            font_weight: Some(MINIMAP_FONT_WEIGHT),
16749            ..Default::default()
16750        });
16751        minimap.update_minimap_configuration(minimap_settings, cx);
16752        cx.new(|_| minimap)
16753    }
16754
16755    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16756        let current_line_highlight = minimap_settings
16757            .current_line_highlight
16758            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16759        self.set_current_line_highlight(Some(current_line_highlight));
16760    }
16761
16762    pub fn minimap(&self) -> Option<&Entity<Self>> {
16763        self.minimap
16764            .as_ref()
16765            .filter(|_| self.minimap_visibility.visible())
16766    }
16767
16768    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16769        let mut wrap_guides = smallvec![];
16770
16771        if self.show_wrap_guides == Some(false) {
16772            return wrap_guides;
16773        }
16774
16775        let settings = self.buffer.read(cx).language_settings(cx);
16776        if settings.show_wrap_guides {
16777            match self.soft_wrap_mode(cx) {
16778                SoftWrap::Column(soft_wrap) => {
16779                    wrap_guides.push((soft_wrap as usize, true));
16780                }
16781                SoftWrap::Bounded(soft_wrap) => {
16782                    wrap_guides.push((soft_wrap as usize, true));
16783                }
16784                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16785            }
16786            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16787        }
16788
16789        wrap_guides
16790    }
16791
16792    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16793        let settings = self.buffer.read(cx).language_settings(cx);
16794        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16795        match mode {
16796            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16797                SoftWrap::None
16798            }
16799            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16800            language_settings::SoftWrap::PreferredLineLength => {
16801                SoftWrap::Column(settings.preferred_line_length)
16802            }
16803            language_settings::SoftWrap::Bounded => {
16804                SoftWrap::Bounded(settings.preferred_line_length)
16805            }
16806        }
16807    }
16808
16809    pub fn set_soft_wrap_mode(
16810        &mut self,
16811        mode: language_settings::SoftWrap,
16812
16813        cx: &mut Context<Self>,
16814    ) {
16815        self.soft_wrap_mode_override = Some(mode);
16816        cx.notify();
16817    }
16818
16819    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16820        self.hard_wrap = hard_wrap;
16821        cx.notify();
16822    }
16823
16824    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16825        self.text_style_refinement = Some(style);
16826    }
16827
16828    /// called by the Element so we know what style we were most recently rendered with.
16829    pub(crate) fn set_style(
16830        &mut self,
16831        style: EditorStyle,
16832        window: &mut Window,
16833        cx: &mut Context<Self>,
16834    ) {
16835        // We intentionally do not inform the display map about the minimap style
16836        // so that wrapping is not recalculated and stays consistent for the editor
16837        // and its linked minimap.
16838        if !self.mode.is_minimap() {
16839            let rem_size = window.rem_size();
16840            self.display_map.update(cx, |map, cx| {
16841                map.set_font(
16842                    style.text.font(),
16843                    style.text.font_size.to_pixels(rem_size),
16844                    cx,
16845                )
16846            });
16847        }
16848        self.style = Some(style);
16849    }
16850
16851    pub fn style(&self) -> Option<&EditorStyle> {
16852        self.style.as_ref()
16853    }
16854
16855    // Called by the element. This method is not designed to be called outside of the editor
16856    // element's layout code because it does not notify when rewrapping is computed synchronously.
16857    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16858        self.display_map
16859            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16860    }
16861
16862    pub fn set_soft_wrap(&mut self) {
16863        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16864    }
16865
16866    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16867        if self.soft_wrap_mode_override.is_some() {
16868            self.soft_wrap_mode_override.take();
16869        } else {
16870            let soft_wrap = match self.soft_wrap_mode(cx) {
16871                SoftWrap::GitDiff => return,
16872                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16873                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16874                    language_settings::SoftWrap::None
16875                }
16876            };
16877            self.soft_wrap_mode_override = Some(soft_wrap);
16878        }
16879        cx.notify();
16880    }
16881
16882    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16883        let Some(workspace) = self.workspace() else {
16884            return;
16885        };
16886        let fs = workspace.read(cx).app_state().fs.clone();
16887        let current_show = TabBarSettings::get_global(cx).show;
16888        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16889            setting.show = Some(!current_show);
16890        });
16891    }
16892
16893    pub fn toggle_indent_guides(
16894        &mut self,
16895        _: &ToggleIndentGuides,
16896        _: &mut Window,
16897        cx: &mut Context<Self>,
16898    ) {
16899        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16900            self.buffer
16901                .read(cx)
16902                .language_settings(cx)
16903                .indent_guides
16904                .enabled
16905        });
16906        self.show_indent_guides = Some(!currently_enabled);
16907        cx.notify();
16908    }
16909
16910    fn should_show_indent_guides(&self) -> Option<bool> {
16911        self.show_indent_guides
16912    }
16913
16914    pub fn toggle_line_numbers(
16915        &mut self,
16916        _: &ToggleLineNumbers,
16917        _: &mut Window,
16918        cx: &mut Context<Self>,
16919    ) {
16920        let mut editor_settings = EditorSettings::get_global(cx).clone();
16921        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16922        EditorSettings::override_global(editor_settings, cx);
16923    }
16924
16925    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16926        if let Some(show_line_numbers) = self.show_line_numbers {
16927            return show_line_numbers;
16928        }
16929        EditorSettings::get_global(cx).gutter.line_numbers
16930    }
16931
16932    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16933        self.use_relative_line_numbers
16934            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16935    }
16936
16937    pub fn toggle_relative_line_numbers(
16938        &mut self,
16939        _: &ToggleRelativeLineNumbers,
16940        _: &mut Window,
16941        cx: &mut Context<Self>,
16942    ) {
16943        let is_relative = self.should_use_relative_line_numbers(cx);
16944        self.set_relative_line_number(Some(!is_relative), cx)
16945    }
16946
16947    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16948        self.use_relative_line_numbers = is_relative;
16949        cx.notify();
16950    }
16951
16952    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16953        self.show_gutter = show_gutter;
16954        cx.notify();
16955    }
16956
16957    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16958        self.show_scrollbars = show_scrollbars;
16959        cx.notify();
16960    }
16961
16962    pub fn set_minimap_visibility(
16963        &mut self,
16964        minimap_visibility: MinimapVisibility,
16965        window: &mut Window,
16966        cx: &mut Context<Self>,
16967    ) {
16968        if self.minimap_visibility != minimap_visibility {
16969            if minimap_visibility.visible() && self.minimap.is_none() {
16970                let minimap_settings = EditorSettings::get_global(cx).minimap;
16971                self.minimap =
16972                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16973            }
16974            self.minimap_visibility = minimap_visibility;
16975            cx.notify();
16976        }
16977    }
16978
16979    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16980        self.set_show_scrollbars(false, cx);
16981        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16982    }
16983
16984    /// Normally the text in full mode and auto height editors is padded on the
16985    /// left side by roughly half a character width for improved hit testing.
16986    ///
16987    /// Use this method to disable this for cases where this is not wanted (e.g.
16988    /// if you want to align the editor text with some other text above or below)
16989    /// or if you want to add this padding to single-line editors.
16990    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
16991        self.offset_content = offset_content;
16992        cx.notify();
16993    }
16994
16995    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16996        self.show_line_numbers = Some(show_line_numbers);
16997        cx.notify();
16998    }
16999
17000    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17001        self.disable_expand_excerpt_buttons = true;
17002        cx.notify();
17003    }
17004
17005    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17006        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17007        cx.notify();
17008    }
17009
17010    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17011        self.show_code_actions = Some(show_code_actions);
17012        cx.notify();
17013    }
17014
17015    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17016        self.show_runnables = Some(show_runnables);
17017        cx.notify();
17018    }
17019
17020    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17021        self.show_breakpoints = Some(show_breakpoints);
17022        cx.notify();
17023    }
17024
17025    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17026        if self.display_map.read(cx).masked != masked {
17027            self.display_map.update(cx, |map, _| map.masked = masked);
17028        }
17029        cx.notify()
17030    }
17031
17032    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17033        self.show_wrap_guides = Some(show_wrap_guides);
17034        cx.notify();
17035    }
17036
17037    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17038        self.show_indent_guides = Some(show_indent_guides);
17039        cx.notify();
17040    }
17041
17042    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17043        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17044            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17045                if let Some(dir) = file.abs_path(cx).parent() {
17046                    return Some(dir.to_owned());
17047                }
17048            }
17049
17050            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17051                return Some(project_path.path.to_path_buf());
17052            }
17053        }
17054
17055        None
17056    }
17057
17058    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17059        self.active_excerpt(cx)?
17060            .1
17061            .read(cx)
17062            .file()
17063            .and_then(|f| f.as_local())
17064    }
17065
17066    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17067        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17068            let buffer = buffer.read(cx);
17069            if let Some(project_path) = buffer.project_path(cx) {
17070                let project = self.project.as_ref()?.read(cx);
17071                project.absolute_path(&project_path, cx)
17072            } else {
17073                buffer
17074                    .file()
17075                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17076            }
17077        })
17078    }
17079
17080    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17081        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17082            let project_path = buffer.read(cx).project_path(cx)?;
17083            let project = self.project.as_ref()?.read(cx);
17084            let entry = project.entry_for_path(&project_path, cx)?;
17085            let path = entry.path.to_path_buf();
17086            Some(path)
17087        })
17088    }
17089
17090    pub fn reveal_in_finder(
17091        &mut self,
17092        _: &RevealInFileManager,
17093        _window: &mut Window,
17094        cx: &mut Context<Self>,
17095    ) {
17096        if let Some(target) = self.target_file(cx) {
17097            cx.reveal_path(&target.abs_path(cx));
17098        }
17099    }
17100
17101    pub fn copy_path(
17102        &mut self,
17103        _: &zed_actions::workspace::CopyPath,
17104        _window: &mut Window,
17105        cx: &mut Context<Self>,
17106    ) {
17107        if let Some(path) = self.target_file_abs_path(cx) {
17108            if let Some(path) = path.to_str() {
17109                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17110            }
17111        }
17112    }
17113
17114    pub fn copy_relative_path(
17115        &mut self,
17116        _: &zed_actions::workspace::CopyRelativePath,
17117        _window: &mut Window,
17118        cx: &mut Context<Self>,
17119    ) {
17120        if let Some(path) = self.target_file_path(cx) {
17121            if let Some(path) = path.to_str() {
17122                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17123            }
17124        }
17125    }
17126
17127    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17128        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17129            buffer.read(cx).project_path(cx)
17130        } else {
17131            None
17132        }
17133    }
17134
17135    // Returns true if the editor handled a go-to-line request
17136    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17137        maybe!({
17138            let breakpoint_store = self.breakpoint_store.as_ref()?;
17139
17140            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17141            else {
17142                self.clear_row_highlights::<ActiveDebugLine>();
17143                return None;
17144            };
17145
17146            let position = active_stack_frame.position;
17147            let buffer_id = position.buffer_id?;
17148            let snapshot = self
17149                .project
17150                .as_ref()?
17151                .read(cx)
17152                .buffer_for_id(buffer_id, cx)?
17153                .read(cx)
17154                .snapshot();
17155
17156            let mut handled = false;
17157            for (id, ExcerptRange { context, .. }) in
17158                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17159            {
17160                if context.start.cmp(&position, &snapshot).is_ge()
17161                    || context.end.cmp(&position, &snapshot).is_lt()
17162                {
17163                    continue;
17164                }
17165                let snapshot = self.buffer.read(cx).snapshot(cx);
17166                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17167
17168                handled = true;
17169                self.clear_row_highlights::<ActiveDebugLine>();
17170
17171                self.go_to_line::<ActiveDebugLine>(
17172                    multibuffer_anchor,
17173                    Some(cx.theme().colors().editor_debugger_active_line_background),
17174                    window,
17175                    cx,
17176                );
17177
17178                cx.notify();
17179            }
17180
17181            handled.then_some(())
17182        })
17183        .is_some()
17184    }
17185
17186    pub fn copy_file_name_without_extension(
17187        &mut self,
17188        _: &CopyFileNameWithoutExtension,
17189        _: &mut Window,
17190        cx: &mut Context<Self>,
17191    ) {
17192        if let Some(file) = self.target_file(cx) {
17193            if let Some(file_stem) = file.path().file_stem() {
17194                if let Some(name) = file_stem.to_str() {
17195                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17196                }
17197            }
17198        }
17199    }
17200
17201    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17202        if let Some(file) = self.target_file(cx) {
17203            if let Some(file_name) = file.path().file_name() {
17204                if let Some(name) = file_name.to_str() {
17205                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17206                }
17207            }
17208        }
17209    }
17210
17211    pub fn toggle_git_blame(
17212        &mut self,
17213        _: &::git::Blame,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) {
17217        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17218
17219        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17220            self.start_git_blame(true, window, cx);
17221        }
17222
17223        cx.notify();
17224    }
17225
17226    pub fn toggle_git_blame_inline(
17227        &mut self,
17228        _: &ToggleGitBlameInline,
17229        window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) {
17232        self.toggle_git_blame_inline_internal(true, window, cx);
17233        cx.notify();
17234    }
17235
17236    pub fn open_git_blame_commit(
17237        &mut self,
17238        _: &OpenGitBlameCommit,
17239        window: &mut Window,
17240        cx: &mut Context<Self>,
17241    ) {
17242        self.open_git_blame_commit_internal(window, cx);
17243    }
17244
17245    fn open_git_blame_commit_internal(
17246        &mut self,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) -> Option<()> {
17250        let blame = self.blame.as_ref()?;
17251        let snapshot = self.snapshot(window, cx);
17252        let cursor = self.selections.newest::<Point>(cx).head();
17253        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17254        let blame_entry = blame
17255            .update(cx, |blame, cx| {
17256                blame
17257                    .blame_for_rows(
17258                        &[RowInfo {
17259                            buffer_id: Some(buffer.remote_id()),
17260                            buffer_row: Some(point.row),
17261                            ..Default::default()
17262                        }],
17263                        cx,
17264                    )
17265                    .next()
17266            })
17267            .flatten()?;
17268        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17269        let repo = blame.read(cx).repository(cx)?;
17270        let workspace = self.workspace()?.downgrade();
17271        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17272        None
17273    }
17274
17275    pub fn git_blame_inline_enabled(&self) -> bool {
17276        self.git_blame_inline_enabled
17277    }
17278
17279    pub fn toggle_selection_menu(
17280        &mut self,
17281        _: &ToggleSelectionMenu,
17282        _: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) {
17285        self.show_selection_menu = self
17286            .show_selection_menu
17287            .map(|show_selections_menu| !show_selections_menu)
17288            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17289
17290        cx.notify();
17291    }
17292
17293    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17294        self.show_selection_menu
17295            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17296    }
17297
17298    fn start_git_blame(
17299        &mut self,
17300        user_triggered: bool,
17301        window: &mut Window,
17302        cx: &mut Context<Self>,
17303    ) {
17304        if let Some(project) = self.project.as_ref() {
17305            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17306                return;
17307            };
17308
17309            if buffer.read(cx).file().is_none() {
17310                return;
17311            }
17312
17313            let focused = self.focus_handle(cx).contains_focused(window, cx);
17314
17315            let project = project.clone();
17316            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17317            self.blame_subscription =
17318                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17319            self.blame = Some(blame);
17320        }
17321    }
17322
17323    fn toggle_git_blame_inline_internal(
17324        &mut self,
17325        user_triggered: bool,
17326        window: &mut Window,
17327        cx: &mut Context<Self>,
17328    ) {
17329        if self.git_blame_inline_enabled {
17330            self.git_blame_inline_enabled = false;
17331            self.show_git_blame_inline = false;
17332            self.show_git_blame_inline_delay_task.take();
17333        } else {
17334            self.git_blame_inline_enabled = true;
17335            self.start_git_blame_inline(user_triggered, window, cx);
17336        }
17337
17338        cx.notify();
17339    }
17340
17341    fn start_git_blame_inline(
17342        &mut self,
17343        user_triggered: bool,
17344        window: &mut Window,
17345        cx: &mut Context<Self>,
17346    ) {
17347        self.start_git_blame(user_triggered, window, cx);
17348
17349        if ProjectSettings::get_global(cx)
17350            .git
17351            .inline_blame_delay()
17352            .is_some()
17353        {
17354            self.start_inline_blame_timer(window, cx);
17355        } else {
17356            self.show_git_blame_inline = true
17357        }
17358    }
17359
17360    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17361        self.blame.as_ref()
17362    }
17363
17364    pub fn show_git_blame_gutter(&self) -> bool {
17365        self.show_git_blame_gutter
17366    }
17367
17368    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17369        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17370    }
17371
17372    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17373        self.show_git_blame_inline
17374            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17375            && !self.newest_selection_head_on_empty_line(cx)
17376            && self.has_blame_entries(cx)
17377    }
17378
17379    fn has_blame_entries(&self, cx: &App) -> bool {
17380        self.blame()
17381            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17382    }
17383
17384    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17385        let cursor_anchor = self.selections.newest_anchor().head();
17386
17387        let snapshot = self.buffer.read(cx).snapshot(cx);
17388        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17389
17390        snapshot.line_len(buffer_row) == 0
17391    }
17392
17393    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17394        let buffer_and_selection = maybe!({
17395            let selection = self.selections.newest::<Point>(cx);
17396            let selection_range = selection.range();
17397
17398            let multi_buffer = self.buffer().read(cx);
17399            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17400            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17401
17402            let (buffer, range, _) = if selection.reversed {
17403                buffer_ranges.first()
17404            } else {
17405                buffer_ranges.last()
17406            }?;
17407
17408            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17409                ..text::ToPoint::to_point(&range.end, &buffer).row;
17410            Some((
17411                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17412                selection,
17413            ))
17414        });
17415
17416        let Some((buffer, selection)) = buffer_and_selection else {
17417            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17418        };
17419
17420        let Some(project) = self.project.as_ref() else {
17421            return Task::ready(Err(anyhow!("editor does not have project")));
17422        };
17423
17424        project.update(cx, |project, cx| {
17425            project.get_permalink_to_line(&buffer, selection, cx)
17426        })
17427    }
17428
17429    pub fn copy_permalink_to_line(
17430        &mut self,
17431        _: &CopyPermalinkToLine,
17432        window: &mut Window,
17433        cx: &mut Context<Self>,
17434    ) {
17435        let permalink_task = self.get_permalink_to_line(cx);
17436        let workspace = self.workspace();
17437
17438        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17439            Ok(permalink) => {
17440                cx.update(|_, cx| {
17441                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17442                })
17443                .ok();
17444            }
17445            Err(err) => {
17446                let message = format!("Failed to copy permalink: {err}");
17447
17448                anyhow::Result::<()>::Err(err).log_err();
17449
17450                if let Some(workspace) = workspace {
17451                    workspace
17452                        .update_in(cx, |workspace, _, cx| {
17453                            struct CopyPermalinkToLine;
17454
17455                            workspace.show_toast(
17456                                Toast::new(
17457                                    NotificationId::unique::<CopyPermalinkToLine>(),
17458                                    message,
17459                                ),
17460                                cx,
17461                            )
17462                        })
17463                        .ok();
17464                }
17465            }
17466        })
17467        .detach();
17468    }
17469
17470    pub fn copy_file_location(
17471        &mut self,
17472        _: &CopyFileLocation,
17473        _: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) {
17476        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17477        if let Some(file) = self.target_file(cx) {
17478            if let Some(path) = file.path().to_str() {
17479                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17480            }
17481        }
17482    }
17483
17484    pub fn open_permalink_to_line(
17485        &mut self,
17486        _: &OpenPermalinkToLine,
17487        window: &mut Window,
17488        cx: &mut Context<Self>,
17489    ) {
17490        let permalink_task = self.get_permalink_to_line(cx);
17491        let workspace = self.workspace();
17492
17493        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17494            Ok(permalink) => {
17495                cx.update(|_, cx| {
17496                    cx.open_url(permalink.as_ref());
17497                })
17498                .ok();
17499            }
17500            Err(err) => {
17501                let message = format!("Failed to open permalink: {err}");
17502
17503                anyhow::Result::<()>::Err(err).log_err();
17504
17505                if let Some(workspace) = workspace {
17506                    workspace
17507                        .update(cx, |workspace, cx| {
17508                            struct OpenPermalinkToLine;
17509
17510                            workspace.show_toast(
17511                                Toast::new(
17512                                    NotificationId::unique::<OpenPermalinkToLine>(),
17513                                    message,
17514                                ),
17515                                cx,
17516                            )
17517                        })
17518                        .ok();
17519                }
17520            }
17521        })
17522        .detach();
17523    }
17524
17525    pub fn insert_uuid_v4(
17526        &mut self,
17527        _: &InsertUuidV4,
17528        window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        self.insert_uuid(UuidVersion::V4, window, cx);
17532    }
17533
17534    pub fn insert_uuid_v7(
17535        &mut self,
17536        _: &InsertUuidV7,
17537        window: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) {
17540        self.insert_uuid(UuidVersion::V7, window, cx);
17541    }
17542
17543    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17544        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17545        self.transact(window, cx, |this, window, cx| {
17546            let edits = this
17547                .selections
17548                .all::<Point>(cx)
17549                .into_iter()
17550                .map(|selection| {
17551                    let uuid = match version {
17552                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17553                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17554                    };
17555
17556                    (selection.range(), uuid.to_string())
17557                });
17558            this.edit(edits, cx);
17559            this.refresh_inline_completion(true, false, window, cx);
17560        });
17561    }
17562
17563    pub fn open_selections_in_multibuffer(
17564        &mut self,
17565        _: &OpenSelectionsInMultibuffer,
17566        window: &mut Window,
17567        cx: &mut Context<Self>,
17568    ) {
17569        let multibuffer = self.buffer.read(cx);
17570
17571        let Some(buffer) = multibuffer.as_singleton() else {
17572            return;
17573        };
17574
17575        let Some(workspace) = self.workspace() else {
17576            return;
17577        };
17578
17579        let locations = self
17580            .selections
17581            .disjoint_anchors()
17582            .iter()
17583            .map(|selection| {
17584                let range = if selection.reversed {
17585                    selection.end.text_anchor..selection.start.text_anchor
17586                } else {
17587                    selection.start.text_anchor..selection.end.text_anchor
17588                };
17589                Location {
17590                    buffer: buffer.clone(),
17591                    range,
17592                }
17593            })
17594            .collect::<Vec<_>>();
17595
17596        let title = multibuffer.title(cx).to_string();
17597
17598        cx.spawn_in(window, async move |_, cx| {
17599            workspace.update_in(cx, |workspace, window, cx| {
17600                Self::open_locations_in_multibuffer(
17601                    workspace,
17602                    locations,
17603                    format!("Selections for '{title}'"),
17604                    false,
17605                    MultibufferSelectionMode::All,
17606                    window,
17607                    cx,
17608                );
17609            })
17610        })
17611        .detach();
17612    }
17613
17614    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17615    /// last highlight added will be used.
17616    ///
17617    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17618    pub fn highlight_rows<T: 'static>(
17619        &mut self,
17620        range: Range<Anchor>,
17621        color: Hsla,
17622        options: RowHighlightOptions,
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 ix = row_highlights.binary_search_by(|highlight| {
17628            Ordering::Equal
17629                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17630                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17631        });
17632
17633        if let Err(mut ix) = ix {
17634            let index = post_inc(&mut self.highlight_order);
17635
17636            // If this range intersects with the preceding highlight, then merge it with
17637            // the preceding highlight. Otherwise insert a new highlight.
17638            let mut merged = false;
17639            if ix > 0 {
17640                let prev_highlight = &mut row_highlights[ix - 1];
17641                if prev_highlight
17642                    .range
17643                    .end
17644                    .cmp(&range.start, &snapshot)
17645                    .is_ge()
17646                {
17647                    ix -= 1;
17648                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17649                        prev_highlight.range.end = range.end;
17650                    }
17651                    merged = true;
17652                    prev_highlight.index = index;
17653                    prev_highlight.color = color;
17654                    prev_highlight.options = options;
17655                }
17656            }
17657
17658            if !merged {
17659                row_highlights.insert(
17660                    ix,
17661                    RowHighlight {
17662                        range: range.clone(),
17663                        index,
17664                        color,
17665                        options,
17666                        type_id: TypeId::of::<T>(),
17667                    },
17668                );
17669            }
17670
17671            // If any of the following highlights intersect with this one, merge them.
17672            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17673                let highlight = &row_highlights[ix];
17674                if next_highlight
17675                    .range
17676                    .start
17677                    .cmp(&highlight.range.end, &snapshot)
17678                    .is_le()
17679                {
17680                    if next_highlight
17681                        .range
17682                        .end
17683                        .cmp(&highlight.range.end, &snapshot)
17684                        .is_gt()
17685                    {
17686                        row_highlights[ix].range.end = next_highlight.range.end;
17687                    }
17688                    row_highlights.remove(ix + 1);
17689                } else {
17690                    break;
17691                }
17692            }
17693        }
17694    }
17695
17696    /// Remove any highlighted row ranges of the given type that intersect the
17697    /// given ranges.
17698    pub fn remove_highlighted_rows<T: 'static>(
17699        &mut self,
17700        ranges_to_remove: Vec<Range<Anchor>>,
17701        cx: &mut Context<Self>,
17702    ) {
17703        let snapshot = self.buffer().read(cx).snapshot(cx);
17704        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17705        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17706        row_highlights.retain(|highlight| {
17707            while let Some(range_to_remove) = ranges_to_remove.peek() {
17708                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17709                    Ordering::Less | Ordering::Equal => {
17710                        ranges_to_remove.next();
17711                    }
17712                    Ordering::Greater => {
17713                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17714                            Ordering::Less | Ordering::Equal => {
17715                                return false;
17716                            }
17717                            Ordering::Greater => break,
17718                        }
17719                    }
17720                }
17721            }
17722
17723            true
17724        })
17725    }
17726
17727    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17728    pub fn clear_row_highlights<T: 'static>(&mut self) {
17729        self.highlighted_rows.remove(&TypeId::of::<T>());
17730    }
17731
17732    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17733    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17734        self.highlighted_rows
17735            .get(&TypeId::of::<T>())
17736            .map_or(&[] as &[_], |vec| vec.as_slice())
17737            .iter()
17738            .map(|highlight| (highlight.range.clone(), highlight.color))
17739    }
17740
17741    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17742    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17743    /// Allows to ignore certain kinds of highlights.
17744    pub fn highlighted_display_rows(
17745        &self,
17746        window: &mut Window,
17747        cx: &mut App,
17748    ) -> BTreeMap<DisplayRow, LineHighlight> {
17749        let snapshot = self.snapshot(window, cx);
17750        let mut used_highlight_orders = HashMap::default();
17751        self.highlighted_rows
17752            .iter()
17753            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17754            .fold(
17755                BTreeMap::<DisplayRow, LineHighlight>::new(),
17756                |mut unique_rows, highlight| {
17757                    let start = highlight.range.start.to_display_point(&snapshot);
17758                    let end = highlight.range.end.to_display_point(&snapshot);
17759                    let start_row = start.row().0;
17760                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17761                        && end.column() == 0
17762                    {
17763                        end.row().0.saturating_sub(1)
17764                    } else {
17765                        end.row().0
17766                    };
17767                    for row in start_row..=end_row {
17768                        let used_index =
17769                            used_highlight_orders.entry(row).or_insert(highlight.index);
17770                        if highlight.index >= *used_index {
17771                            *used_index = highlight.index;
17772                            unique_rows.insert(
17773                                DisplayRow(row),
17774                                LineHighlight {
17775                                    include_gutter: highlight.options.include_gutter,
17776                                    border: None,
17777                                    background: highlight.color.into(),
17778                                    type_id: Some(highlight.type_id),
17779                                },
17780                            );
17781                        }
17782                    }
17783                    unique_rows
17784                },
17785            )
17786    }
17787
17788    pub fn highlighted_display_row_for_autoscroll(
17789        &self,
17790        snapshot: &DisplaySnapshot,
17791    ) -> Option<DisplayRow> {
17792        self.highlighted_rows
17793            .values()
17794            .flat_map(|highlighted_rows| highlighted_rows.iter())
17795            .filter_map(|highlight| {
17796                if highlight.options.autoscroll {
17797                    Some(highlight.range.start.to_display_point(snapshot).row())
17798                } else {
17799                    None
17800                }
17801            })
17802            .min()
17803    }
17804
17805    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17806        self.highlight_background::<SearchWithinRange>(
17807            ranges,
17808            |colors| colors.editor_document_highlight_read_background,
17809            cx,
17810        )
17811    }
17812
17813    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17814        self.breadcrumb_header = Some(new_header);
17815    }
17816
17817    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17818        self.clear_background_highlights::<SearchWithinRange>(cx);
17819    }
17820
17821    pub fn highlight_background<T: 'static>(
17822        &mut self,
17823        ranges: &[Range<Anchor>],
17824        color_fetcher: fn(&ThemeColors) -> Hsla,
17825        cx: &mut Context<Self>,
17826    ) {
17827        self.background_highlights
17828            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17829        self.scrollbar_marker_state.dirty = true;
17830        cx.notify();
17831    }
17832
17833    pub fn clear_background_highlights<T: 'static>(
17834        &mut self,
17835        cx: &mut Context<Self>,
17836    ) -> Option<BackgroundHighlight> {
17837        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17838        if !text_highlights.1.is_empty() {
17839            self.scrollbar_marker_state.dirty = true;
17840            cx.notify();
17841        }
17842        Some(text_highlights)
17843    }
17844
17845    pub fn highlight_gutter<T: 'static>(
17846        &mut self,
17847        ranges: &[Range<Anchor>],
17848        color_fetcher: fn(&App) -> Hsla,
17849        cx: &mut Context<Self>,
17850    ) {
17851        self.gutter_highlights
17852            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17853        cx.notify();
17854    }
17855
17856    pub fn clear_gutter_highlights<T: 'static>(
17857        &mut self,
17858        cx: &mut Context<Self>,
17859    ) -> Option<GutterHighlight> {
17860        cx.notify();
17861        self.gutter_highlights.remove(&TypeId::of::<T>())
17862    }
17863
17864    #[cfg(feature = "test-support")]
17865    pub fn all_text_background_highlights(
17866        &self,
17867        window: &mut Window,
17868        cx: &mut Context<Self>,
17869    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17870        let snapshot = self.snapshot(window, cx);
17871        let buffer = &snapshot.buffer_snapshot;
17872        let start = buffer.anchor_before(0);
17873        let end = buffer.anchor_after(buffer.len());
17874        let theme = cx.theme().colors();
17875        self.background_highlights_in_range(start..end, &snapshot, theme)
17876    }
17877
17878    #[cfg(feature = "test-support")]
17879    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17880        let snapshot = self.buffer().read(cx).snapshot(cx);
17881
17882        let highlights = self
17883            .background_highlights
17884            .get(&TypeId::of::<items::BufferSearchHighlights>());
17885
17886        if let Some((_color, ranges)) = highlights {
17887            ranges
17888                .iter()
17889                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17890                .collect_vec()
17891        } else {
17892            vec![]
17893        }
17894    }
17895
17896    fn document_highlights_for_position<'a>(
17897        &'a self,
17898        position: Anchor,
17899        buffer: &'a MultiBufferSnapshot,
17900    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17901        let read_highlights = self
17902            .background_highlights
17903            .get(&TypeId::of::<DocumentHighlightRead>())
17904            .map(|h| &h.1);
17905        let write_highlights = self
17906            .background_highlights
17907            .get(&TypeId::of::<DocumentHighlightWrite>())
17908            .map(|h| &h.1);
17909        let left_position = position.bias_left(buffer);
17910        let right_position = position.bias_right(buffer);
17911        read_highlights
17912            .into_iter()
17913            .chain(write_highlights)
17914            .flat_map(move |ranges| {
17915                let start_ix = match ranges.binary_search_by(|probe| {
17916                    let cmp = probe.end.cmp(&left_position, buffer);
17917                    if cmp.is_ge() {
17918                        Ordering::Greater
17919                    } else {
17920                        Ordering::Less
17921                    }
17922                }) {
17923                    Ok(i) | Err(i) => i,
17924                };
17925
17926                ranges[start_ix..]
17927                    .iter()
17928                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17929            })
17930    }
17931
17932    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17933        self.background_highlights
17934            .get(&TypeId::of::<T>())
17935            .map_or(false, |(_, highlights)| !highlights.is_empty())
17936    }
17937
17938    pub fn background_highlights_in_range(
17939        &self,
17940        search_range: Range<Anchor>,
17941        display_snapshot: &DisplaySnapshot,
17942        theme: &ThemeColors,
17943    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17944        let mut results = Vec::new();
17945        for (color_fetcher, ranges) in self.background_highlights.values() {
17946            let color = color_fetcher(theme);
17947            let start_ix = match ranges.binary_search_by(|probe| {
17948                let cmp = probe
17949                    .end
17950                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17951                if cmp.is_gt() {
17952                    Ordering::Greater
17953                } else {
17954                    Ordering::Less
17955                }
17956            }) {
17957                Ok(i) | Err(i) => i,
17958            };
17959            for range in &ranges[start_ix..] {
17960                if range
17961                    .start
17962                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17963                    .is_ge()
17964                {
17965                    break;
17966                }
17967
17968                let start = range.start.to_display_point(display_snapshot);
17969                let end = range.end.to_display_point(display_snapshot);
17970                results.push((start..end, color))
17971            }
17972        }
17973        results
17974    }
17975
17976    pub fn background_highlight_row_ranges<T: 'static>(
17977        &self,
17978        search_range: Range<Anchor>,
17979        display_snapshot: &DisplaySnapshot,
17980        count: usize,
17981    ) -> Vec<RangeInclusive<DisplayPoint>> {
17982        let mut results = Vec::new();
17983        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17984            return vec![];
17985        };
17986
17987        let start_ix = match ranges.binary_search_by(|probe| {
17988            let cmp = probe
17989                .end
17990                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17991            if cmp.is_gt() {
17992                Ordering::Greater
17993            } else {
17994                Ordering::Less
17995            }
17996        }) {
17997            Ok(i) | Err(i) => i,
17998        };
17999        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18000            if let (Some(start_display), Some(end_display)) = (start, end) {
18001                results.push(
18002                    start_display.to_display_point(display_snapshot)
18003                        ..=end_display.to_display_point(display_snapshot),
18004                );
18005            }
18006        };
18007        let mut start_row: Option<Point> = None;
18008        let mut end_row: Option<Point> = None;
18009        if ranges.len() > count {
18010            return Vec::new();
18011        }
18012        for range in &ranges[start_ix..] {
18013            if range
18014                .start
18015                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18016                .is_ge()
18017            {
18018                break;
18019            }
18020            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18021            if let Some(current_row) = &end_row {
18022                if end.row == current_row.row {
18023                    continue;
18024                }
18025            }
18026            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18027            if start_row.is_none() {
18028                assert_eq!(end_row, None);
18029                start_row = Some(start);
18030                end_row = Some(end);
18031                continue;
18032            }
18033            if let Some(current_end) = end_row.as_mut() {
18034                if start.row > current_end.row + 1 {
18035                    push_region(start_row, end_row);
18036                    start_row = Some(start);
18037                    end_row = Some(end);
18038                } else {
18039                    // Merge two hunks.
18040                    *current_end = end;
18041                }
18042            } else {
18043                unreachable!();
18044            }
18045        }
18046        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18047        push_region(start_row, end_row);
18048        results
18049    }
18050
18051    pub fn gutter_highlights_in_range(
18052        &self,
18053        search_range: Range<Anchor>,
18054        display_snapshot: &DisplaySnapshot,
18055        cx: &App,
18056    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18057        let mut results = Vec::new();
18058        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18059            let color = color_fetcher(cx);
18060            let start_ix = match ranges.binary_search_by(|probe| {
18061                let cmp = probe
18062                    .end
18063                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18064                if cmp.is_gt() {
18065                    Ordering::Greater
18066                } else {
18067                    Ordering::Less
18068                }
18069            }) {
18070                Ok(i) | Err(i) => i,
18071            };
18072            for range in &ranges[start_ix..] {
18073                if range
18074                    .start
18075                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18076                    .is_ge()
18077                {
18078                    break;
18079                }
18080
18081                let start = range.start.to_display_point(display_snapshot);
18082                let end = range.end.to_display_point(display_snapshot);
18083                results.push((start..end, color))
18084            }
18085        }
18086        results
18087    }
18088
18089    /// Get the text ranges corresponding to the redaction query
18090    pub fn redacted_ranges(
18091        &self,
18092        search_range: Range<Anchor>,
18093        display_snapshot: &DisplaySnapshot,
18094        cx: &App,
18095    ) -> Vec<Range<DisplayPoint>> {
18096        display_snapshot
18097            .buffer_snapshot
18098            .redacted_ranges(search_range, |file| {
18099                if let Some(file) = file {
18100                    file.is_private()
18101                        && EditorSettings::get(
18102                            Some(SettingsLocation {
18103                                worktree_id: file.worktree_id(cx),
18104                                path: file.path().as_ref(),
18105                            }),
18106                            cx,
18107                        )
18108                        .redact_private_values
18109                } else {
18110                    false
18111                }
18112            })
18113            .map(|range| {
18114                range.start.to_display_point(display_snapshot)
18115                    ..range.end.to_display_point(display_snapshot)
18116            })
18117            .collect()
18118    }
18119
18120    pub fn highlight_text<T: 'static>(
18121        &mut self,
18122        ranges: Vec<Range<Anchor>>,
18123        style: HighlightStyle,
18124        cx: &mut Context<Self>,
18125    ) {
18126        self.display_map.update(cx, |map, _| {
18127            map.highlight_text(TypeId::of::<T>(), ranges, style)
18128        });
18129        cx.notify();
18130    }
18131
18132    pub(crate) fn highlight_inlays<T: 'static>(
18133        &mut self,
18134        highlights: Vec<InlayHighlight>,
18135        style: HighlightStyle,
18136        cx: &mut Context<Self>,
18137    ) {
18138        self.display_map.update(cx, |map, _| {
18139            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18140        });
18141        cx.notify();
18142    }
18143
18144    pub fn text_highlights<'a, T: 'static>(
18145        &'a self,
18146        cx: &'a App,
18147    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18148        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18149    }
18150
18151    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18152        let cleared = self
18153            .display_map
18154            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18155        if cleared {
18156            cx.notify();
18157        }
18158    }
18159
18160    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18161        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18162            && self.focus_handle.is_focused(window)
18163    }
18164
18165    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18166        self.show_cursor_when_unfocused = is_enabled;
18167        cx.notify();
18168    }
18169
18170    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18171        cx.notify();
18172    }
18173
18174    fn on_debug_session_event(
18175        &mut self,
18176        _session: Entity<Session>,
18177        event: &SessionEvent,
18178        cx: &mut Context<Self>,
18179    ) {
18180        match event {
18181            SessionEvent::InvalidateInlineValue => {
18182                self.refresh_inline_values(cx);
18183            }
18184            _ => {}
18185        }
18186    }
18187
18188    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18189        let Some(project) = self.project.clone() else {
18190            return;
18191        };
18192
18193        if !self.inline_value_cache.enabled {
18194            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18195            self.splice_inlays(&inlays, Vec::new(), cx);
18196            return;
18197        }
18198
18199        let current_execution_position = self
18200            .highlighted_rows
18201            .get(&TypeId::of::<ActiveDebugLine>())
18202            .and_then(|lines| lines.last().map(|line| line.range.start));
18203
18204        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18205            let inline_values = editor
18206                .update(cx, |editor, cx| {
18207                    let Some(current_execution_position) = current_execution_position else {
18208                        return Some(Task::ready(Ok(Vec::new())));
18209                    };
18210
18211                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18212                        let snapshot = buffer.snapshot(cx);
18213
18214                        let excerpt = snapshot.excerpt_containing(
18215                            current_execution_position..current_execution_position,
18216                        )?;
18217
18218                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18219                    })?;
18220
18221                    let range =
18222                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18223
18224                    project.inline_values(buffer, range, cx)
18225                })
18226                .ok()
18227                .flatten()?
18228                .await
18229                .context("refreshing debugger inlays")
18230                .log_err()?;
18231
18232            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18233
18234            for (buffer_id, inline_value) in inline_values
18235                .into_iter()
18236                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18237            {
18238                buffer_inline_values
18239                    .entry(buffer_id)
18240                    .or_default()
18241                    .push(inline_value);
18242            }
18243
18244            editor
18245                .update(cx, |editor, cx| {
18246                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18247                    let mut new_inlays = Vec::default();
18248
18249                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18250                        let buffer_id = buffer_snapshot.remote_id();
18251                        buffer_inline_values
18252                            .get(&buffer_id)
18253                            .into_iter()
18254                            .flatten()
18255                            .for_each(|hint| {
18256                                let inlay = Inlay::debugger_hint(
18257                                    post_inc(&mut editor.next_inlay_id),
18258                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18259                                    hint.text(),
18260                                );
18261
18262                                new_inlays.push(inlay);
18263                            });
18264                    }
18265
18266                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18267                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18268
18269                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18270                })
18271                .ok()?;
18272            Some(())
18273        });
18274    }
18275
18276    fn on_buffer_event(
18277        &mut self,
18278        multibuffer: &Entity<MultiBuffer>,
18279        event: &multi_buffer::Event,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        match event {
18284            multi_buffer::Event::Edited {
18285                singleton_buffer_edited,
18286                edited_buffer: buffer_edited,
18287            } => {
18288                self.scrollbar_marker_state.dirty = true;
18289                self.active_indent_guides_state.dirty = true;
18290                self.refresh_active_diagnostics(cx);
18291                self.refresh_code_actions(window, cx);
18292                self.refresh_selected_text_highlights(true, window, cx);
18293                refresh_matching_bracket_highlights(self, window, cx);
18294                if self.has_active_inline_completion() {
18295                    self.update_visible_inline_completion(window, cx);
18296                }
18297                if let Some(buffer) = buffer_edited {
18298                    let buffer_id = buffer.read(cx).remote_id();
18299                    if !self.registered_buffers.contains_key(&buffer_id) {
18300                        if let Some(project) = self.project.as_ref() {
18301                            project.update(cx, |project, cx| {
18302                                self.registered_buffers.insert(
18303                                    buffer_id,
18304                                    project.register_buffer_with_language_servers(&buffer, cx),
18305                                );
18306                            })
18307                        }
18308                    }
18309                }
18310                cx.emit(EditorEvent::BufferEdited);
18311                cx.emit(SearchEvent::MatchesInvalidated);
18312                if *singleton_buffer_edited {
18313                    if let Some(project) = &self.project {
18314                        #[allow(clippy::mutable_key_type)]
18315                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18316                            multibuffer
18317                                .all_buffers()
18318                                .into_iter()
18319                                .filter_map(|buffer| {
18320                                    buffer.update(cx, |buffer, cx| {
18321                                        let language = buffer.language()?;
18322                                        let should_discard = project.update(cx, |project, cx| {
18323                                            project.is_local()
18324                                                && !project.has_language_servers_for(buffer, cx)
18325                                        });
18326                                        should_discard.not().then_some(language.clone())
18327                                    })
18328                                })
18329                                .collect::<HashSet<_>>()
18330                        });
18331                        if !languages_affected.is_empty() {
18332                            self.refresh_inlay_hints(
18333                                InlayHintRefreshReason::BufferEdited(languages_affected),
18334                                cx,
18335                            );
18336                        }
18337                    }
18338                }
18339
18340                let Some(project) = &self.project else { return };
18341                let (telemetry, is_via_ssh) = {
18342                    let project = project.read(cx);
18343                    let telemetry = project.client().telemetry().clone();
18344                    let is_via_ssh = project.is_via_ssh();
18345                    (telemetry, is_via_ssh)
18346                };
18347                refresh_linked_ranges(self, window, cx);
18348                telemetry.log_edit_event("editor", is_via_ssh);
18349            }
18350            multi_buffer::Event::ExcerptsAdded {
18351                buffer,
18352                predecessor,
18353                excerpts,
18354            } => {
18355                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18356                let buffer_id = buffer.read(cx).remote_id();
18357                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18358                    if let Some(project) = &self.project {
18359                        update_uncommitted_diff_for_buffer(
18360                            cx.entity(),
18361                            project,
18362                            [buffer.clone()],
18363                            self.buffer.clone(),
18364                            cx,
18365                        )
18366                        .detach();
18367                    }
18368                }
18369                cx.emit(EditorEvent::ExcerptsAdded {
18370                    buffer: buffer.clone(),
18371                    predecessor: *predecessor,
18372                    excerpts: excerpts.clone(),
18373                });
18374                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18375            }
18376            multi_buffer::Event::ExcerptsRemoved {
18377                ids,
18378                removed_buffer_ids,
18379            } => {
18380                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18381                let buffer = self.buffer.read(cx);
18382                self.registered_buffers
18383                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18384                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18385                cx.emit(EditorEvent::ExcerptsRemoved {
18386                    ids: ids.clone(),
18387                    removed_buffer_ids: removed_buffer_ids.clone(),
18388                })
18389            }
18390            multi_buffer::Event::ExcerptsEdited {
18391                excerpt_ids,
18392                buffer_ids,
18393            } => {
18394                self.display_map.update(cx, |map, cx| {
18395                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18396                });
18397                cx.emit(EditorEvent::ExcerptsEdited {
18398                    ids: excerpt_ids.clone(),
18399                })
18400            }
18401            multi_buffer::Event::ExcerptsExpanded { ids } => {
18402                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18403                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18404            }
18405            multi_buffer::Event::Reparsed(buffer_id) => {
18406                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18407                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18408
18409                cx.emit(EditorEvent::Reparsed(*buffer_id));
18410            }
18411            multi_buffer::Event::DiffHunksToggled => {
18412                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18413            }
18414            multi_buffer::Event::LanguageChanged(buffer_id) => {
18415                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18416                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18417                cx.emit(EditorEvent::Reparsed(*buffer_id));
18418                cx.notify();
18419            }
18420            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18421            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18422            multi_buffer::Event::FileHandleChanged
18423            | multi_buffer::Event::Reloaded
18424            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18425            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18426            multi_buffer::Event::DiagnosticsUpdated => {
18427                self.refresh_active_diagnostics(cx);
18428                self.refresh_inline_diagnostics(true, window, cx);
18429                self.scrollbar_marker_state.dirty = true;
18430                cx.notify();
18431            }
18432            _ => {}
18433        };
18434    }
18435
18436    pub fn start_temporary_diff_override(&mut self) {
18437        self.load_diff_task.take();
18438        self.temporary_diff_override = true;
18439    }
18440
18441    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18442        self.temporary_diff_override = false;
18443        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18444        self.buffer.update(cx, |buffer, cx| {
18445            buffer.set_all_diff_hunks_collapsed(cx);
18446        });
18447
18448        if let Some(project) = self.project.clone() {
18449            self.load_diff_task = Some(
18450                update_uncommitted_diff_for_buffer(
18451                    cx.entity(),
18452                    &project,
18453                    self.buffer.read(cx).all_buffers(),
18454                    self.buffer.clone(),
18455                    cx,
18456                )
18457                .shared(),
18458            );
18459        }
18460    }
18461
18462    fn on_display_map_changed(
18463        &mut self,
18464        _: Entity<DisplayMap>,
18465        _: &mut Window,
18466        cx: &mut Context<Self>,
18467    ) {
18468        cx.notify();
18469    }
18470
18471    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18472        let new_severity = if self.diagnostics_enabled() {
18473            EditorSettings::get_global(cx)
18474                .diagnostics_max_severity
18475                .unwrap_or(DiagnosticSeverity::Hint)
18476        } else {
18477            DiagnosticSeverity::Off
18478        };
18479        self.set_max_diagnostics_severity(new_severity, cx);
18480        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18481        self.update_edit_prediction_settings(cx);
18482        self.refresh_inline_completion(true, false, window, cx);
18483        self.refresh_inlay_hints(
18484            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18485                self.selections.newest_anchor().head(),
18486                &self.buffer.read(cx).snapshot(cx),
18487                cx,
18488            )),
18489            cx,
18490        );
18491
18492        let old_cursor_shape = self.cursor_shape;
18493
18494        {
18495            let editor_settings = EditorSettings::get_global(cx);
18496            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18497            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18498            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18499            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18500        }
18501
18502        if old_cursor_shape != self.cursor_shape {
18503            cx.emit(EditorEvent::CursorShapeChanged);
18504        }
18505
18506        let project_settings = ProjectSettings::get_global(cx);
18507        self.serialize_dirty_buffers =
18508            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18509
18510        if self.mode.is_full() {
18511            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18512            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18513            if self.show_inline_diagnostics != show_inline_diagnostics {
18514                self.show_inline_diagnostics = show_inline_diagnostics;
18515                self.refresh_inline_diagnostics(false, window, cx);
18516            }
18517
18518            if self.git_blame_inline_enabled != inline_blame_enabled {
18519                self.toggle_git_blame_inline_internal(false, window, cx);
18520            }
18521
18522            let minimap_settings = EditorSettings::get_global(cx).minimap;
18523            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18524                self.set_minimap_visibility(
18525                    self.minimap_visibility.toggle_visibility(),
18526                    window,
18527                    cx,
18528                );
18529            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18530                minimap_entity.update(cx, |minimap_editor, cx| {
18531                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18532                })
18533            }
18534        }
18535
18536        cx.notify();
18537    }
18538
18539    pub fn set_searchable(&mut self, searchable: bool) {
18540        self.searchable = searchable;
18541    }
18542
18543    pub fn searchable(&self) -> bool {
18544        self.searchable
18545    }
18546
18547    fn open_proposed_changes_editor(
18548        &mut self,
18549        _: &OpenProposedChangesEditor,
18550        window: &mut Window,
18551        cx: &mut Context<Self>,
18552    ) {
18553        let Some(workspace) = self.workspace() else {
18554            cx.propagate();
18555            return;
18556        };
18557
18558        let selections = self.selections.all::<usize>(cx);
18559        let multi_buffer = self.buffer.read(cx);
18560        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18561        let mut new_selections_by_buffer = HashMap::default();
18562        for selection in selections {
18563            for (buffer, range, _) in
18564                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18565            {
18566                let mut range = range.to_point(buffer);
18567                range.start.column = 0;
18568                range.end.column = buffer.line_len(range.end.row);
18569                new_selections_by_buffer
18570                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18571                    .or_insert(Vec::new())
18572                    .push(range)
18573            }
18574        }
18575
18576        let proposed_changes_buffers = new_selections_by_buffer
18577            .into_iter()
18578            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18579            .collect::<Vec<_>>();
18580        let proposed_changes_editor = cx.new(|cx| {
18581            ProposedChangesEditor::new(
18582                "Proposed changes",
18583                proposed_changes_buffers,
18584                self.project.clone(),
18585                window,
18586                cx,
18587            )
18588        });
18589
18590        window.defer(cx, move |window, cx| {
18591            workspace.update(cx, |workspace, cx| {
18592                workspace.active_pane().update(cx, |pane, cx| {
18593                    pane.add_item(
18594                        Box::new(proposed_changes_editor),
18595                        true,
18596                        true,
18597                        None,
18598                        window,
18599                        cx,
18600                    );
18601                });
18602            });
18603        });
18604    }
18605
18606    pub fn open_excerpts_in_split(
18607        &mut self,
18608        _: &OpenExcerptsSplit,
18609        window: &mut Window,
18610        cx: &mut Context<Self>,
18611    ) {
18612        self.open_excerpts_common(None, true, window, cx)
18613    }
18614
18615    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18616        self.open_excerpts_common(None, false, window, cx)
18617    }
18618
18619    fn open_excerpts_common(
18620        &mut self,
18621        jump_data: Option<JumpData>,
18622        split: bool,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        let Some(workspace) = self.workspace() else {
18627            cx.propagate();
18628            return;
18629        };
18630
18631        if self.buffer.read(cx).is_singleton() {
18632            cx.propagate();
18633            return;
18634        }
18635
18636        let mut new_selections_by_buffer = HashMap::default();
18637        match &jump_data {
18638            Some(JumpData::MultiBufferPoint {
18639                excerpt_id,
18640                position,
18641                anchor,
18642                line_offset_from_top,
18643            }) => {
18644                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18645                if let Some(buffer) = multi_buffer_snapshot
18646                    .buffer_id_for_excerpt(*excerpt_id)
18647                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18648                {
18649                    let buffer_snapshot = buffer.read(cx).snapshot();
18650                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18651                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18652                    } else {
18653                        buffer_snapshot.clip_point(*position, Bias::Left)
18654                    };
18655                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18656                    new_selections_by_buffer.insert(
18657                        buffer,
18658                        (
18659                            vec![jump_to_offset..jump_to_offset],
18660                            Some(*line_offset_from_top),
18661                        ),
18662                    );
18663                }
18664            }
18665            Some(JumpData::MultiBufferRow {
18666                row,
18667                line_offset_from_top,
18668            }) => {
18669                let point = MultiBufferPoint::new(row.0, 0);
18670                if let Some((buffer, buffer_point, _)) =
18671                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18672                {
18673                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18674                    new_selections_by_buffer
18675                        .entry(buffer)
18676                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18677                        .0
18678                        .push(buffer_offset..buffer_offset)
18679                }
18680            }
18681            None => {
18682                let selections = self.selections.all::<usize>(cx);
18683                let multi_buffer = self.buffer.read(cx);
18684                for selection in selections {
18685                    for (snapshot, range, _, anchor) in multi_buffer
18686                        .snapshot(cx)
18687                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18688                    {
18689                        if let Some(anchor) = anchor {
18690                            // selection is in a deleted hunk
18691                            let Some(buffer_id) = anchor.buffer_id else {
18692                                continue;
18693                            };
18694                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18695                                continue;
18696                            };
18697                            let offset = text::ToOffset::to_offset(
18698                                &anchor.text_anchor,
18699                                &buffer_handle.read(cx).snapshot(),
18700                            );
18701                            let range = offset..offset;
18702                            new_selections_by_buffer
18703                                .entry(buffer_handle)
18704                                .or_insert((Vec::new(), None))
18705                                .0
18706                                .push(range)
18707                        } else {
18708                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18709                            else {
18710                                continue;
18711                            };
18712                            new_selections_by_buffer
18713                                .entry(buffer_handle)
18714                                .or_insert((Vec::new(), None))
18715                                .0
18716                                .push(range)
18717                        }
18718                    }
18719                }
18720            }
18721        }
18722
18723        new_selections_by_buffer
18724            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18725
18726        if new_selections_by_buffer.is_empty() {
18727            return;
18728        }
18729
18730        // We defer the pane interaction because we ourselves are a workspace item
18731        // and activating a new item causes the pane to call a method on us reentrantly,
18732        // which panics if we're on the stack.
18733        window.defer(cx, move |window, cx| {
18734            workspace.update(cx, |workspace, cx| {
18735                let pane = if split {
18736                    workspace.adjacent_pane(window, cx)
18737                } else {
18738                    workspace.active_pane().clone()
18739                };
18740
18741                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18742                    let editor = buffer
18743                        .read(cx)
18744                        .file()
18745                        .is_none()
18746                        .then(|| {
18747                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18748                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18749                            // Instead, we try to activate the existing editor in the pane first.
18750                            let (editor, pane_item_index) =
18751                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18752                                    let editor = item.downcast::<Editor>()?;
18753                                    let singleton_buffer =
18754                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18755                                    if singleton_buffer == buffer {
18756                                        Some((editor, i))
18757                                    } else {
18758                                        None
18759                                    }
18760                                })?;
18761                            pane.update(cx, |pane, cx| {
18762                                pane.activate_item(pane_item_index, true, true, window, cx)
18763                            });
18764                            Some(editor)
18765                        })
18766                        .flatten()
18767                        .unwrap_or_else(|| {
18768                            workspace.open_project_item::<Self>(
18769                                pane.clone(),
18770                                buffer,
18771                                true,
18772                                true,
18773                                window,
18774                                cx,
18775                            )
18776                        });
18777
18778                    editor.update(cx, |editor, cx| {
18779                        let autoscroll = match scroll_offset {
18780                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18781                            None => Autoscroll::newest(),
18782                        };
18783                        let nav_history = editor.nav_history.take();
18784                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18785                            s.select_ranges(ranges);
18786                        });
18787                        editor.nav_history = nav_history;
18788                    });
18789                }
18790            })
18791        });
18792    }
18793
18794    // For now, don't allow opening excerpts in buffers that aren't backed by
18795    // regular project files.
18796    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18797        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18798    }
18799
18800    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18801        let snapshot = self.buffer.read(cx).read(cx);
18802        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18803        Some(
18804            ranges
18805                .iter()
18806                .map(move |range| {
18807                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18808                })
18809                .collect(),
18810        )
18811    }
18812
18813    fn selection_replacement_ranges(
18814        &self,
18815        range: Range<OffsetUtf16>,
18816        cx: &mut App,
18817    ) -> Vec<Range<OffsetUtf16>> {
18818        let selections = self.selections.all::<OffsetUtf16>(cx);
18819        let newest_selection = selections
18820            .iter()
18821            .max_by_key(|selection| selection.id)
18822            .unwrap();
18823        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18824        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18825        let snapshot = self.buffer.read(cx).read(cx);
18826        selections
18827            .into_iter()
18828            .map(|mut selection| {
18829                selection.start.0 =
18830                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18831                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18832                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18833                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18834            })
18835            .collect()
18836    }
18837
18838    fn report_editor_event(
18839        &self,
18840        event_type: &'static str,
18841        file_extension: Option<String>,
18842        cx: &App,
18843    ) {
18844        if cfg!(any(test, feature = "test-support")) {
18845            return;
18846        }
18847
18848        let Some(project) = &self.project else { return };
18849
18850        // If None, we are in a file without an extension
18851        let file = self
18852            .buffer
18853            .read(cx)
18854            .as_singleton()
18855            .and_then(|b| b.read(cx).file());
18856        let file_extension = file_extension.or(file
18857            .as_ref()
18858            .and_then(|file| Path::new(file.file_name(cx)).extension())
18859            .and_then(|e| e.to_str())
18860            .map(|a| a.to_string()));
18861
18862        let vim_mode = vim_enabled(cx);
18863
18864        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18865        let copilot_enabled = edit_predictions_provider
18866            == language::language_settings::EditPredictionProvider::Copilot;
18867        let copilot_enabled_for_language = self
18868            .buffer
18869            .read(cx)
18870            .language_settings(cx)
18871            .show_edit_predictions;
18872
18873        let project = project.read(cx);
18874        telemetry::event!(
18875            event_type,
18876            file_extension,
18877            vim_mode,
18878            copilot_enabled,
18879            copilot_enabled_for_language,
18880            edit_predictions_provider,
18881            is_via_ssh = project.is_via_ssh(),
18882        );
18883    }
18884
18885    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18886    /// with each line being an array of {text, highlight} objects.
18887    fn copy_highlight_json(
18888        &mut self,
18889        _: &CopyHighlightJson,
18890        window: &mut Window,
18891        cx: &mut Context<Self>,
18892    ) {
18893        #[derive(Serialize)]
18894        struct Chunk<'a> {
18895            text: String,
18896            highlight: Option<&'a str>,
18897        }
18898
18899        let snapshot = self.buffer.read(cx).snapshot(cx);
18900        let range = self
18901            .selected_text_range(false, window, cx)
18902            .and_then(|selection| {
18903                if selection.range.is_empty() {
18904                    None
18905                } else {
18906                    Some(selection.range)
18907                }
18908            })
18909            .unwrap_or_else(|| 0..snapshot.len());
18910
18911        let chunks = snapshot.chunks(range, true);
18912        let mut lines = Vec::new();
18913        let mut line: VecDeque<Chunk> = VecDeque::new();
18914
18915        let Some(style) = self.style.as_ref() else {
18916            return;
18917        };
18918
18919        for chunk in chunks {
18920            let highlight = chunk
18921                .syntax_highlight_id
18922                .and_then(|id| id.name(&style.syntax));
18923            let mut chunk_lines = chunk.text.split('\n').peekable();
18924            while let Some(text) = chunk_lines.next() {
18925                let mut merged_with_last_token = false;
18926                if let Some(last_token) = line.back_mut() {
18927                    if last_token.highlight == highlight {
18928                        last_token.text.push_str(text);
18929                        merged_with_last_token = true;
18930                    }
18931                }
18932
18933                if !merged_with_last_token {
18934                    line.push_back(Chunk {
18935                        text: text.into(),
18936                        highlight,
18937                    });
18938                }
18939
18940                if chunk_lines.peek().is_some() {
18941                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18942                        line.pop_front();
18943                    }
18944                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18945                        line.pop_back();
18946                    }
18947
18948                    lines.push(mem::take(&mut line));
18949                }
18950            }
18951        }
18952
18953        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18954            return;
18955        };
18956        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18957    }
18958
18959    pub fn open_context_menu(
18960        &mut self,
18961        _: &OpenContextMenu,
18962        window: &mut Window,
18963        cx: &mut Context<Self>,
18964    ) {
18965        self.request_autoscroll(Autoscroll::newest(), cx);
18966        let position = self.selections.newest_display(cx).start;
18967        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18968    }
18969
18970    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18971        &self.inlay_hint_cache
18972    }
18973
18974    pub fn replay_insert_event(
18975        &mut self,
18976        text: &str,
18977        relative_utf16_range: Option<Range<isize>>,
18978        window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        if !self.input_enabled {
18982            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18983            return;
18984        }
18985        if let Some(relative_utf16_range) = relative_utf16_range {
18986            let selections = self.selections.all::<OffsetUtf16>(cx);
18987            self.change_selections(None, window, cx, |s| {
18988                let new_ranges = selections.into_iter().map(|range| {
18989                    let start = OffsetUtf16(
18990                        range
18991                            .head()
18992                            .0
18993                            .saturating_add_signed(relative_utf16_range.start),
18994                    );
18995                    let end = OffsetUtf16(
18996                        range
18997                            .head()
18998                            .0
18999                            .saturating_add_signed(relative_utf16_range.end),
19000                    );
19001                    start..end
19002                });
19003                s.select_ranges(new_ranges);
19004            });
19005        }
19006
19007        self.handle_input(text, window, cx);
19008    }
19009
19010    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19011        let Some(provider) = self.semantics_provider.as_ref() else {
19012            return false;
19013        };
19014
19015        let mut supports = false;
19016        self.buffer().update(cx, |this, cx| {
19017            this.for_each_buffer(|buffer| {
19018                supports |= provider.supports_inlay_hints(buffer, cx);
19019            });
19020        });
19021
19022        supports
19023    }
19024
19025    pub fn is_focused(&self, window: &Window) -> bool {
19026        self.focus_handle.is_focused(window)
19027    }
19028
19029    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19030        cx.emit(EditorEvent::Focused);
19031
19032        if let Some(descendant) = self
19033            .last_focused_descendant
19034            .take()
19035            .and_then(|descendant| descendant.upgrade())
19036        {
19037            window.focus(&descendant);
19038        } else {
19039            if let Some(blame) = self.blame.as_ref() {
19040                blame.update(cx, GitBlame::focus)
19041            }
19042
19043            self.blink_manager.update(cx, BlinkManager::enable);
19044            self.show_cursor_names(window, cx);
19045            self.buffer.update(cx, |buffer, cx| {
19046                buffer.finalize_last_transaction(cx);
19047                if self.leader_id.is_none() {
19048                    buffer.set_active_selections(
19049                        &self.selections.disjoint_anchors(),
19050                        self.selections.line_mode,
19051                        self.cursor_shape,
19052                        cx,
19053                    );
19054                }
19055            });
19056        }
19057    }
19058
19059    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19060        cx.emit(EditorEvent::FocusedIn)
19061    }
19062
19063    fn handle_focus_out(
19064        &mut self,
19065        event: FocusOutEvent,
19066        _window: &mut Window,
19067        cx: &mut Context<Self>,
19068    ) {
19069        if event.blurred != self.focus_handle {
19070            self.last_focused_descendant = Some(event.blurred);
19071        }
19072        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19073    }
19074
19075    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19076        self.blink_manager.update(cx, BlinkManager::disable);
19077        self.buffer
19078            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19079
19080        if let Some(blame) = self.blame.as_ref() {
19081            blame.update(cx, GitBlame::blur)
19082        }
19083        if !self.hover_state.focused(window, cx) {
19084            hide_hover(self, cx);
19085        }
19086        if !self
19087            .context_menu
19088            .borrow()
19089            .as_ref()
19090            .is_some_and(|context_menu| context_menu.focused(window, cx))
19091        {
19092            self.hide_context_menu(window, cx);
19093        }
19094        self.discard_inline_completion(false, cx);
19095        cx.emit(EditorEvent::Blurred);
19096        cx.notify();
19097    }
19098
19099    pub fn register_action<A: Action>(
19100        &mut self,
19101        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19102    ) -> Subscription {
19103        let id = self.next_editor_action_id.post_inc();
19104        let listener = Arc::new(listener);
19105        self.editor_actions.borrow_mut().insert(
19106            id,
19107            Box::new(move |window, _| {
19108                let listener = listener.clone();
19109                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19110                    let action = action.downcast_ref().unwrap();
19111                    if phase == DispatchPhase::Bubble {
19112                        listener(action, window, cx)
19113                    }
19114                })
19115            }),
19116        );
19117
19118        let editor_actions = self.editor_actions.clone();
19119        Subscription::new(move || {
19120            editor_actions.borrow_mut().remove(&id);
19121        })
19122    }
19123
19124    pub fn file_header_size(&self) -> u32 {
19125        FILE_HEADER_HEIGHT
19126    }
19127
19128    pub fn restore(
19129        &mut self,
19130        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19131        window: &mut Window,
19132        cx: &mut Context<Self>,
19133    ) {
19134        let workspace = self.workspace();
19135        let project = self.project.as_ref();
19136        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19137            let mut tasks = Vec::new();
19138            for (buffer_id, changes) in revert_changes {
19139                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19140                    buffer.update(cx, |buffer, cx| {
19141                        buffer.edit(
19142                            changes
19143                                .into_iter()
19144                                .map(|(range, text)| (range, text.to_string())),
19145                            None,
19146                            cx,
19147                        );
19148                    });
19149
19150                    if let Some(project) =
19151                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19152                    {
19153                        project.update(cx, |project, cx| {
19154                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19155                        })
19156                    }
19157                }
19158            }
19159            tasks
19160        });
19161        cx.spawn_in(window, async move |_, cx| {
19162            for (buffer, task) in save_tasks {
19163                let result = task.await;
19164                if result.is_err() {
19165                    let Some(path) = buffer
19166                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19167                        .ok()
19168                    else {
19169                        continue;
19170                    };
19171                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19172                        let Some(task) = cx
19173                            .update_window_entity(&workspace, |workspace, window, cx| {
19174                                workspace
19175                                    .open_path_preview(path, None, false, false, false, window, cx)
19176                            })
19177                            .ok()
19178                        else {
19179                            continue;
19180                        };
19181                        task.await.log_err();
19182                    }
19183                }
19184            }
19185        })
19186        .detach();
19187        self.change_selections(None, window, cx, |selections| selections.refresh());
19188    }
19189
19190    pub fn to_pixel_point(
19191        &self,
19192        source: multi_buffer::Anchor,
19193        editor_snapshot: &EditorSnapshot,
19194        window: &mut Window,
19195    ) -> Option<gpui::Point<Pixels>> {
19196        let source_point = source.to_display_point(editor_snapshot);
19197        self.display_to_pixel_point(source_point, editor_snapshot, window)
19198    }
19199
19200    pub fn display_to_pixel_point(
19201        &self,
19202        source: DisplayPoint,
19203        editor_snapshot: &EditorSnapshot,
19204        window: &mut Window,
19205    ) -> Option<gpui::Point<Pixels>> {
19206        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19207        let text_layout_details = self.text_layout_details(window);
19208        let scroll_top = text_layout_details
19209            .scroll_anchor
19210            .scroll_position(editor_snapshot)
19211            .y;
19212
19213        if source.row().as_f32() < scroll_top.floor() {
19214            return None;
19215        }
19216        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19217        let source_y = line_height * (source.row().as_f32() - scroll_top);
19218        Some(gpui::Point::new(source_x, source_y))
19219    }
19220
19221    pub fn has_visible_completions_menu(&self) -> bool {
19222        !self.edit_prediction_preview_is_active()
19223            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19224                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19225            })
19226    }
19227
19228    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19229        if self.mode.is_minimap() {
19230            return;
19231        }
19232        self.addons
19233            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19234    }
19235
19236    pub fn unregister_addon<T: Addon>(&mut self) {
19237        self.addons.remove(&std::any::TypeId::of::<T>());
19238    }
19239
19240    pub fn addon<T: Addon>(&self) -> Option<&T> {
19241        let type_id = std::any::TypeId::of::<T>();
19242        self.addons
19243            .get(&type_id)
19244            .and_then(|item| item.to_any().downcast_ref::<T>())
19245    }
19246
19247    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19248        let type_id = std::any::TypeId::of::<T>();
19249        self.addons
19250            .get_mut(&type_id)
19251            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19252    }
19253
19254    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19255        let text_layout_details = self.text_layout_details(window);
19256        let style = &text_layout_details.editor_style;
19257        let font_id = window.text_system().resolve_font(&style.text.font());
19258        let font_size = style.text.font_size.to_pixels(window.rem_size());
19259        let line_height = style.text.line_height_in_pixels(window.rem_size());
19260        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19261
19262        gpui::Size::new(em_width, line_height)
19263    }
19264
19265    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19266        self.load_diff_task.clone()
19267    }
19268
19269    fn read_metadata_from_db(
19270        &mut self,
19271        item_id: u64,
19272        workspace_id: WorkspaceId,
19273        window: &mut Window,
19274        cx: &mut Context<Editor>,
19275    ) {
19276        if self.is_singleton(cx)
19277            && !self.mode.is_minimap()
19278            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19279        {
19280            let buffer_snapshot = OnceCell::new();
19281
19282            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19283                if !folds.is_empty() {
19284                    let snapshot =
19285                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19286                    self.fold_ranges(
19287                        folds
19288                            .into_iter()
19289                            .map(|(start, end)| {
19290                                snapshot.clip_offset(start, Bias::Left)
19291                                    ..snapshot.clip_offset(end, Bias::Right)
19292                            })
19293                            .collect(),
19294                        false,
19295                        window,
19296                        cx,
19297                    );
19298                }
19299            }
19300
19301            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19302                if !selections.is_empty() {
19303                    let snapshot =
19304                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19305                    self.change_selections(None, window, cx, |s| {
19306                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19307                            snapshot.clip_offset(start, Bias::Left)
19308                                ..snapshot.clip_offset(end, Bias::Right)
19309                        }));
19310                    });
19311                }
19312            };
19313        }
19314
19315        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19316    }
19317}
19318
19319fn vim_enabled(cx: &App) -> bool {
19320    cx.global::<SettingsStore>()
19321        .raw_user_settings()
19322        .get("vim_mode")
19323        == Some(&serde_json::Value::Bool(true))
19324}
19325
19326// Consider user intent and default settings
19327fn choose_completion_range(
19328    completion: &Completion,
19329    intent: CompletionIntent,
19330    buffer: &Entity<Buffer>,
19331    cx: &mut Context<Editor>,
19332) -> Range<usize> {
19333    fn should_replace(
19334        completion: &Completion,
19335        insert_range: &Range<text::Anchor>,
19336        intent: CompletionIntent,
19337        completion_mode_setting: LspInsertMode,
19338        buffer: &Buffer,
19339    ) -> bool {
19340        // specific actions take precedence over settings
19341        match intent {
19342            CompletionIntent::CompleteWithInsert => return false,
19343            CompletionIntent::CompleteWithReplace => return true,
19344            CompletionIntent::Complete | CompletionIntent::Compose => {}
19345        }
19346
19347        match completion_mode_setting {
19348            LspInsertMode::Insert => false,
19349            LspInsertMode::Replace => true,
19350            LspInsertMode::ReplaceSubsequence => {
19351                let mut text_to_replace = buffer.chars_for_range(
19352                    buffer.anchor_before(completion.replace_range.start)
19353                        ..buffer.anchor_after(completion.replace_range.end),
19354                );
19355                let mut completion_text = completion.new_text.chars();
19356
19357                // is `text_to_replace` a subsequence of `completion_text`
19358                text_to_replace
19359                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19360            }
19361            LspInsertMode::ReplaceSuffix => {
19362                let range_after_cursor = insert_range.end..completion.replace_range.end;
19363
19364                let text_after_cursor = buffer
19365                    .text_for_range(
19366                        buffer.anchor_before(range_after_cursor.start)
19367                            ..buffer.anchor_after(range_after_cursor.end),
19368                    )
19369                    .collect::<String>();
19370                completion.new_text.ends_with(&text_after_cursor)
19371            }
19372        }
19373    }
19374
19375    let buffer = buffer.read(cx);
19376
19377    if let CompletionSource::Lsp {
19378        insert_range: Some(insert_range),
19379        ..
19380    } = &completion.source
19381    {
19382        let completion_mode_setting =
19383            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19384                .completions
19385                .lsp_insert_mode;
19386
19387        if !should_replace(
19388            completion,
19389            &insert_range,
19390            intent,
19391            completion_mode_setting,
19392            buffer,
19393        ) {
19394            return insert_range.to_offset(buffer);
19395        }
19396    }
19397
19398    completion.replace_range.to_offset(buffer)
19399}
19400
19401fn insert_extra_newline_brackets(
19402    buffer: &MultiBufferSnapshot,
19403    range: Range<usize>,
19404    language: &language::LanguageScope,
19405) -> bool {
19406    let leading_whitespace_len = buffer
19407        .reversed_chars_at(range.start)
19408        .take_while(|c| c.is_whitespace() && *c != '\n')
19409        .map(|c| c.len_utf8())
19410        .sum::<usize>();
19411    let trailing_whitespace_len = buffer
19412        .chars_at(range.end)
19413        .take_while(|c| c.is_whitespace() && *c != '\n')
19414        .map(|c| c.len_utf8())
19415        .sum::<usize>();
19416    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19417
19418    language.brackets().any(|(pair, enabled)| {
19419        let pair_start = pair.start.trim_end();
19420        let pair_end = pair.end.trim_start();
19421
19422        enabled
19423            && pair.newline
19424            && buffer.contains_str_at(range.end, pair_end)
19425            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19426    })
19427}
19428
19429fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19430    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19431        [(buffer, range, _)] => (*buffer, range.clone()),
19432        _ => return false,
19433    };
19434    let pair = {
19435        let mut result: Option<BracketMatch> = None;
19436
19437        for pair in buffer
19438            .all_bracket_ranges(range.clone())
19439            .filter(move |pair| {
19440                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19441            })
19442        {
19443            let len = pair.close_range.end - pair.open_range.start;
19444
19445            if let Some(existing) = &result {
19446                let existing_len = existing.close_range.end - existing.open_range.start;
19447                if len > existing_len {
19448                    continue;
19449                }
19450            }
19451
19452            result = Some(pair);
19453        }
19454
19455        result
19456    };
19457    let Some(pair) = pair else {
19458        return false;
19459    };
19460    pair.newline_only
19461        && buffer
19462            .chars_for_range(pair.open_range.end..range.start)
19463            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19464            .all(|c| c.is_whitespace() && c != '\n')
19465}
19466
19467fn update_uncommitted_diff_for_buffer(
19468    editor: Entity<Editor>,
19469    project: &Entity<Project>,
19470    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19471    buffer: Entity<MultiBuffer>,
19472    cx: &mut App,
19473) -> Task<()> {
19474    let mut tasks = Vec::new();
19475    project.update(cx, |project, cx| {
19476        for buffer in buffers {
19477            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19478                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19479            }
19480        }
19481    });
19482    cx.spawn(async move |cx| {
19483        let diffs = future::join_all(tasks).await;
19484        if editor
19485            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19486            .unwrap_or(false)
19487        {
19488            return;
19489        }
19490
19491        buffer
19492            .update(cx, |buffer, cx| {
19493                for diff in diffs.into_iter().flatten() {
19494                    buffer.add_diff(diff, cx);
19495                }
19496            })
19497            .ok();
19498    })
19499}
19500
19501pub trait CollaborationHub {
19502    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19503    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19504    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19505}
19506
19507impl CollaborationHub for Entity<Project> {
19508    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19509        self.read(cx).collaborators()
19510    }
19511
19512    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19513        self.read(cx).user_store().read(cx).participant_indices()
19514    }
19515
19516    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19517        let this = self.read(cx);
19518        let user_ids = this.collaborators().values().map(|c| c.user_id);
19519        this.user_store().read_with(cx, |user_store, cx| {
19520            user_store.participant_names(user_ids, cx)
19521        })
19522    }
19523}
19524
19525pub trait SemanticsProvider {
19526    fn hover(
19527        &self,
19528        buffer: &Entity<Buffer>,
19529        position: text::Anchor,
19530        cx: &mut App,
19531    ) -> Option<Task<Vec<project::Hover>>>;
19532
19533    fn inline_values(
19534        &self,
19535        buffer_handle: Entity<Buffer>,
19536        range: Range<text::Anchor>,
19537        cx: &mut App,
19538    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19539
19540    fn inlay_hints(
19541        &self,
19542        buffer_handle: Entity<Buffer>,
19543        range: Range<text::Anchor>,
19544        cx: &mut App,
19545    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19546
19547    fn resolve_inlay_hint(
19548        &self,
19549        hint: InlayHint,
19550        buffer_handle: Entity<Buffer>,
19551        server_id: LanguageServerId,
19552        cx: &mut App,
19553    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19554
19555    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19556
19557    fn document_highlights(
19558        &self,
19559        buffer: &Entity<Buffer>,
19560        position: text::Anchor,
19561        cx: &mut App,
19562    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19563
19564    fn definitions(
19565        &self,
19566        buffer: &Entity<Buffer>,
19567        position: text::Anchor,
19568        kind: GotoDefinitionKind,
19569        cx: &mut App,
19570    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19571
19572    fn range_for_rename(
19573        &self,
19574        buffer: &Entity<Buffer>,
19575        position: text::Anchor,
19576        cx: &mut App,
19577    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19578
19579    fn perform_rename(
19580        &self,
19581        buffer: &Entity<Buffer>,
19582        position: text::Anchor,
19583        new_name: String,
19584        cx: &mut App,
19585    ) -> Option<Task<Result<ProjectTransaction>>>;
19586}
19587
19588pub trait CompletionProvider {
19589    fn completions(
19590        &self,
19591        excerpt_id: ExcerptId,
19592        buffer: &Entity<Buffer>,
19593        buffer_position: text::Anchor,
19594        trigger: CompletionContext,
19595        window: &mut Window,
19596        cx: &mut Context<Editor>,
19597    ) -> Task<Result<Option<Vec<Completion>>>>;
19598
19599    fn resolve_completions(
19600        &self,
19601        buffer: Entity<Buffer>,
19602        completion_indices: Vec<usize>,
19603        completions: Rc<RefCell<Box<[Completion]>>>,
19604        cx: &mut Context<Editor>,
19605    ) -> Task<Result<bool>>;
19606
19607    fn apply_additional_edits_for_completion(
19608        &self,
19609        _buffer: Entity<Buffer>,
19610        _completions: Rc<RefCell<Box<[Completion]>>>,
19611        _completion_index: usize,
19612        _push_to_history: bool,
19613        _cx: &mut Context<Editor>,
19614    ) -> Task<Result<Option<language::Transaction>>> {
19615        Task::ready(Ok(None))
19616    }
19617
19618    fn is_completion_trigger(
19619        &self,
19620        buffer: &Entity<Buffer>,
19621        position: language::Anchor,
19622        text: &str,
19623        trigger_in_words: bool,
19624        cx: &mut Context<Editor>,
19625    ) -> bool;
19626
19627    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
19628
19629    fn sort_completions(&self) -> bool {
19630        true
19631    }
19632
19633    fn filter_completions(&self) -> bool {
19634        true
19635    }
19636}
19637
19638pub trait CodeActionProvider {
19639    fn id(&self) -> Arc<str>;
19640
19641    fn code_actions(
19642        &self,
19643        buffer: &Entity<Buffer>,
19644        range: Range<text::Anchor>,
19645        window: &mut Window,
19646        cx: &mut App,
19647    ) -> Task<Result<Vec<CodeAction>>>;
19648
19649    fn apply_code_action(
19650        &self,
19651        buffer_handle: Entity<Buffer>,
19652        action: CodeAction,
19653        excerpt_id: ExcerptId,
19654        push_to_history: bool,
19655        window: &mut Window,
19656        cx: &mut App,
19657    ) -> Task<Result<ProjectTransaction>>;
19658}
19659
19660impl CodeActionProvider for Entity<Project> {
19661    fn id(&self) -> Arc<str> {
19662        "project".into()
19663    }
19664
19665    fn code_actions(
19666        &self,
19667        buffer: &Entity<Buffer>,
19668        range: Range<text::Anchor>,
19669        _window: &mut Window,
19670        cx: &mut App,
19671    ) -> Task<Result<Vec<CodeAction>>> {
19672        self.update(cx, |project, cx| {
19673            let code_lens = project.code_lens(buffer, range.clone(), cx);
19674            let code_actions = project.code_actions(buffer, range, None, cx);
19675            cx.background_spawn(async move {
19676                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19677                Ok(code_lens
19678                    .context("code lens fetch")?
19679                    .into_iter()
19680                    .chain(code_actions.context("code action fetch")?)
19681                    .collect())
19682            })
19683        })
19684    }
19685
19686    fn apply_code_action(
19687        &self,
19688        buffer_handle: Entity<Buffer>,
19689        action: CodeAction,
19690        _excerpt_id: ExcerptId,
19691        push_to_history: bool,
19692        _window: &mut Window,
19693        cx: &mut App,
19694    ) -> Task<Result<ProjectTransaction>> {
19695        self.update(cx, |project, cx| {
19696            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19697        })
19698    }
19699}
19700
19701fn snippet_completions(
19702    project: &Project,
19703    buffer: &Entity<Buffer>,
19704    buffer_position: text::Anchor,
19705    cx: &mut App,
19706) -> Task<Result<Vec<Completion>>> {
19707    let languages = buffer.read(cx).languages_at(buffer_position);
19708    let snippet_store = project.snippets().read(cx);
19709
19710    let scopes: Vec<_> = languages
19711        .iter()
19712        .filter_map(|language| {
19713            let language_name = language.lsp_id();
19714            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19715
19716            if snippets.is_empty() {
19717                None
19718            } else {
19719                Some((language.default_scope(), snippets))
19720            }
19721        })
19722        .collect();
19723
19724    if scopes.is_empty() {
19725        return Task::ready(Ok(vec![]));
19726    }
19727
19728    let snapshot = buffer.read(cx).text_snapshot();
19729    let chars: String = snapshot
19730        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19731        .collect();
19732    let executor = cx.background_executor().clone();
19733
19734    cx.background_spawn(async move {
19735        let mut all_results: Vec<Completion> = Vec::new();
19736        for (scope, snippets) in scopes.into_iter() {
19737            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19738            let mut last_word = chars
19739                .chars()
19740                .take_while(|c| classifier.is_word(*c))
19741                .collect::<String>();
19742            last_word = last_word.chars().rev().collect();
19743
19744            if last_word.is_empty() {
19745                return Ok(vec![]);
19746            }
19747
19748            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19749            let to_lsp = |point: &text::Anchor| {
19750                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19751                point_to_lsp(end)
19752            };
19753            let lsp_end = to_lsp(&buffer_position);
19754
19755            let candidates = snippets
19756                .iter()
19757                .enumerate()
19758                .flat_map(|(ix, snippet)| {
19759                    snippet
19760                        .prefix
19761                        .iter()
19762                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19763                })
19764                .collect::<Vec<StringMatchCandidate>>();
19765
19766            let mut matches = fuzzy::match_strings(
19767                &candidates,
19768                &last_word,
19769                last_word.chars().any(|c| c.is_uppercase()),
19770                100,
19771                &Default::default(),
19772                executor.clone(),
19773            )
19774            .await;
19775
19776            // Remove all candidates where the query's start does not match the start of any word in the candidate
19777            if let Some(query_start) = last_word.chars().next() {
19778                matches.retain(|string_match| {
19779                    split_words(&string_match.string).any(|word| {
19780                        // Check that the first codepoint of the word as lowercase matches the first
19781                        // codepoint of the query as lowercase
19782                        word.chars()
19783                            .flat_map(|codepoint| codepoint.to_lowercase())
19784                            .zip(query_start.to_lowercase())
19785                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19786                    })
19787                });
19788            }
19789
19790            let matched_strings = matches
19791                .into_iter()
19792                .map(|m| m.string)
19793                .collect::<HashSet<_>>();
19794
19795            let mut result: Vec<Completion> = snippets
19796                .iter()
19797                .filter_map(|snippet| {
19798                    let matching_prefix = snippet
19799                        .prefix
19800                        .iter()
19801                        .find(|prefix| matched_strings.contains(*prefix))?;
19802                    let start = as_offset - last_word.len();
19803                    let start = snapshot.anchor_before(start);
19804                    let range = start..buffer_position;
19805                    let lsp_start = to_lsp(&start);
19806                    let lsp_range = lsp::Range {
19807                        start: lsp_start,
19808                        end: lsp_end,
19809                    };
19810                    Some(Completion {
19811                        replace_range: range,
19812                        new_text: snippet.body.clone(),
19813                        source: CompletionSource::Lsp {
19814                            insert_range: None,
19815                            server_id: LanguageServerId(usize::MAX),
19816                            resolved: true,
19817                            lsp_completion: Box::new(lsp::CompletionItem {
19818                                label: snippet.prefix.first().unwrap().clone(),
19819                                kind: Some(CompletionItemKind::SNIPPET),
19820                                label_details: snippet.description.as_ref().map(|description| {
19821                                    lsp::CompletionItemLabelDetails {
19822                                        detail: Some(description.clone()),
19823                                        description: None,
19824                                    }
19825                                }),
19826                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19827                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19828                                    lsp::InsertReplaceEdit {
19829                                        new_text: snippet.body.clone(),
19830                                        insert: lsp_range,
19831                                        replace: lsp_range,
19832                                    },
19833                                )),
19834                                filter_text: Some(snippet.body.clone()),
19835                                sort_text: Some(char::MAX.to_string()),
19836                                ..lsp::CompletionItem::default()
19837                            }),
19838                            lsp_defaults: None,
19839                        },
19840                        label: CodeLabel {
19841                            text: matching_prefix.clone(),
19842                            runs: Vec::new(),
19843                            filter_range: 0..matching_prefix.len(),
19844                        },
19845                        icon_path: None,
19846                        documentation: Some(
19847                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
19848                                single_line: snippet.name.clone().into(),
19849                                plain_text: snippet
19850                                    .description
19851                                    .clone()
19852                                    .map(|description| description.into()),
19853                            },
19854                        ),
19855                        insert_text_mode: None,
19856                        confirm: None,
19857                    })
19858                })
19859                .collect();
19860
19861            all_results.append(&mut result);
19862        }
19863
19864        Ok(all_results)
19865    })
19866}
19867
19868impl CompletionProvider for Entity<Project> {
19869    fn completions(
19870        &self,
19871        _excerpt_id: ExcerptId,
19872        buffer: &Entity<Buffer>,
19873        buffer_position: text::Anchor,
19874        options: CompletionContext,
19875        _window: &mut Window,
19876        cx: &mut Context<Editor>,
19877    ) -> Task<Result<Option<Vec<Completion>>>> {
19878        self.update(cx, |project, cx| {
19879            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19880            let project_completions = project.completions(buffer, buffer_position, options, cx);
19881            cx.background_spawn(async move {
19882                let snippets_completions = snippets.await?;
19883                match project_completions.await? {
19884                    Some(mut completions) => {
19885                        completions.extend(snippets_completions);
19886                        Ok(Some(completions))
19887                    }
19888                    None => {
19889                        if snippets_completions.is_empty() {
19890                            Ok(None)
19891                        } else {
19892                            Ok(Some(snippets_completions))
19893                        }
19894                    }
19895                }
19896            })
19897        })
19898    }
19899
19900    fn resolve_completions(
19901        &self,
19902        buffer: Entity<Buffer>,
19903        completion_indices: Vec<usize>,
19904        completions: Rc<RefCell<Box<[Completion]>>>,
19905        cx: &mut Context<Editor>,
19906    ) -> Task<Result<bool>> {
19907        self.update(cx, |project, cx| {
19908            project.lsp_store().update(cx, |lsp_store, cx| {
19909                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19910            })
19911        })
19912    }
19913
19914    fn apply_additional_edits_for_completion(
19915        &self,
19916        buffer: Entity<Buffer>,
19917        completions: Rc<RefCell<Box<[Completion]>>>,
19918        completion_index: usize,
19919        push_to_history: bool,
19920        cx: &mut Context<Editor>,
19921    ) -> Task<Result<Option<language::Transaction>>> {
19922        self.update(cx, |project, cx| {
19923            project.lsp_store().update(cx, |lsp_store, cx| {
19924                lsp_store.apply_additional_edits_for_completion(
19925                    buffer,
19926                    completions,
19927                    completion_index,
19928                    push_to_history,
19929                    cx,
19930                )
19931            })
19932        })
19933    }
19934
19935    fn is_completion_trigger(
19936        &self,
19937        buffer: &Entity<Buffer>,
19938        position: language::Anchor,
19939        text: &str,
19940        trigger_in_words: bool,
19941        cx: &mut Context<Editor>,
19942    ) -> bool {
19943        let mut chars = text.chars();
19944        let char = if let Some(char) = chars.next() {
19945            char
19946        } else {
19947            return false;
19948        };
19949        if chars.next().is_some() {
19950            return false;
19951        }
19952
19953        let buffer = buffer.read(cx);
19954        let snapshot = buffer.snapshot();
19955        if !snapshot.settings_at(position, cx).show_completions_on_input {
19956            return false;
19957        }
19958        let classifier = snapshot.char_classifier_at(position).for_completion(true);
19959        if trigger_in_words && classifier.is_word(char) {
19960            return true;
19961        }
19962
19963        buffer.completion_triggers().contains(text)
19964    }
19965}
19966
19967impl SemanticsProvider for Entity<Project> {
19968    fn hover(
19969        &self,
19970        buffer: &Entity<Buffer>,
19971        position: text::Anchor,
19972        cx: &mut App,
19973    ) -> Option<Task<Vec<project::Hover>>> {
19974        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
19975    }
19976
19977    fn document_highlights(
19978        &self,
19979        buffer: &Entity<Buffer>,
19980        position: text::Anchor,
19981        cx: &mut App,
19982    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
19983        Some(self.update(cx, |project, cx| {
19984            project.document_highlights(buffer, position, cx)
19985        }))
19986    }
19987
19988    fn definitions(
19989        &self,
19990        buffer: &Entity<Buffer>,
19991        position: text::Anchor,
19992        kind: GotoDefinitionKind,
19993        cx: &mut App,
19994    ) -> Option<Task<Result<Vec<LocationLink>>>> {
19995        Some(self.update(cx, |project, cx| match kind {
19996            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
19997            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
19998            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
19999            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20000        }))
20001    }
20002
20003    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20004        // TODO: make this work for remote projects
20005        self.update(cx, |project, cx| {
20006            if project
20007                .active_debug_session(cx)
20008                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20009            {
20010                return true;
20011            }
20012
20013            buffer.update(cx, |buffer, cx| {
20014                project.any_language_server_supports_inlay_hints(buffer, cx)
20015            })
20016        })
20017    }
20018
20019    fn inline_values(
20020        &self,
20021        buffer_handle: Entity<Buffer>,
20022
20023        range: Range<text::Anchor>,
20024        cx: &mut App,
20025    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20026        self.update(cx, |project, cx| {
20027            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20028
20029            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20030        })
20031    }
20032
20033    fn inlay_hints(
20034        &self,
20035        buffer_handle: Entity<Buffer>,
20036        range: Range<text::Anchor>,
20037        cx: &mut App,
20038    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20039        Some(self.update(cx, |project, cx| {
20040            project.inlay_hints(buffer_handle, range, cx)
20041        }))
20042    }
20043
20044    fn resolve_inlay_hint(
20045        &self,
20046        hint: InlayHint,
20047        buffer_handle: Entity<Buffer>,
20048        server_id: LanguageServerId,
20049        cx: &mut App,
20050    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20051        Some(self.update(cx, |project, cx| {
20052            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20053        }))
20054    }
20055
20056    fn range_for_rename(
20057        &self,
20058        buffer: &Entity<Buffer>,
20059        position: text::Anchor,
20060        cx: &mut App,
20061    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20062        Some(self.update(cx, |project, cx| {
20063            let buffer = buffer.clone();
20064            let task = project.prepare_rename(buffer.clone(), position, cx);
20065            cx.spawn(async move |_, cx| {
20066                Ok(match task.await? {
20067                    PrepareRenameResponse::Success(range) => Some(range),
20068                    PrepareRenameResponse::InvalidPosition => None,
20069                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20070                        // Fallback on using TreeSitter info to determine identifier range
20071                        buffer.update(cx, |buffer, _| {
20072                            let snapshot = buffer.snapshot();
20073                            let (range, kind) = snapshot.surrounding_word(position);
20074                            if kind != Some(CharKind::Word) {
20075                                return None;
20076                            }
20077                            Some(
20078                                snapshot.anchor_before(range.start)
20079                                    ..snapshot.anchor_after(range.end),
20080                            )
20081                        })?
20082                    }
20083                })
20084            })
20085        }))
20086    }
20087
20088    fn perform_rename(
20089        &self,
20090        buffer: &Entity<Buffer>,
20091        position: text::Anchor,
20092        new_name: String,
20093        cx: &mut App,
20094    ) -> Option<Task<Result<ProjectTransaction>>> {
20095        Some(self.update(cx, |project, cx| {
20096            project.perform_rename(buffer.clone(), position, new_name, cx)
20097        }))
20098    }
20099}
20100
20101fn inlay_hint_settings(
20102    location: Anchor,
20103    snapshot: &MultiBufferSnapshot,
20104    cx: &mut Context<Editor>,
20105) -> InlayHintSettings {
20106    let file = snapshot.file_at(location);
20107    let language = snapshot.language_at(location).map(|l| l.name());
20108    language_settings(language, file, cx).inlay_hints
20109}
20110
20111fn consume_contiguous_rows(
20112    contiguous_row_selections: &mut Vec<Selection<Point>>,
20113    selection: &Selection<Point>,
20114    display_map: &DisplaySnapshot,
20115    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20116) -> (MultiBufferRow, MultiBufferRow) {
20117    contiguous_row_selections.push(selection.clone());
20118    let start_row = MultiBufferRow(selection.start.row);
20119    let mut end_row = ending_row(selection, display_map);
20120
20121    while let Some(next_selection) = selections.peek() {
20122        if next_selection.start.row <= end_row.0 {
20123            end_row = ending_row(next_selection, display_map);
20124            contiguous_row_selections.push(selections.next().unwrap().clone());
20125        } else {
20126            break;
20127        }
20128    }
20129    (start_row, end_row)
20130}
20131
20132fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20133    if next_selection.end.column > 0 || next_selection.is_empty() {
20134        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20135    } else {
20136        MultiBufferRow(next_selection.end.row)
20137    }
20138}
20139
20140impl EditorSnapshot {
20141    pub fn remote_selections_in_range<'a>(
20142        &'a self,
20143        range: &'a Range<Anchor>,
20144        collaboration_hub: &dyn CollaborationHub,
20145        cx: &'a App,
20146    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20147        let participant_names = collaboration_hub.user_names(cx);
20148        let participant_indices = collaboration_hub.user_participant_indices(cx);
20149        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20150        let collaborators_by_replica_id = collaborators_by_peer_id
20151            .values()
20152            .map(|collaborator| (collaborator.replica_id, collaborator))
20153            .collect::<HashMap<_, _>>();
20154        self.buffer_snapshot
20155            .selections_in_range(range, false)
20156            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20157                if replica_id == AGENT_REPLICA_ID {
20158                    Some(RemoteSelection {
20159                        replica_id,
20160                        selection,
20161                        cursor_shape,
20162                        line_mode,
20163                        collaborator_id: CollaboratorId::Agent,
20164                        user_name: Some("Agent".into()),
20165                        color: cx.theme().players().agent(),
20166                    })
20167                } else {
20168                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20169                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20170                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20171                    Some(RemoteSelection {
20172                        replica_id,
20173                        selection,
20174                        cursor_shape,
20175                        line_mode,
20176                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20177                        user_name,
20178                        color: if let Some(index) = participant_index {
20179                            cx.theme().players().color_for_participant(index.0)
20180                        } else {
20181                            cx.theme().players().absent()
20182                        },
20183                    })
20184                }
20185            })
20186    }
20187
20188    pub fn hunks_for_ranges(
20189        &self,
20190        ranges: impl IntoIterator<Item = Range<Point>>,
20191    ) -> Vec<MultiBufferDiffHunk> {
20192        let mut hunks = Vec::new();
20193        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20194            HashMap::default();
20195        for query_range in ranges {
20196            let query_rows =
20197                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20198            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20199                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20200            ) {
20201                // Include deleted hunks that are adjacent to the query range, because
20202                // otherwise they would be missed.
20203                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20204                if hunk.status().is_deleted() {
20205                    intersects_range |= hunk.row_range.start == query_rows.end;
20206                    intersects_range |= hunk.row_range.end == query_rows.start;
20207                }
20208                if intersects_range {
20209                    if !processed_buffer_rows
20210                        .entry(hunk.buffer_id)
20211                        .or_default()
20212                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20213                    {
20214                        continue;
20215                    }
20216                    hunks.push(hunk);
20217                }
20218            }
20219        }
20220
20221        hunks
20222    }
20223
20224    fn display_diff_hunks_for_rows<'a>(
20225        &'a self,
20226        display_rows: Range<DisplayRow>,
20227        folded_buffers: &'a HashSet<BufferId>,
20228    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20229        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20230        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20231
20232        self.buffer_snapshot
20233            .diff_hunks_in_range(buffer_start..buffer_end)
20234            .filter_map(|hunk| {
20235                if folded_buffers.contains(&hunk.buffer_id) {
20236                    return None;
20237                }
20238
20239                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20240                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20241
20242                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20243                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20244
20245                let display_hunk = if hunk_display_start.column() != 0 {
20246                    DisplayDiffHunk::Folded {
20247                        display_row: hunk_display_start.row(),
20248                    }
20249                } else {
20250                    let mut end_row = hunk_display_end.row();
20251                    if hunk_display_end.column() > 0 {
20252                        end_row.0 += 1;
20253                    }
20254                    let is_created_file = hunk.is_created_file();
20255                    DisplayDiffHunk::Unfolded {
20256                        status: hunk.status(),
20257                        diff_base_byte_range: hunk.diff_base_byte_range,
20258                        display_row_range: hunk_display_start.row()..end_row,
20259                        multi_buffer_range: Anchor::range_in_buffer(
20260                            hunk.excerpt_id,
20261                            hunk.buffer_id,
20262                            hunk.buffer_range,
20263                        ),
20264                        is_created_file,
20265                    }
20266                };
20267
20268                Some(display_hunk)
20269            })
20270    }
20271
20272    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20273        self.display_snapshot.buffer_snapshot.language_at(position)
20274    }
20275
20276    pub fn is_focused(&self) -> bool {
20277        self.is_focused
20278    }
20279
20280    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20281        self.placeholder_text.as_ref()
20282    }
20283
20284    pub fn scroll_position(&self) -> gpui::Point<f32> {
20285        self.scroll_anchor.scroll_position(&self.display_snapshot)
20286    }
20287
20288    fn gutter_dimensions(
20289        &self,
20290        font_id: FontId,
20291        font_size: Pixels,
20292        max_line_number_width: Pixels,
20293        cx: &App,
20294    ) -> Option<GutterDimensions> {
20295        if !self.show_gutter {
20296            return None;
20297        }
20298
20299        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20300        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20301
20302        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20303            matches!(
20304                ProjectSettings::get_global(cx).git.git_gutter,
20305                Some(GitGutterSetting::TrackedFiles)
20306            )
20307        });
20308        let gutter_settings = EditorSettings::get_global(cx).gutter;
20309        let show_line_numbers = self
20310            .show_line_numbers
20311            .unwrap_or(gutter_settings.line_numbers);
20312        let line_gutter_width = if show_line_numbers {
20313            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20314            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20315            max_line_number_width.max(min_width_for_number_on_gutter)
20316        } else {
20317            0.0.into()
20318        };
20319
20320        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20321        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20322
20323        let git_blame_entries_width =
20324            self.git_blame_gutter_max_author_length
20325                .map(|max_author_length| {
20326                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20327                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20328
20329                    /// The number of characters to dedicate to gaps and margins.
20330                    const SPACING_WIDTH: usize = 4;
20331
20332                    let max_char_count = max_author_length.min(renderer.max_author_length())
20333                        + ::git::SHORT_SHA_LENGTH
20334                        + MAX_RELATIVE_TIMESTAMP.len()
20335                        + SPACING_WIDTH;
20336
20337                    em_advance * max_char_count
20338                });
20339
20340        let is_singleton = self.buffer_snapshot.is_singleton();
20341
20342        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20343        left_padding += if !is_singleton {
20344            em_width * 4.0
20345        } else if show_runnables || show_breakpoints {
20346            em_width * 3.0
20347        } else if show_git_gutter && show_line_numbers {
20348            em_width * 2.0
20349        } else if show_git_gutter || show_line_numbers {
20350            em_width
20351        } else {
20352            px(0.)
20353        };
20354
20355        let shows_folds = is_singleton && gutter_settings.folds;
20356
20357        let right_padding = if shows_folds && show_line_numbers {
20358            em_width * 4.0
20359        } else if shows_folds || (!is_singleton && show_line_numbers) {
20360            em_width * 3.0
20361        } else if show_line_numbers {
20362            em_width
20363        } else {
20364            px(0.)
20365        };
20366
20367        Some(GutterDimensions {
20368            left_padding,
20369            right_padding,
20370            width: line_gutter_width + left_padding + right_padding,
20371            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20372            git_blame_entries_width,
20373        })
20374    }
20375
20376    pub fn render_crease_toggle(
20377        &self,
20378        buffer_row: MultiBufferRow,
20379        row_contains_cursor: bool,
20380        editor: Entity<Editor>,
20381        window: &mut Window,
20382        cx: &mut App,
20383    ) -> Option<AnyElement> {
20384        let folded = self.is_line_folded(buffer_row);
20385        let mut is_foldable = false;
20386
20387        if let Some(crease) = self
20388            .crease_snapshot
20389            .query_row(buffer_row, &self.buffer_snapshot)
20390        {
20391            is_foldable = true;
20392            match crease {
20393                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20394                    if let Some(render_toggle) = render_toggle {
20395                        let toggle_callback =
20396                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20397                                if folded {
20398                                    editor.update(cx, |editor, cx| {
20399                                        editor.fold_at(buffer_row, window, cx)
20400                                    });
20401                                } else {
20402                                    editor.update(cx, |editor, cx| {
20403                                        editor.unfold_at(buffer_row, window, cx)
20404                                    });
20405                                }
20406                            });
20407                        return Some((render_toggle)(
20408                            buffer_row,
20409                            folded,
20410                            toggle_callback,
20411                            window,
20412                            cx,
20413                        ));
20414                    }
20415                }
20416            }
20417        }
20418
20419        is_foldable |= self.starts_indent(buffer_row);
20420
20421        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20422            Some(
20423                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20424                    .toggle_state(folded)
20425                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20426                        if folded {
20427                            this.unfold_at(buffer_row, window, cx);
20428                        } else {
20429                            this.fold_at(buffer_row, window, cx);
20430                        }
20431                    }))
20432                    .into_any_element(),
20433            )
20434        } else {
20435            None
20436        }
20437    }
20438
20439    pub fn render_crease_trailer(
20440        &self,
20441        buffer_row: MultiBufferRow,
20442        window: &mut Window,
20443        cx: &mut App,
20444    ) -> Option<AnyElement> {
20445        let folded = self.is_line_folded(buffer_row);
20446        if let Crease::Inline { render_trailer, .. } = self
20447            .crease_snapshot
20448            .query_row(buffer_row, &self.buffer_snapshot)?
20449        {
20450            let render_trailer = render_trailer.as_ref()?;
20451            Some(render_trailer(buffer_row, folded, window, cx))
20452        } else {
20453            None
20454        }
20455    }
20456}
20457
20458impl Deref for EditorSnapshot {
20459    type Target = DisplaySnapshot;
20460
20461    fn deref(&self) -> &Self::Target {
20462        &self.display_snapshot
20463    }
20464}
20465
20466#[derive(Clone, Debug, PartialEq, Eq)]
20467pub enum EditorEvent {
20468    InputIgnored {
20469        text: Arc<str>,
20470    },
20471    InputHandled {
20472        utf16_range_to_replace: Option<Range<isize>>,
20473        text: Arc<str>,
20474    },
20475    ExcerptsAdded {
20476        buffer: Entity<Buffer>,
20477        predecessor: ExcerptId,
20478        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20479    },
20480    ExcerptsRemoved {
20481        ids: Vec<ExcerptId>,
20482        removed_buffer_ids: Vec<BufferId>,
20483    },
20484    BufferFoldToggled {
20485        ids: Vec<ExcerptId>,
20486        folded: bool,
20487    },
20488    ExcerptsEdited {
20489        ids: Vec<ExcerptId>,
20490    },
20491    ExcerptsExpanded {
20492        ids: Vec<ExcerptId>,
20493    },
20494    BufferEdited,
20495    Edited {
20496        transaction_id: clock::Lamport,
20497    },
20498    Reparsed(BufferId),
20499    Focused,
20500    FocusedIn,
20501    Blurred,
20502    DirtyChanged,
20503    Saved,
20504    TitleChanged,
20505    DiffBaseChanged,
20506    SelectionsChanged {
20507        local: bool,
20508    },
20509    ScrollPositionChanged {
20510        local: bool,
20511        autoscroll: bool,
20512    },
20513    Closed,
20514    TransactionUndone {
20515        transaction_id: clock::Lamport,
20516    },
20517    TransactionBegun {
20518        transaction_id: clock::Lamport,
20519    },
20520    Reloaded,
20521    CursorShapeChanged,
20522    PushedToNavHistory {
20523        anchor: Anchor,
20524        is_deactivate: bool,
20525    },
20526}
20527
20528impl EventEmitter<EditorEvent> for Editor {}
20529
20530impl Focusable for Editor {
20531    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20532        self.focus_handle.clone()
20533    }
20534}
20535
20536impl Render for Editor {
20537    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20538        let settings = ThemeSettings::get_global(cx);
20539
20540        let mut text_style = match self.mode {
20541            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20542                color: cx.theme().colors().editor_foreground,
20543                font_family: settings.ui_font.family.clone(),
20544                font_features: settings.ui_font.features.clone(),
20545                font_fallbacks: settings.ui_font.fallbacks.clone(),
20546                font_size: rems(0.875).into(),
20547                font_weight: settings.ui_font.weight,
20548                line_height: relative(settings.buffer_line_height.value()),
20549                ..Default::default()
20550            },
20551            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20552                color: cx.theme().colors().editor_foreground,
20553                font_family: settings.buffer_font.family.clone(),
20554                font_features: settings.buffer_font.features.clone(),
20555                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20556                font_size: settings.buffer_font_size(cx).into(),
20557                font_weight: settings.buffer_font.weight,
20558                line_height: relative(settings.buffer_line_height.value()),
20559                ..Default::default()
20560            },
20561        };
20562        if let Some(text_style_refinement) = &self.text_style_refinement {
20563            text_style.refine(text_style_refinement)
20564        }
20565
20566        let background = match self.mode {
20567            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20568            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20569            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20570            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20571        };
20572
20573        EditorElement::new(
20574            &cx.entity(),
20575            EditorStyle {
20576                background,
20577                local_player: cx.theme().players().local(),
20578                text: text_style,
20579                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20580                syntax: cx.theme().syntax().clone(),
20581                status: cx.theme().status().clone(),
20582                inlay_hints_style: make_inlay_hints_style(cx),
20583                inline_completion_styles: make_suggestion_styles(cx),
20584                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20585                show_underlines: !self.mode.is_minimap(),
20586            },
20587        )
20588    }
20589}
20590
20591impl EntityInputHandler for Editor {
20592    fn text_for_range(
20593        &mut self,
20594        range_utf16: Range<usize>,
20595        adjusted_range: &mut Option<Range<usize>>,
20596        _: &mut Window,
20597        cx: &mut Context<Self>,
20598    ) -> Option<String> {
20599        let snapshot = self.buffer.read(cx).read(cx);
20600        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20601        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20602        if (start.0..end.0) != range_utf16 {
20603            adjusted_range.replace(start.0..end.0);
20604        }
20605        Some(snapshot.text_for_range(start..end).collect())
20606    }
20607
20608    fn selected_text_range(
20609        &mut self,
20610        ignore_disabled_input: bool,
20611        _: &mut Window,
20612        cx: &mut Context<Self>,
20613    ) -> Option<UTF16Selection> {
20614        // Prevent the IME menu from appearing when holding down an alphabetic key
20615        // while input is disabled.
20616        if !ignore_disabled_input && !self.input_enabled {
20617            return None;
20618        }
20619
20620        let selection = self.selections.newest::<OffsetUtf16>(cx);
20621        let range = selection.range();
20622
20623        Some(UTF16Selection {
20624            range: range.start.0..range.end.0,
20625            reversed: selection.reversed,
20626        })
20627    }
20628
20629    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20630        let snapshot = self.buffer.read(cx).read(cx);
20631        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20632        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20633    }
20634
20635    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20636        self.clear_highlights::<InputComposition>(cx);
20637        self.ime_transaction.take();
20638    }
20639
20640    fn replace_text_in_range(
20641        &mut self,
20642        range_utf16: Option<Range<usize>>,
20643        text: &str,
20644        window: &mut Window,
20645        cx: &mut Context<Self>,
20646    ) {
20647        if !self.input_enabled {
20648            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20649            return;
20650        }
20651
20652        self.transact(window, cx, |this, window, cx| {
20653            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20654                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20655                Some(this.selection_replacement_ranges(range_utf16, cx))
20656            } else {
20657                this.marked_text_ranges(cx)
20658            };
20659
20660            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20661                let newest_selection_id = this.selections.newest_anchor().id;
20662                this.selections
20663                    .all::<OffsetUtf16>(cx)
20664                    .iter()
20665                    .zip(ranges_to_replace.iter())
20666                    .find_map(|(selection, range)| {
20667                        if selection.id == newest_selection_id {
20668                            Some(
20669                                (range.start.0 as isize - selection.head().0 as isize)
20670                                    ..(range.end.0 as isize - selection.head().0 as isize),
20671                            )
20672                        } else {
20673                            None
20674                        }
20675                    })
20676            });
20677
20678            cx.emit(EditorEvent::InputHandled {
20679                utf16_range_to_replace: range_to_replace,
20680                text: text.into(),
20681            });
20682
20683            if let Some(new_selected_ranges) = new_selected_ranges {
20684                this.change_selections(None, window, cx, |selections| {
20685                    selections.select_ranges(new_selected_ranges)
20686                });
20687                this.backspace(&Default::default(), window, cx);
20688            }
20689
20690            this.handle_input(text, window, cx);
20691        });
20692
20693        if let Some(transaction) = self.ime_transaction {
20694            self.buffer.update(cx, |buffer, cx| {
20695                buffer.group_until_transaction(transaction, cx);
20696            });
20697        }
20698
20699        self.unmark_text(window, cx);
20700    }
20701
20702    fn replace_and_mark_text_in_range(
20703        &mut self,
20704        range_utf16: Option<Range<usize>>,
20705        text: &str,
20706        new_selected_range_utf16: Option<Range<usize>>,
20707        window: &mut Window,
20708        cx: &mut Context<Self>,
20709    ) {
20710        if !self.input_enabled {
20711            return;
20712        }
20713
20714        let transaction = self.transact(window, cx, |this, window, cx| {
20715            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20716                let snapshot = this.buffer.read(cx).read(cx);
20717                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20718                    for marked_range in &mut marked_ranges {
20719                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20720                        marked_range.start.0 += relative_range_utf16.start;
20721                        marked_range.start =
20722                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20723                        marked_range.end =
20724                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20725                    }
20726                }
20727                Some(marked_ranges)
20728            } else if let Some(range_utf16) = range_utf16 {
20729                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20730                Some(this.selection_replacement_ranges(range_utf16, cx))
20731            } else {
20732                None
20733            };
20734
20735            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20736                let newest_selection_id = this.selections.newest_anchor().id;
20737                this.selections
20738                    .all::<OffsetUtf16>(cx)
20739                    .iter()
20740                    .zip(ranges_to_replace.iter())
20741                    .find_map(|(selection, range)| {
20742                        if selection.id == newest_selection_id {
20743                            Some(
20744                                (range.start.0 as isize - selection.head().0 as isize)
20745                                    ..(range.end.0 as isize - selection.head().0 as isize),
20746                            )
20747                        } else {
20748                            None
20749                        }
20750                    })
20751            });
20752
20753            cx.emit(EditorEvent::InputHandled {
20754                utf16_range_to_replace: range_to_replace,
20755                text: text.into(),
20756            });
20757
20758            if let Some(ranges) = ranges_to_replace {
20759                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20760            }
20761
20762            let marked_ranges = {
20763                let snapshot = this.buffer.read(cx).read(cx);
20764                this.selections
20765                    .disjoint_anchors()
20766                    .iter()
20767                    .map(|selection| {
20768                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20769                    })
20770                    .collect::<Vec<_>>()
20771            };
20772
20773            if text.is_empty() {
20774                this.unmark_text(window, cx);
20775            } else {
20776                this.highlight_text::<InputComposition>(
20777                    marked_ranges.clone(),
20778                    HighlightStyle {
20779                        underline: Some(UnderlineStyle {
20780                            thickness: px(1.),
20781                            color: None,
20782                            wavy: false,
20783                        }),
20784                        ..Default::default()
20785                    },
20786                    cx,
20787                );
20788            }
20789
20790            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20791            let use_autoclose = this.use_autoclose;
20792            let use_auto_surround = this.use_auto_surround;
20793            this.set_use_autoclose(false);
20794            this.set_use_auto_surround(false);
20795            this.handle_input(text, window, cx);
20796            this.set_use_autoclose(use_autoclose);
20797            this.set_use_auto_surround(use_auto_surround);
20798
20799            if let Some(new_selected_range) = new_selected_range_utf16 {
20800                let snapshot = this.buffer.read(cx).read(cx);
20801                let new_selected_ranges = marked_ranges
20802                    .into_iter()
20803                    .map(|marked_range| {
20804                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20805                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20806                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20807                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20808                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20809                    })
20810                    .collect::<Vec<_>>();
20811
20812                drop(snapshot);
20813                this.change_selections(None, window, cx, |selections| {
20814                    selections.select_ranges(new_selected_ranges)
20815                });
20816            }
20817        });
20818
20819        self.ime_transaction = self.ime_transaction.or(transaction);
20820        if let Some(transaction) = self.ime_transaction {
20821            self.buffer.update(cx, |buffer, cx| {
20822                buffer.group_until_transaction(transaction, cx);
20823            });
20824        }
20825
20826        if self.text_highlights::<InputComposition>(cx).is_none() {
20827            self.ime_transaction.take();
20828        }
20829    }
20830
20831    fn bounds_for_range(
20832        &mut self,
20833        range_utf16: Range<usize>,
20834        element_bounds: gpui::Bounds<Pixels>,
20835        window: &mut Window,
20836        cx: &mut Context<Self>,
20837    ) -> Option<gpui::Bounds<Pixels>> {
20838        let text_layout_details = self.text_layout_details(window);
20839        let gpui::Size {
20840            width: em_width,
20841            height: line_height,
20842        } = self.character_size(window);
20843
20844        let snapshot = self.snapshot(window, cx);
20845        let scroll_position = snapshot.scroll_position();
20846        let scroll_left = scroll_position.x * em_width;
20847
20848        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20849        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20850            + self.gutter_dimensions.width
20851            + self.gutter_dimensions.margin;
20852        let y = line_height * (start.row().as_f32() - scroll_position.y);
20853
20854        Some(Bounds {
20855            origin: element_bounds.origin + point(x, y),
20856            size: size(em_width, line_height),
20857        })
20858    }
20859
20860    fn character_index_for_point(
20861        &mut self,
20862        point: gpui::Point<Pixels>,
20863        _window: &mut Window,
20864        _cx: &mut Context<Self>,
20865    ) -> Option<usize> {
20866        let position_map = self.last_position_map.as_ref()?;
20867        if !position_map.text_hitbox.contains(&point) {
20868            return None;
20869        }
20870        let display_point = position_map.point_for_position(point).previous_valid;
20871        let anchor = position_map
20872            .snapshot
20873            .display_point_to_anchor(display_point, Bias::Left);
20874        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20875        Some(utf16_offset.0)
20876    }
20877}
20878
20879trait SelectionExt {
20880    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20881    fn spanned_rows(
20882        &self,
20883        include_end_if_at_line_start: bool,
20884        map: &DisplaySnapshot,
20885    ) -> Range<MultiBufferRow>;
20886}
20887
20888impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20889    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20890        let start = self
20891            .start
20892            .to_point(&map.buffer_snapshot)
20893            .to_display_point(map);
20894        let end = self
20895            .end
20896            .to_point(&map.buffer_snapshot)
20897            .to_display_point(map);
20898        if self.reversed {
20899            end..start
20900        } else {
20901            start..end
20902        }
20903    }
20904
20905    fn spanned_rows(
20906        &self,
20907        include_end_if_at_line_start: bool,
20908        map: &DisplaySnapshot,
20909    ) -> Range<MultiBufferRow> {
20910        let start = self.start.to_point(&map.buffer_snapshot);
20911        let mut end = self.end.to_point(&map.buffer_snapshot);
20912        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20913            end.row -= 1;
20914        }
20915
20916        let buffer_start = map.prev_line_boundary(start).0;
20917        let buffer_end = map.next_line_boundary(end).0;
20918        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20919    }
20920}
20921
20922impl<T: InvalidationRegion> InvalidationStack<T> {
20923    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20924    where
20925        S: Clone + ToOffset,
20926    {
20927        while let Some(region) = self.last() {
20928            let all_selections_inside_invalidation_ranges =
20929                if selections.len() == region.ranges().len() {
20930                    selections
20931                        .iter()
20932                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20933                        .all(|(selection, invalidation_range)| {
20934                            let head = selection.head().to_offset(buffer);
20935                            invalidation_range.start <= head && invalidation_range.end >= head
20936                        })
20937                } else {
20938                    false
20939                };
20940
20941            if all_selections_inside_invalidation_ranges {
20942                break;
20943            } else {
20944                self.pop();
20945            }
20946        }
20947    }
20948}
20949
20950impl<T> Default for InvalidationStack<T> {
20951    fn default() -> Self {
20952        Self(Default::default())
20953    }
20954}
20955
20956impl<T> Deref for InvalidationStack<T> {
20957    type Target = Vec<T>;
20958
20959    fn deref(&self) -> &Self::Target {
20960        &self.0
20961    }
20962}
20963
20964impl<T> DerefMut for InvalidationStack<T> {
20965    fn deref_mut(&mut self) -> &mut Self::Target {
20966        &mut self.0
20967    }
20968}
20969
20970impl InvalidationRegion for SnippetState {
20971    fn ranges(&self) -> &[Range<Anchor>] {
20972        &self.ranges[self.active_index]
20973    }
20974}
20975
20976fn inline_completion_edit_text(
20977    current_snapshot: &BufferSnapshot,
20978    edits: &[(Range<Anchor>, String)],
20979    edit_preview: &EditPreview,
20980    include_deletions: bool,
20981    cx: &App,
20982) -> HighlightedText {
20983    let edits = edits
20984        .iter()
20985        .map(|(anchor, text)| {
20986            (
20987                anchor.start.text_anchor..anchor.end.text_anchor,
20988                text.clone(),
20989            )
20990        })
20991        .collect::<Vec<_>>();
20992
20993    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
20994}
20995
20996pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
20997    match severity {
20998        lsp::DiagnosticSeverity::ERROR => colors.error,
20999        lsp::DiagnosticSeverity::WARNING => colors.warning,
21000        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21001        lsp::DiagnosticSeverity::HINT => colors.info,
21002        _ => colors.ignored,
21003    }
21004}
21005
21006pub fn styled_runs_for_code_label<'a>(
21007    label: &'a CodeLabel,
21008    syntax_theme: &'a theme::SyntaxTheme,
21009) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21010    let fade_out = HighlightStyle {
21011        fade_out: Some(0.35),
21012        ..Default::default()
21013    };
21014
21015    let mut prev_end = label.filter_range.end;
21016    label
21017        .runs
21018        .iter()
21019        .enumerate()
21020        .flat_map(move |(ix, (range, highlight_id))| {
21021            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21022                style
21023            } else {
21024                return Default::default();
21025            };
21026            let mut muted_style = style;
21027            muted_style.highlight(fade_out);
21028
21029            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21030            if range.start >= label.filter_range.end {
21031                if range.start > prev_end {
21032                    runs.push((prev_end..range.start, fade_out));
21033                }
21034                runs.push((range.clone(), muted_style));
21035            } else if range.end <= label.filter_range.end {
21036                runs.push((range.clone(), style));
21037            } else {
21038                runs.push((range.start..label.filter_range.end, style));
21039                runs.push((label.filter_range.end..range.end, muted_style));
21040            }
21041            prev_end = cmp::max(prev_end, range.end);
21042
21043            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21044                runs.push((prev_end..label.text.len(), fade_out));
21045            }
21046
21047            runs
21048        })
21049}
21050
21051pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21052    let mut prev_index = 0;
21053    let mut prev_codepoint: Option<char> = None;
21054    text.char_indices()
21055        .chain([(text.len(), '\0')])
21056        .filter_map(move |(index, codepoint)| {
21057            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21058            let is_boundary = index == text.len()
21059                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21060                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21061            if is_boundary {
21062                let chunk = &text[prev_index..index];
21063                prev_index = index;
21064                Some(chunk)
21065            } else {
21066                None
21067            }
21068        })
21069}
21070
21071pub trait RangeToAnchorExt: Sized {
21072    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21073
21074    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21075        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21076        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21077    }
21078}
21079
21080impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21081    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21082        let start_offset = self.start.to_offset(snapshot);
21083        let end_offset = self.end.to_offset(snapshot);
21084        if start_offset == end_offset {
21085            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21086        } else {
21087            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21088        }
21089    }
21090}
21091
21092pub trait RowExt {
21093    fn as_f32(&self) -> f32;
21094
21095    fn next_row(&self) -> Self;
21096
21097    fn previous_row(&self) -> Self;
21098
21099    fn minus(&self, other: Self) -> u32;
21100}
21101
21102impl RowExt for DisplayRow {
21103    fn as_f32(&self) -> f32 {
21104        self.0 as f32
21105    }
21106
21107    fn next_row(&self) -> Self {
21108        Self(self.0 + 1)
21109    }
21110
21111    fn previous_row(&self) -> Self {
21112        Self(self.0.saturating_sub(1))
21113    }
21114
21115    fn minus(&self, other: Self) -> u32 {
21116        self.0 - other.0
21117    }
21118}
21119
21120impl RowExt for MultiBufferRow {
21121    fn as_f32(&self) -> f32 {
21122        self.0 as f32
21123    }
21124
21125    fn next_row(&self) -> Self {
21126        Self(self.0 + 1)
21127    }
21128
21129    fn previous_row(&self) -> Self {
21130        Self(self.0.saturating_sub(1))
21131    }
21132
21133    fn minus(&self, other: Self) -> u32 {
21134        self.0 - other.0
21135    }
21136}
21137
21138trait RowRangeExt {
21139    type Row;
21140
21141    fn len(&self) -> usize;
21142
21143    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21144}
21145
21146impl RowRangeExt for Range<MultiBufferRow> {
21147    type Row = MultiBufferRow;
21148
21149    fn len(&self) -> usize {
21150        (self.end.0 - self.start.0) as usize
21151    }
21152
21153    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21154        (self.start.0..self.end.0).map(MultiBufferRow)
21155    }
21156}
21157
21158impl RowRangeExt for Range<DisplayRow> {
21159    type Row = DisplayRow;
21160
21161    fn len(&self) -> usize {
21162        (self.end.0 - self.start.0) as usize
21163    }
21164
21165    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21166        (self.start.0..self.end.0).map(DisplayRow)
21167    }
21168}
21169
21170/// If select range has more than one line, we
21171/// just point the cursor to range.start.
21172fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21173    if range.start.row == range.end.row {
21174        range
21175    } else {
21176        range.start..range.start
21177    }
21178}
21179pub struct KillRing(ClipboardItem);
21180impl Global for KillRing {}
21181
21182const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21183
21184enum BreakpointPromptEditAction {
21185    Log,
21186    Condition,
21187    HitCondition,
21188}
21189
21190struct BreakpointPromptEditor {
21191    pub(crate) prompt: Entity<Editor>,
21192    editor: WeakEntity<Editor>,
21193    breakpoint_anchor: Anchor,
21194    breakpoint: Breakpoint,
21195    edit_action: BreakpointPromptEditAction,
21196    block_ids: HashSet<CustomBlockId>,
21197    editor_margins: Arc<Mutex<EditorMargins>>,
21198    _subscriptions: Vec<Subscription>,
21199}
21200
21201impl BreakpointPromptEditor {
21202    const MAX_LINES: u8 = 4;
21203
21204    fn new(
21205        editor: WeakEntity<Editor>,
21206        breakpoint_anchor: Anchor,
21207        breakpoint: Breakpoint,
21208        edit_action: BreakpointPromptEditAction,
21209        window: &mut Window,
21210        cx: &mut Context<Self>,
21211    ) -> Self {
21212        let base_text = match edit_action {
21213            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21214            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21215            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21216        }
21217        .map(|msg| msg.to_string())
21218        .unwrap_or_default();
21219
21220        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21221        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21222
21223        let prompt = cx.new(|cx| {
21224            let mut prompt = Editor::new(
21225                EditorMode::AutoHeight {
21226                    max_lines: Self::MAX_LINES as usize,
21227                },
21228                buffer,
21229                None,
21230                window,
21231                cx,
21232            );
21233            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21234            prompt.set_show_cursor_when_unfocused(false, cx);
21235            prompt.set_placeholder_text(
21236                match edit_action {
21237                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21238                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21239                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21240                },
21241                cx,
21242            );
21243
21244            prompt
21245        });
21246
21247        Self {
21248            prompt,
21249            editor,
21250            breakpoint_anchor,
21251            breakpoint,
21252            edit_action,
21253            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21254            block_ids: Default::default(),
21255            _subscriptions: vec![],
21256        }
21257    }
21258
21259    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21260        self.block_ids.extend(block_ids)
21261    }
21262
21263    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21264        if let Some(editor) = self.editor.upgrade() {
21265            let message = self
21266                .prompt
21267                .read(cx)
21268                .buffer
21269                .read(cx)
21270                .as_singleton()
21271                .expect("A multi buffer in breakpoint prompt isn't possible")
21272                .read(cx)
21273                .as_rope()
21274                .to_string();
21275
21276            editor.update(cx, |editor, cx| {
21277                editor.edit_breakpoint_at_anchor(
21278                    self.breakpoint_anchor,
21279                    self.breakpoint.clone(),
21280                    match self.edit_action {
21281                        BreakpointPromptEditAction::Log => {
21282                            BreakpointEditAction::EditLogMessage(message.into())
21283                        }
21284                        BreakpointPromptEditAction::Condition => {
21285                            BreakpointEditAction::EditCondition(message.into())
21286                        }
21287                        BreakpointPromptEditAction::HitCondition => {
21288                            BreakpointEditAction::EditHitCondition(message.into())
21289                        }
21290                    },
21291                    cx,
21292                );
21293
21294                editor.remove_blocks(self.block_ids.clone(), None, cx);
21295                cx.focus_self(window);
21296            });
21297        }
21298    }
21299
21300    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21301        self.editor
21302            .update(cx, |editor, cx| {
21303                editor.remove_blocks(self.block_ids.clone(), None, cx);
21304                window.focus(&editor.focus_handle);
21305            })
21306            .log_err();
21307    }
21308
21309    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21310        let settings = ThemeSettings::get_global(cx);
21311        let text_style = TextStyle {
21312            color: if self.prompt.read(cx).read_only(cx) {
21313                cx.theme().colors().text_disabled
21314            } else {
21315                cx.theme().colors().text
21316            },
21317            font_family: settings.buffer_font.family.clone(),
21318            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21319            font_size: settings.buffer_font_size(cx).into(),
21320            font_weight: settings.buffer_font.weight,
21321            line_height: relative(settings.buffer_line_height.value()),
21322            ..Default::default()
21323        };
21324        EditorElement::new(
21325            &self.prompt,
21326            EditorStyle {
21327                background: cx.theme().colors().editor_background,
21328                local_player: cx.theme().players().local(),
21329                text: text_style,
21330                ..Default::default()
21331            },
21332        )
21333    }
21334}
21335
21336impl Render for BreakpointPromptEditor {
21337    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21338        let editor_margins = *self.editor_margins.lock();
21339        let gutter_dimensions = editor_margins.gutter;
21340        h_flex()
21341            .key_context("Editor")
21342            .bg(cx.theme().colors().editor_background)
21343            .border_y_1()
21344            .border_color(cx.theme().status().info_border)
21345            .size_full()
21346            .py(window.line_height() / 2.5)
21347            .on_action(cx.listener(Self::confirm))
21348            .on_action(cx.listener(Self::cancel))
21349            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21350            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21351    }
21352}
21353
21354impl Focusable for BreakpointPromptEditor {
21355    fn focus_handle(&self, cx: &App) -> FocusHandle {
21356        self.prompt.focus_handle(cx)
21357    }
21358}
21359
21360fn all_edits_insertions_or_deletions(
21361    edits: &Vec<(Range<Anchor>, String)>,
21362    snapshot: &MultiBufferSnapshot,
21363) -> bool {
21364    let mut all_insertions = true;
21365    let mut all_deletions = true;
21366
21367    for (range, new_text) in edits.iter() {
21368        let range_is_empty = range.to_offset(&snapshot).is_empty();
21369        let text_is_empty = new_text.is_empty();
21370
21371        if range_is_empty != text_is_empty {
21372            if range_is_empty {
21373                all_deletions = false;
21374            } else {
21375                all_insertions = false;
21376            }
21377        } else {
21378            return false;
21379        }
21380
21381        if !all_insertions && !all_deletions {
21382            return false;
21383        }
21384    }
21385    all_insertions || all_deletions
21386}
21387
21388struct MissingEditPredictionKeybindingTooltip;
21389
21390impl Render for MissingEditPredictionKeybindingTooltip {
21391    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21392        ui::tooltip_container(window, cx, |container, _, cx| {
21393            container
21394                .flex_shrink_0()
21395                .max_w_80()
21396                .min_h(rems_from_px(124.))
21397                .justify_between()
21398                .child(
21399                    v_flex()
21400                        .flex_1()
21401                        .text_ui_sm(cx)
21402                        .child(Label::new("Conflict with Accept Keybinding"))
21403                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21404                )
21405                .child(
21406                    h_flex()
21407                        .pb_1()
21408                        .gap_1()
21409                        .items_end()
21410                        .w_full()
21411                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21412                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21413                        }))
21414                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21415                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21416                        })),
21417                )
21418        })
21419    }
21420}
21421
21422#[derive(Debug, Clone, Copy, PartialEq)]
21423pub struct LineHighlight {
21424    pub background: Background,
21425    pub border: Option<gpui::Hsla>,
21426    pub include_gutter: bool,
21427    pub type_id: Option<TypeId>,
21428}
21429
21430fn render_diff_hunk_controls(
21431    row: u32,
21432    status: &DiffHunkStatus,
21433    hunk_range: Range<Anchor>,
21434    is_created_file: bool,
21435    line_height: Pixels,
21436    editor: &Entity<Editor>,
21437    _window: &mut Window,
21438    cx: &mut App,
21439) -> AnyElement {
21440    h_flex()
21441        .h(line_height)
21442        .mr_1()
21443        .gap_1()
21444        .px_0p5()
21445        .pb_1()
21446        .border_x_1()
21447        .border_b_1()
21448        .border_color(cx.theme().colors().border_variant)
21449        .rounded_b_lg()
21450        .bg(cx.theme().colors().editor_background)
21451        .gap_1()
21452        .occlude()
21453        .shadow_md()
21454        .child(if status.has_secondary_hunk() {
21455            Button::new(("stage", row as u64), "Stage")
21456                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21457                .tooltip({
21458                    let focus_handle = editor.focus_handle(cx);
21459                    move |window, cx| {
21460                        Tooltip::for_action_in(
21461                            "Stage Hunk",
21462                            &::git::ToggleStaged,
21463                            &focus_handle,
21464                            window,
21465                            cx,
21466                        )
21467                    }
21468                })
21469                .on_click({
21470                    let editor = editor.clone();
21471                    move |_event, _window, cx| {
21472                        editor.update(cx, |editor, cx| {
21473                            editor.stage_or_unstage_diff_hunks(
21474                                true,
21475                                vec![hunk_range.start..hunk_range.start],
21476                                cx,
21477                            );
21478                        });
21479                    }
21480                })
21481        } else {
21482            Button::new(("unstage", row as u64), "Unstage")
21483                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21484                .tooltip({
21485                    let focus_handle = editor.focus_handle(cx);
21486                    move |window, cx| {
21487                        Tooltip::for_action_in(
21488                            "Unstage Hunk",
21489                            &::git::ToggleStaged,
21490                            &focus_handle,
21491                            window,
21492                            cx,
21493                        )
21494                    }
21495                })
21496                .on_click({
21497                    let editor = editor.clone();
21498                    move |_event, _window, cx| {
21499                        editor.update(cx, |editor, cx| {
21500                            editor.stage_or_unstage_diff_hunks(
21501                                false,
21502                                vec![hunk_range.start..hunk_range.start],
21503                                cx,
21504                            );
21505                        });
21506                    }
21507                })
21508        })
21509        .child(
21510            Button::new(("restore", row as u64), "Restore")
21511                .tooltip({
21512                    let focus_handle = editor.focus_handle(cx);
21513                    move |window, cx| {
21514                        Tooltip::for_action_in(
21515                            "Restore Hunk",
21516                            &::git::Restore,
21517                            &focus_handle,
21518                            window,
21519                            cx,
21520                        )
21521                    }
21522                })
21523                .on_click({
21524                    let editor = editor.clone();
21525                    move |_event, window, cx| {
21526                        editor.update(cx, |editor, cx| {
21527                            let snapshot = editor.snapshot(window, cx);
21528                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21529                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21530                        });
21531                    }
21532                })
21533                .disabled(is_created_file),
21534        )
21535        .when(
21536            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21537            |el| {
21538                el.child(
21539                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21540                        .shape(IconButtonShape::Square)
21541                        .icon_size(IconSize::Small)
21542                        // .disabled(!has_multiple_hunks)
21543                        .tooltip({
21544                            let focus_handle = editor.focus_handle(cx);
21545                            move |window, cx| {
21546                                Tooltip::for_action_in(
21547                                    "Next Hunk",
21548                                    &GoToHunk,
21549                                    &focus_handle,
21550                                    window,
21551                                    cx,
21552                                )
21553                            }
21554                        })
21555                        .on_click({
21556                            let editor = editor.clone();
21557                            move |_event, window, cx| {
21558                                editor.update(cx, |editor, cx| {
21559                                    let snapshot = editor.snapshot(window, cx);
21560                                    let position =
21561                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21562                                    editor.go_to_hunk_before_or_after_position(
21563                                        &snapshot,
21564                                        position,
21565                                        Direction::Next,
21566                                        window,
21567                                        cx,
21568                                    );
21569                                    editor.expand_selected_diff_hunks(cx);
21570                                });
21571                            }
21572                        }),
21573                )
21574                .child(
21575                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21576                        .shape(IconButtonShape::Square)
21577                        .icon_size(IconSize::Small)
21578                        // .disabled(!has_multiple_hunks)
21579                        .tooltip({
21580                            let focus_handle = editor.focus_handle(cx);
21581                            move |window, cx| {
21582                                Tooltip::for_action_in(
21583                                    "Previous Hunk",
21584                                    &GoToPreviousHunk,
21585                                    &focus_handle,
21586                                    window,
21587                                    cx,
21588                                )
21589                            }
21590                        })
21591                        .on_click({
21592                            let editor = editor.clone();
21593                            move |_event, window, cx| {
21594                                editor.update(cx, |editor, cx| {
21595                                    let snapshot = editor.snapshot(window, cx);
21596                                    let point =
21597                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21598                                    editor.go_to_hunk_before_or_after_position(
21599                                        &snapshot,
21600                                        point,
21601                                        Direction::Prev,
21602                                        window,
21603                                        cx,
21604                                    );
21605                                    editor.expand_selected_diff_hunks(cx);
21606                                });
21607                            }
21608                        }),
21609                )
21610            },
21611        )
21612        .into_any_element()
21613}