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 {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  909/// a breakpoint on them.
  910#[derive(Clone, Copy, Debug)]
  911struct PhantomBreakpointIndicator {
  912    display_row: DisplayRow,
  913    /// There's a small debounce between hovering over the line and showing the indicator.
  914    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  915    is_active: bool,
  916    collides_with_existing_breakpoint: bool,
  917}
  918/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  919///
  920/// See the [module level documentation](self) for more information.
  921pub struct Editor {
  922    focus_handle: FocusHandle,
  923    last_focused_descendant: Option<WeakFocusHandle>,
  924    /// The text buffer being edited
  925    buffer: Entity<MultiBuffer>,
  926    /// Map of how text in the buffer should be displayed.
  927    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  928    pub display_map: Entity<DisplayMap>,
  929    pub selections: SelectionsCollection,
  930    pub scroll_manager: ScrollManager,
  931    /// When inline assist editors are linked, they all render cursors because
  932    /// typing enters text into each of them, even the ones that aren't focused.
  933    pub(crate) show_cursor_when_unfocused: bool,
  934    columnar_selection_tail: Option<Anchor>,
  935    add_selections_state: Option<AddSelectionsState>,
  936    select_next_state: Option<SelectNextState>,
  937    select_prev_state: Option<SelectNextState>,
  938    selection_history: SelectionHistory,
  939    autoclose_regions: Vec<AutocloseRegion>,
  940    snippet_stack: InvalidationStack<SnippetState>,
  941    select_syntax_node_history: SelectSyntaxNodeHistory,
  942    ime_transaction: Option<TransactionId>,
  943    pub diagnostics_max_severity: DiagnosticSeverity,
  944    active_diagnostics: ActiveDiagnostic,
  945    show_inline_diagnostics: bool,
  946    inline_diagnostics_update: Task<()>,
  947    inline_diagnostics_enabled: bool,
  948    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  949    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  950    hard_wrap: Option<usize>,
  951
  952    // TODO: make this a access method
  953    pub project: Option<Entity<Project>>,
  954    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  955    completion_provider: Option<Rc<dyn CompletionProvider>>,
  956    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  957    blink_manager: Entity<BlinkManager>,
  958    show_cursor_names: bool,
  959    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  960    pub show_local_selections: bool,
  961    mode: EditorMode,
  962    show_breadcrumbs: bool,
  963    show_gutter: bool,
  964    show_scrollbars: bool,
  965    minimap_visibility: MinimapVisibility,
  966    offset_content: bool,
  967    disable_expand_excerpt_buttons: bool,
  968    show_line_numbers: Option<bool>,
  969    use_relative_line_numbers: Option<bool>,
  970    show_git_diff_gutter: Option<bool>,
  971    show_code_actions: Option<bool>,
  972    show_runnables: Option<bool>,
  973    show_breakpoints: Option<bool>,
  974    show_wrap_guides: Option<bool>,
  975    show_indent_guides: Option<bool>,
  976    placeholder_text: Option<Arc<str>>,
  977    highlight_order: usize,
  978    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  979    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  980    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  981    scrollbar_marker_state: ScrollbarMarkerState,
  982    active_indent_guides_state: ActiveIndentGuidesState,
  983    nav_history: Option<ItemNavHistory>,
  984    context_menu: RefCell<Option<CodeContextMenu>>,
  985    context_menu_options: Option<ContextMenuOptions>,
  986    mouse_context_menu: Option<MouseContextMenu>,
  987    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  988    inline_blame_popover: Option<InlineBlamePopover>,
  989    signature_help_state: SignatureHelpState,
  990    auto_signature_help: Option<bool>,
  991    find_all_references_task_sources: Vec<Anchor>,
  992    next_completion_id: CompletionId,
  993    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  994    code_actions_task: Option<Task<Result<()>>>,
  995    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  996    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  997    document_highlights_task: Option<Task<()>>,
  998    linked_editing_range_task: Option<Task<Option<()>>>,
  999    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1000    pending_rename: Option<RenameState>,
 1001    searchable: bool,
 1002    cursor_shape: CursorShape,
 1003    current_line_highlight: Option<CurrentLineHighlight>,
 1004    collapse_matches: bool,
 1005    autoindent_mode: Option<AutoindentMode>,
 1006    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1007    input_enabled: bool,
 1008    use_modal_editing: bool,
 1009    read_only: bool,
 1010    leader_id: Option<CollaboratorId>,
 1011    remote_id: Option<ViewId>,
 1012    pub hover_state: HoverState,
 1013    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1014    gutter_hovered: bool,
 1015    hovered_link_state: Option<HoveredLinkState>,
 1016    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1017    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1018    active_inline_completion: Option<InlineCompletionState>,
 1019    /// Used to prevent flickering as the user types while the menu is open
 1020    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1021    edit_prediction_settings: EditPredictionSettings,
 1022    inline_completions_hidden_for_vim_mode: bool,
 1023    show_inline_completions_override: Option<bool>,
 1024    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1025    edit_prediction_preview: EditPredictionPreview,
 1026    edit_prediction_indent_conflict: bool,
 1027    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1028    inlay_hint_cache: InlayHintCache,
 1029    next_inlay_id: usize,
 1030    _subscriptions: Vec<Subscription>,
 1031    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1032    gutter_dimensions: GutterDimensions,
 1033    style: Option<EditorStyle>,
 1034    text_style_refinement: Option<TextStyleRefinement>,
 1035    next_editor_action_id: EditorActionId,
 1036    editor_actions:
 1037        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1038    use_autoclose: bool,
 1039    use_auto_surround: bool,
 1040    auto_replace_emoji_shortcode: bool,
 1041    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1042    show_git_blame_gutter: bool,
 1043    show_git_blame_inline: bool,
 1044    show_git_blame_inline_delay_task: Option<Task<()>>,
 1045    git_blame_inline_enabled: bool,
 1046    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1047    serialize_dirty_buffers: bool,
 1048    show_selection_menu: Option<bool>,
 1049    blame: Option<Entity<GitBlame>>,
 1050    blame_subscription: Option<Subscription>,
 1051    custom_context_menu: Option<
 1052        Box<
 1053            dyn 'static
 1054                + Fn(
 1055                    &mut Self,
 1056                    DisplayPoint,
 1057                    &mut Window,
 1058                    &mut Context<Self>,
 1059                ) -> Option<Entity<ui::ContextMenu>>,
 1060        >,
 1061    >,
 1062    last_bounds: Option<Bounds<Pixels>>,
 1063    last_position_map: Option<Rc<PositionMap>>,
 1064    expect_bounds_change: Option<Bounds<Pixels>>,
 1065    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1066    tasks_update_task: Option<Task<()>>,
 1067    breakpoint_store: Option<Entity<BreakpointStore>>,
 1068    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1069    in_project_search: bool,
 1070    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1071    breadcrumb_header: Option<String>,
 1072    focused_block: Option<FocusedBlock>,
 1073    next_scroll_position: NextScrollCursorCenterTopBottom,
 1074    addons: HashMap<TypeId, Box<dyn Addon>>,
 1075    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1076    load_diff_task: Option<Shared<Task<()>>>,
 1077    /// Whether we are temporarily displaying a diff other than git's
 1078    temporary_diff_override: bool,
 1079    selection_mark_mode: bool,
 1080    toggle_fold_multiple_buffers: Task<()>,
 1081    _scroll_cursor_center_top_bottom_task: Task<()>,
 1082    serialize_selections: Task<()>,
 1083    serialize_folds: Task<()>,
 1084    mouse_cursor_hidden: bool,
 1085    minimap: Option<Entity<Self>>,
 1086    hide_mouse_mode: HideMouseMode,
 1087    pub change_list: ChangeList,
 1088    inline_value_cache: InlineValueCache,
 1089}
 1090
 1091#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1092enum NextScrollCursorCenterTopBottom {
 1093    #[default]
 1094    Center,
 1095    Top,
 1096    Bottom,
 1097}
 1098
 1099impl NextScrollCursorCenterTopBottom {
 1100    fn next(&self) -> Self {
 1101        match self {
 1102            Self::Center => Self::Top,
 1103            Self::Top => Self::Bottom,
 1104            Self::Bottom => Self::Center,
 1105        }
 1106    }
 1107}
 1108
 1109#[derive(Clone)]
 1110pub struct EditorSnapshot {
 1111    pub mode: EditorMode,
 1112    show_gutter: bool,
 1113    show_line_numbers: Option<bool>,
 1114    show_git_diff_gutter: Option<bool>,
 1115    show_code_actions: Option<bool>,
 1116    show_runnables: Option<bool>,
 1117    show_breakpoints: Option<bool>,
 1118    git_blame_gutter_max_author_length: Option<usize>,
 1119    pub display_snapshot: DisplaySnapshot,
 1120    pub placeholder_text: Option<Arc<str>>,
 1121    is_focused: bool,
 1122    scroll_anchor: ScrollAnchor,
 1123    ongoing_scroll: OngoingScroll,
 1124    current_line_highlight: CurrentLineHighlight,
 1125    gutter_hovered: bool,
 1126}
 1127
 1128#[derive(Default, Debug, Clone, Copy)]
 1129pub struct GutterDimensions {
 1130    pub left_padding: Pixels,
 1131    pub right_padding: Pixels,
 1132    pub width: Pixels,
 1133    pub margin: Pixels,
 1134    pub git_blame_entries_width: Option<Pixels>,
 1135}
 1136
 1137impl GutterDimensions {
 1138    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1139        Self {
 1140            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1141            ..Default::default()
 1142        }
 1143    }
 1144
 1145    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1146        -cx.text_system().descent(font_id, font_size)
 1147    }
 1148    /// The full width of the space taken up by the gutter.
 1149    pub fn full_width(&self) -> Pixels {
 1150        self.margin + self.width
 1151    }
 1152
 1153    /// The width of the space reserved for the fold indicators,
 1154    /// use alongside 'justify_end' and `gutter_width` to
 1155    /// right align content with the line numbers
 1156    pub fn fold_area_width(&self) -> Pixels {
 1157        self.margin + self.right_padding
 1158    }
 1159}
 1160
 1161#[derive(Debug)]
 1162pub struct RemoteSelection {
 1163    pub replica_id: ReplicaId,
 1164    pub selection: Selection<Anchor>,
 1165    pub cursor_shape: CursorShape,
 1166    pub collaborator_id: CollaboratorId,
 1167    pub line_mode: bool,
 1168    pub user_name: Option<SharedString>,
 1169    pub color: PlayerColor,
 1170}
 1171
 1172#[derive(Clone, Debug)]
 1173struct SelectionHistoryEntry {
 1174    selections: Arc<[Selection<Anchor>]>,
 1175    select_next_state: Option<SelectNextState>,
 1176    select_prev_state: Option<SelectNextState>,
 1177    add_selections_state: Option<AddSelectionsState>,
 1178}
 1179
 1180enum SelectionHistoryMode {
 1181    Normal,
 1182    Undoing,
 1183    Redoing,
 1184}
 1185
 1186#[derive(Clone, PartialEq, Eq, Hash)]
 1187struct HoveredCursor {
 1188    replica_id: u16,
 1189    selection_id: usize,
 1190}
 1191
 1192impl Default for SelectionHistoryMode {
 1193    fn default() -> Self {
 1194        Self::Normal
 1195    }
 1196}
 1197
 1198#[derive(Default)]
 1199struct SelectionHistory {
 1200    #[allow(clippy::type_complexity)]
 1201    selections_by_transaction:
 1202        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1203    mode: SelectionHistoryMode,
 1204    undo_stack: VecDeque<SelectionHistoryEntry>,
 1205    redo_stack: VecDeque<SelectionHistoryEntry>,
 1206}
 1207
 1208impl SelectionHistory {
 1209    fn insert_transaction(
 1210        &mut self,
 1211        transaction_id: TransactionId,
 1212        selections: Arc<[Selection<Anchor>]>,
 1213    ) {
 1214        self.selections_by_transaction
 1215            .insert(transaction_id, (selections, None));
 1216    }
 1217
 1218    #[allow(clippy::type_complexity)]
 1219    fn transaction(
 1220        &self,
 1221        transaction_id: TransactionId,
 1222    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1223        self.selections_by_transaction.get(&transaction_id)
 1224    }
 1225
 1226    #[allow(clippy::type_complexity)]
 1227    fn transaction_mut(
 1228        &mut self,
 1229        transaction_id: TransactionId,
 1230    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1231        self.selections_by_transaction.get_mut(&transaction_id)
 1232    }
 1233
 1234    fn push(&mut self, entry: SelectionHistoryEntry) {
 1235        if !entry.selections.is_empty() {
 1236            match self.mode {
 1237                SelectionHistoryMode::Normal => {
 1238                    self.push_undo(entry);
 1239                    self.redo_stack.clear();
 1240                }
 1241                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1242                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1243            }
 1244        }
 1245    }
 1246
 1247    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1248        if self
 1249            .undo_stack
 1250            .back()
 1251            .map_or(true, |e| e.selections != entry.selections)
 1252        {
 1253            self.undo_stack.push_back(entry);
 1254            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1255                self.undo_stack.pop_front();
 1256            }
 1257        }
 1258    }
 1259
 1260    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1261        if self
 1262            .redo_stack
 1263            .back()
 1264            .map_or(true, |e| e.selections != entry.selections)
 1265        {
 1266            self.redo_stack.push_back(entry);
 1267            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1268                self.redo_stack.pop_front();
 1269            }
 1270        }
 1271    }
 1272}
 1273
 1274#[derive(Clone, Copy)]
 1275pub struct RowHighlightOptions {
 1276    pub autoscroll: bool,
 1277    pub include_gutter: bool,
 1278}
 1279
 1280impl Default for RowHighlightOptions {
 1281    fn default() -> Self {
 1282        Self {
 1283            autoscroll: Default::default(),
 1284            include_gutter: true,
 1285        }
 1286    }
 1287}
 1288
 1289struct RowHighlight {
 1290    index: usize,
 1291    range: Range<Anchor>,
 1292    color: Hsla,
 1293    options: RowHighlightOptions,
 1294    type_id: TypeId,
 1295}
 1296
 1297#[derive(Clone, Debug)]
 1298struct AddSelectionsState {
 1299    above: bool,
 1300    stack: Vec<usize>,
 1301}
 1302
 1303#[derive(Clone)]
 1304struct SelectNextState {
 1305    query: AhoCorasick,
 1306    wordwise: bool,
 1307    done: bool,
 1308}
 1309
 1310impl std::fmt::Debug for SelectNextState {
 1311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1312        f.debug_struct(std::any::type_name::<Self>())
 1313            .field("wordwise", &self.wordwise)
 1314            .field("done", &self.done)
 1315            .finish()
 1316    }
 1317}
 1318
 1319#[derive(Debug)]
 1320struct AutocloseRegion {
 1321    selection_id: usize,
 1322    range: Range<Anchor>,
 1323    pair: BracketPair,
 1324}
 1325
 1326#[derive(Debug)]
 1327struct SnippetState {
 1328    ranges: Vec<Vec<Range<Anchor>>>,
 1329    active_index: usize,
 1330    choices: Vec<Option<Vec<String>>>,
 1331}
 1332
 1333#[doc(hidden)]
 1334pub struct RenameState {
 1335    pub range: Range<Anchor>,
 1336    pub old_name: Arc<str>,
 1337    pub editor: Entity<Editor>,
 1338    block_id: CustomBlockId,
 1339}
 1340
 1341struct InvalidationStack<T>(Vec<T>);
 1342
 1343struct RegisteredInlineCompletionProvider {
 1344    provider: Arc<dyn InlineCompletionProviderHandle>,
 1345    _subscription: Subscription,
 1346}
 1347
 1348#[derive(Debug, PartialEq, Eq)]
 1349pub struct ActiveDiagnosticGroup {
 1350    pub active_range: Range<Anchor>,
 1351    pub active_message: String,
 1352    pub group_id: usize,
 1353    pub blocks: HashSet<CustomBlockId>,
 1354}
 1355
 1356#[derive(Debug, PartialEq, Eq)]
 1357
 1358pub(crate) enum ActiveDiagnostic {
 1359    None,
 1360    All,
 1361    Group(ActiveDiagnosticGroup),
 1362}
 1363
 1364#[derive(Serialize, Deserialize, Clone, Debug)]
 1365pub struct ClipboardSelection {
 1366    /// The number of bytes in this selection.
 1367    pub len: usize,
 1368    /// Whether this was a full-line selection.
 1369    pub is_entire_line: bool,
 1370    /// The indentation of the first line when this content was originally copied.
 1371    pub first_line_indent: u32,
 1372}
 1373
 1374// selections, scroll behavior, was newest selection reversed
 1375type SelectSyntaxNodeHistoryState = (
 1376    Box<[Selection<usize>]>,
 1377    SelectSyntaxNodeScrollBehavior,
 1378    bool,
 1379);
 1380
 1381#[derive(Default)]
 1382struct SelectSyntaxNodeHistory {
 1383    stack: Vec<SelectSyntaxNodeHistoryState>,
 1384    // disable temporarily to allow changing selections without losing the stack
 1385    pub disable_clearing: bool,
 1386}
 1387
 1388impl SelectSyntaxNodeHistory {
 1389    pub fn try_clear(&mut self) {
 1390        if !self.disable_clearing {
 1391            self.stack.clear();
 1392        }
 1393    }
 1394
 1395    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1396        self.stack.push(selection);
 1397    }
 1398
 1399    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1400        self.stack.pop()
 1401    }
 1402}
 1403
 1404enum SelectSyntaxNodeScrollBehavior {
 1405    CursorTop,
 1406    FitSelection,
 1407    CursorBottom,
 1408}
 1409
 1410#[derive(Debug)]
 1411pub(crate) struct NavigationData {
 1412    cursor_anchor: Anchor,
 1413    cursor_position: Point,
 1414    scroll_anchor: ScrollAnchor,
 1415    scroll_top_row: u32,
 1416}
 1417
 1418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1419pub enum GotoDefinitionKind {
 1420    Symbol,
 1421    Declaration,
 1422    Type,
 1423    Implementation,
 1424}
 1425
 1426#[derive(Debug, Clone)]
 1427enum InlayHintRefreshReason {
 1428    ModifiersChanged(bool),
 1429    Toggle(bool),
 1430    SettingsChange(InlayHintSettings),
 1431    NewLinesShown,
 1432    BufferEdited(HashSet<Arc<Language>>),
 1433    RefreshRequested,
 1434    ExcerptsRemoved(Vec<ExcerptId>),
 1435}
 1436
 1437impl InlayHintRefreshReason {
 1438    fn description(&self) -> &'static str {
 1439        match self {
 1440            Self::ModifiersChanged(_) => "modifiers changed",
 1441            Self::Toggle(_) => "toggle",
 1442            Self::SettingsChange(_) => "settings change",
 1443            Self::NewLinesShown => "new lines shown",
 1444            Self::BufferEdited(_) => "buffer edited",
 1445            Self::RefreshRequested => "refresh requested",
 1446            Self::ExcerptsRemoved(_) => "excerpts removed",
 1447        }
 1448    }
 1449}
 1450
 1451pub enum FormatTarget {
 1452    Buffers,
 1453    Ranges(Vec<Range<MultiBufferPoint>>),
 1454}
 1455
 1456pub(crate) struct FocusedBlock {
 1457    id: BlockId,
 1458    focus_handle: WeakFocusHandle,
 1459}
 1460
 1461#[derive(Clone)]
 1462enum JumpData {
 1463    MultiBufferRow {
 1464        row: MultiBufferRow,
 1465        line_offset_from_top: u32,
 1466    },
 1467    MultiBufferPoint {
 1468        excerpt_id: ExcerptId,
 1469        position: Point,
 1470        anchor: text::Anchor,
 1471        line_offset_from_top: u32,
 1472    },
 1473}
 1474
 1475pub enum MultibufferSelectionMode {
 1476    First,
 1477    All,
 1478}
 1479
 1480#[derive(Clone, Copy, Debug, Default)]
 1481pub struct RewrapOptions {
 1482    pub override_language_settings: bool,
 1483    pub preserve_existing_whitespace: bool,
 1484}
 1485
 1486impl Editor {
 1487    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1488        let buffer = cx.new(|cx| Buffer::local("", cx));
 1489        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1490        Self::new(
 1491            EditorMode::SingleLine { auto_width: false },
 1492            buffer,
 1493            None,
 1494            window,
 1495            cx,
 1496        )
 1497    }
 1498
 1499    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1500        let buffer = cx.new(|cx| Buffer::local("", cx));
 1501        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1502        Self::new(EditorMode::full(), buffer, None, window, cx)
 1503    }
 1504
 1505    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1506        let buffer = cx.new(|cx| Buffer::local("", cx));
 1507        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1508        Self::new(
 1509            EditorMode::SingleLine { auto_width: true },
 1510            buffer,
 1511            None,
 1512            window,
 1513            cx,
 1514        )
 1515    }
 1516
 1517    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1518        let buffer = cx.new(|cx| Buffer::local("", cx));
 1519        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1520        Self::new(
 1521            EditorMode::AutoHeight { max_lines },
 1522            buffer,
 1523            None,
 1524            window,
 1525            cx,
 1526        )
 1527    }
 1528
 1529    pub fn for_buffer(
 1530        buffer: Entity<Buffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1536        Self::new(EditorMode::full(), buffer, project, window, cx)
 1537    }
 1538
 1539    pub fn for_multibuffer(
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        window: &mut Window,
 1543        cx: &mut Context<Self>,
 1544    ) -> Self {
 1545        Self::new(EditorMode::full(), buffer, project, window, cx)
 1546    }
 1547
 1548    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1549        let mut clone = Self::new(
 1550            self.mode.clone(),
 1551            self.buffer.clone(),
 1552            self.project.clone(),
 1553            window,
 1554            cx,
 1555        );
 1556        self.display_map.update(cx, |display_map, cx| {
 1557            let snapshot = display_map.snapshot(cx);
 1558            clone.display_map.update(cx, |display_map, cx| {
 1559                display_map.set_state(&snapshot, cx);
 1560            });
 1561        });
 1562        clone.folds_did_change(cx);
 1563        clone.selections.clone_state(&self.selections);
 1564        clone.scroll_manager.clone_state(&self.scroll_manager);
 1565        clone.searchable = self.searchable;
 1566        clone.read_only = self.read_only;
 1567        clone
 1568    }
 1569
 1570    pub fn new(
 1571        mode: EditorMode,
 1572        buffer: Entity<MultiBuffer>,
 1573        project: Option<Entity<Project>>,
 1574        window: &mut Window,
 1575        cx: &mut Context<Self>,
 1576    ) -> Self {
 1577        Editor::new_internal(mode, buffer, project, None, window, cx)
 1578    }
 1579
 1580    fn new_internal(
 1581        mode: EditorMode,
 1582        buffer: Entity<MultiBuffer>,
 1583        project: Option<Entity<Project>>,
 1584        display_map: Option<Entity<DisplayMap>>,
 1585        window: &mut Window,
 1586        cx: &mut Context<Self>,
 1587    ) -> Self {
 1588        debug_assert!(
 1589            display_map.is_none() || mode.is_minimap(),
 1590            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1591        );
 1592
 1593        let full_mode = mode.is_full();
 1594        let diagnostics_max_severity = if full_mode {
 1595            EditorSettings::get_global(cx)
 1596                .diagnostics_max_severity
 1597                .unwrap_or(DiagnosticSeverity::Hint)
 1598        } else {
 1599            DiagnosticSeverity::Off
 1600        };
 1601        let style = window.text_style();
 1602        let font_size = style.font_size.to_pixels(window.rem_size());
 1603        let editor = cx.entity().downgrade();
 1604        let fold_placeholder = FoldPlaceholder {
 1605            constrain_width: true,
 1606            render: Arc::new(move |fold_id, fold_range, cx| {
 1607                let editor = editor.clone();
 1608                div()
 1609                    .id(fold_id)
 1610                    .bg(cx.theme().colors().ghost_element_background)
 1611                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1612                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1613                    .rounded_xs()
 1614                    .size_full()
 1615                    .cursor_pointer()
 1616                    .child("")
 1617                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1618                    .on_click(move |_, _window, cx| {
 1619                        editor
 1620                            .update(cx, |editor, cx| {
 1621                                editor.unfold_ranges(
 1622                                    &[fold_range.start..fold_range.end],
 1623                                    true,
 1624                                    false,
 1625                                    cx,
 1626                                );
 1627                                cx.stop_propagation();
 1628                            })
 1629                            .ok();
 1630                    })
 1631                    .into_any()
 1632            }),
 1633            merge_adjacent: true,
 1634            ..FoldPlaceholder::default()
 1635        };
 1636        let display_map = display_map.unwrap_or_else(|| {
 1637            cx.new(|cx| {
 1638                DisplayMap::new(
 1639                    buffer.clone(),
 1640                    style.font(),
 1641                    font_size,
 1642                    None,
 1643                    FILE_HEADER_HEIGHT,
 1644                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1645                    fold_placeholder,
 1646                    diagnostics_max_severity,
 1647                    cx,
 1648                )
 1649            })
 1650        });
 1651
 1652        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1653
 1654        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1655
 1656        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1657            .then(|| language_settings::SoftWrap::None);
 1658
 1659        let mut project_subscriptions = Vec::new();
 1660        if mode.is_full() {
 1661            if let Some(project) = project.as_ref() {
 1662                project_subscriptions.push(cx.subscribe_in(
 1663                    project,
 1664                    window,
 1665                    |editor, _, event, window, cx| match event {
 1666                        project::Event::RefreshCodeLens => {
 1667                            // we always query lens with actions, without storing them, always refreshing them
 1668                        }
 1669                        project::Event::RefreshInlayHints => {
 1670                            editor
 1671                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1672                        }
 1673                        project::Event::SnippetEdit(id, snippet_edits) => {
 1674                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1675                                let focus_handle = editor.focus_handle(cx);
 1676                                if focus_handle.is_focused(window) {
 1677                                    let snapshot = buffer.read(cx).snapshot();
 1678                                    for (range, snippet) in snippet_edits {
 1679                                        let editor_range =
 1680                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1681                                        editor
 1682                                            .insert_snippet(
 1683                                                &[editor_range],
 1684                                                snippet.clone(),
 1685                                                window,
 1686                                                cx,
 1687                                            )
 1688                                            .ok();
 1689                                    }
 1690                                }
 1691                            }
 1692                        }
 1693                        _ => {}
 1694                    },
 1695                ));
 1696                if let Some(task_inventory) = project
 1697                    .read(cx)
 1698                    .task_store()
 1699                    .read(cx)
 1700                    .task_inventory()
 1701                    .cloned()
 1702                {
 1703                    project_subscriptions.push(cx.observe_in(
 1704                        &task_inventory,
 1705                        window,
 1706                        |editor, _, window, cx| {
 1707                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1708                        },
 1709                    ));
 1710                };
 1711
 1712                project_subscriptions.push(cx.subscribe_in(
 1713                    &project.read(cx).breakpoint_store(),
 1714                    window,
 1715                    |editor, _, event, window, cx| match event {
 1716                        BreakpointStoreEvent::ClearDebugLines => {
 1717                            editor.clear_row_highlights::<ActiveDebugLine>();
 1718                            editor.refresh_inline_values(cx);
 1719                        }
 1720                        BreakpointStoreEvent::SetDebugLine => {
 1721                            if editor.go_to_active_debug_line(window, cx) {
 1722                                cx.stop_propagation();
 1723                            }
 1724
 1725                            editor.refresh_inline_values(cx);
 1726                        }
 1727                        _ => {}
 1728                    },
 1729                ));
 1730            }
 1731        }
 1732
 1733        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1734
 1735        let inlay_hint_settings =
 1736            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1737        let focus_handle = cx.focus_handle();
 1738        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1739            .detach();
 1740        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1741            .detach();
 1742        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1743            .detach();
 1744        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1745            .detach();
 1746
 1747        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1748            Some(false)
 1749        } else {
 1750            None
 1751        };
 1752
 1753        let breakpoint_store = match (&mode, project.as_ref()) {
 1754            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1755            _ => None,
 1756        };
 1757
 1758        let mut code_action_providers = Vec::new();
 1759        let mut load_uncommitted_diff = None;
 1760        if let Some(project) = project.clone() {
 1761            load_uncommitted_diff = Some(
 1762                update_uncommitted_diff_for_buffer(
 1763                    cx.entity(),
 1764                    &project,
 1765                    buffer.read(cx).all_buffers(),
 1766                    buffer.clone(),
 1767                    cx,
 1768                )
 1769                .shared(),
 1770            );
 1771            code_action_providers.push(Rc::new(project) as Rc<_>);
 1772        }
 1773
 1774        let mut this = Self {
 1775            focus_handle,
 1776            show_cursor_when_unfocused: false,
 1777            last_focused_descendant: None,
 1778            buffer: buffer.clone(),
 1779            display_map: display_map.clone(),
 1780            selections,
 1781            scroll_manager: ScrollManager::new(cx),
 1782            columnar_selection_tail: None,
 1783            add_selections_state: None,
 1784            select_next_state: None,
 1785            select_prev_state: None,
 1786            selection_history: SelectionHistory::default(),
 1787            autoclose_regions: Vec::new(),
 1788            snippet_stack: InvalidationStack::default(),
 1789            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1790            ime_transaction: None,
 1791            active_diagnostics: ActiveDiagnostic::None,
 1792            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1793            inline_diagnostics_update: Task::ready(()),
 1794            inline_diagnostics: Vec::new(),
 1795            soft_wrap_mode_override,
 1796            diagnostics_max_severity,
 1797            hard_wrap: None,
 1798            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1799            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1800            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1801            project,
 1802            blink_manager: blink_manager.clone(),
 1803            show_local_selections: true,
 1804            show_scrollbars: full_mode,
 1805            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1806            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1807            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1808            show_gutter: mode.is_full(),
 1809            show_line_numbers: None,
 1810            use_relative_line_numbers: None,
 1811            disable_expand_excerpt_buttons: false,
 1812            show_git_diff_gutter: None,
 1813            show_code_actions: None,
 1814            show_runnables: None,
 1815            show_breakpoints: None,
 1816            show_wrap_guides: None,
 1817            show_indent_guides,
 1818            placeholder_text: None,
 1819            highlight_order: 0,
 1820            highlighted_rows: HashMap::default(),
 1821            background_highlights: TreeMap::default(),
 1822            gutter_highlights: TreeMap::default(),
 1823            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1824            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1825            nav_history: None,
 1826            context_menu: RefCell::new(None),
 1827            context_menu_options: None,
 1828            mouse_context_menu: None,
 1829            completion_tasks: Vec::new(),
 1830            inline_blame_popover: None,
 1831            signature_help_state: SignatureHelpState::default(),
 1832            auto_signature_help: None,
 1833            find_all_references_task_sources: Vec::new(),
 1834            next_completion_id: 0,
 1835            next_inlay_id: 0,
 1836            code_action_providers,
 1837            available_code_actions: None,
 1838            code_actions_task: None,
 1839            quick_selection_highlight_task: None,
 1840            debounced_selection_highlight_task: None,
 1841            document_highlights_task: None,
 1842            linked_editing_range_task: None,
 1843            pending_rename: None,
 1844            searchable: true,
 1845            cursor_shape: EditorSettings::get_global(cx)
 1846                .cursor_shape
 1847                .unwrap_or_default(),
 1848            current_line_highlight: None,
 1849            autoindent_mode: Some(AutoindentMode::EachLine),
 1850            collapse_matches: false,
 1851            workspace: None,
 1852            input_enabled: true,
 1853            use_modal_editing: mode.is_full(),
 1854            read_only: mode.is_minimap(),
 1855            use_autoclose: true,
 1856            use_auto_surround: true,
 1857            auto_replace_emoji_shortcode: false,
 1858            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1859            leader_id: None,
 1860            remote_id: None,
 1861            hover_state: HoverState::default(),
 1862            pending_mouse_down: None,
 1863            hovered_link_state: None,
 1864            edit_prediction_provider: None,
 1865            active_inline_completion: None,
 1866            stale_inline_completion_in_menu: None,
 1867            edit_prediction_preview: EditPredictionPreview::Inactive {
 1868                released_too_fast: false,
 1869            },
 1870            inline_diagnostics_enabled: mode.is_full(),
 1871            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1872            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1873
 1874            gutter_hovered: false,
 1875            pixel_position_of_newest_cursor: None,
 1876            last_bounds: None,
 1877            last_position_map: None,
 1878            expect_bounds_change: None,
 1879            gutter_dimensions: GutterDimensions::default(),
 1880            style: None,
 1881            show_cursor_names: false,
 1882            hovered_cursors: HashMap::default(),
 1883            next_editor_action_id: EditorActionId::default(),
 1884            editor_actions: Rc::default(),
 1885            inline_completions_hidden_for_vim_mode: false,
 1886            show_inline_completions_override: None,
 1887            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1888            edit_prediction_settings: EditPredictionSettings::Disabled,
 1889            edit_prediction_indent_conflict: false,
 1890            edit_prediction_requires_modifier_in_indent_conflict: true,
 1891            custom_context_menu: None,
 1892            show_git_blame_gutter: false,
 1893            show_git_blame_inline: false,
 1894            show_selection_menu: None,
 1895            show_git_blame_inline_delay_task: None,
 1896            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1897            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1898            serialize_dirty_buffers: !mode.is_minimap()
 1899                && ProjectSettings::get_global(cx)
 1900                    .session
 1901                    .restore_unsaved_buffers,
 1902            blame: None,
 1903            blame_subscription: None,
 1904            tasks: BTreeMap::default(),
 1905
 1906            breakpoint_store,
 1907            gutter_breakpoint_indicator: (None, None),
 1908            _subscriptions: vec![
 1909                cx.observe(&buffer, Self::on_buffer_changed),
 1910                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1911                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1912                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1913                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1914                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1915                cx.observe_window_activation(window, |editor, window, cx| {
 1916                    let active = window.is_window_active();
 1917                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1918                        if active {
 1919                            blink_manager.enable(cx);
 1920                        } else {
 1921                            blink_manager.disable(cx);
 1922                        }
 1923                    });
 1924                    if active {
 1925                        editor.show_mouse_cursor();
 1926                    }
 1927                }),
 1928            ],
 1929            tasks_update_task: None,
 1930            linked_edit_ranges: Default::default(),
 1931            in_project_search: false,
 1932            previous_search_ranges: None,
 1933            breadcrumb_header: None,
 1934            focused_block: None,
 1935            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1936            addons: HashMap::default(),
 1937            registered_buffers: HashMap::default(),
 1938            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1939            selection_mark_mode: false,
 1940            toggle_fold_multiple_buffers: Task::ready(()),
 1941            serialize_selections: Task::ready(()),
 1942            serialize_folds: Task::ready(()),
 1943            text_style_refinement: None,
 1944            load_diff_task: load_uncommitted_diff,
 1945            temporary_diff_override: false,
 1946            mouse_cursor_hidden: false,
 1947            minimap: None,
 1948            hide_mouse_mode: EditorSettings::get_global(cx)
 1949                .hide_mouse
 1950                .unwrap_or_default(),
 1951            change_list: ChangeList::new(),
 1952            mode,
 1953        };
 1954        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1955            this._subscriptions
 1956                .push(cx.observe(breakpoints, |_, _, cx| {
 1957                    cx.notify();
 1958                }));
 1959        }
 1960        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1961        this._subscriptions.extend(project_subscriptions);
 1962
 1963        this._subscriptions.push(cx.subscribe_in(
 1964            &cx.entity(),
 1965            window,
 1966            |editor, _, e: &EditorEvent, window, cx| match e {
 1967                EditorEvent::ScrollPositionChanged { local, .. } => {
 1968                    if *local {
 1969                        let new_anchor = editor.scroll_manager.anchor();
 1970                        let snapshot = editor.snapshot(window, cx);
 1971                        editor.update_restoration_data(cx, move |data| {
 1972                            data.scroll_position = (
 1973                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1974                                new_anchor.offset,
 1975                            );
 1976                        });
 1977                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1978                        editor.inline_blame_popover.take();
 1979                    }
 1980                }
 1981                EditorEvent::Edited { .. } => {
 1982                    if !vim_enabled(cx) {
 1983                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1984                        let pop_state = editor
 1985                            .change_list
 1986                            .last()
 1987                            .map(|previous| {
 1988                                previous.len() == selections.len()
 1989                                    && previous.iter().enumerate().all(|(ix, p)| {
 1990                                        p.to_display_point(&map).row()
 1991                                            == selections[ix].head().row()
 1992                                    })
 1993                            })
 1994                            .unwrap_or(false);
 1995                        let new_positions = selections
 1996                            .into_iter()
 1997                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1998                            .collect();
 1999                        editor
 2000                            .change_list
 2001                            .push_to_change_list(pop_state, new_positions);
 2002                    }
 2003                }
 2004                _ => (),
 2005            },
 2006        ));
 2007
 2008        if let Some(dap_store) = this
 2009            .project
 2010            .as_ref()
 2011            .map(|project| project.read(cx).dap_store())
 2012        {
 2013            let weak_editor = cx.weak_entity();
 2014
 2015            this._subscriptions
 2016                .push(
 2017                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2018                        let session_entity = cx.entity();
 2019                        weak_editor
 2020                            .update(cx, |editor, cx| {
 2021                                editor._subscriptions.push(
 2022                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2023                                );
 2024                            })
 2025                            .ok();
 2026                    }),
 2027                );
 2028
 2029            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2030                this._subscriptions
 2031                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2032            }
 2033        }
 2034
 2035        this.end_selection(window, cx);
 2036        this.scroll_manager.show_scrollbars(window, cx);
 2037        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2038
 2039        if full_mode {
 2040            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2041            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2042
 2043            if this.git_blame_inline_enabled {
 2044                this.start_git_blame_inline(false, window, cx);
 2045            }
 2046
 2047            this.go_to_active_debug_line(window, cx);
 2048
 2049            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2050                if let Some(project) = this.project.as_ref() {
 2051                    let handle = project.update(cx, |project, cx| {
 2052                        project.register_buffer_with_language_servers(&buffer, cx)
 2053                    });
 2054                    this.registered_buffers
 2055                        .insert(buffer.read(cx).remote_id(), handle);
 2056                }
 2057            }
 2058
 2059            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2060        }
 2061
 2062        this.report_editor_event("Editor Opened", None, cx);
 2063        this
 2064    }
 2065
 2066    pub fn deploy_mouse_context_menu(
 2067        &mut self,
 2068        position: gpui::Point<Pixels>,
 2069        context_menu: Entity<ContextMenu>,
 2070        window: &mut Window,
 2071        cx: &mut Context<Self>,
 2072    ) {
 2073        self.mouse_context_menu = Some(MouseContextMenu::new(
 2074            self,
 2075            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2076            context_menu,
 2077            window,
 2078            cx,
 2079        ));
 2080    }
 2081
 2082    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2083        self.mouse_context_menu
 2084            .as_ref()
 2085            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2086    }
 2087
 2088    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2089        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2090    }
 2091
 2092    fn key_context_internal(
 2093        &self,
 2094        has_active_edit_prediction: bool,
 2095        window: &Window,
 2096        cx: &App,
 2097    ) -> KeyContext {
 2098        let mut key_context = KeyContext::new_with_defaults();
 2099        key_context.add("Editor");
 2100        let mode = match self.mode {
 2101            EditorMode::SingleLine { .. } => "single_line",
 2102            EditorMode::AutoHeight { .. } => "auto_height",
 2103            EditorMode::Minimap { .. } => "minimap",
 2104            EditorMode::Full { .. } => "full",
 2105        };
 2106
 2107        if EditorSettings::jupyter_enabled(cx) {
 2108            key_context.add("jupyter");
 2109        }
 2110
 2111        key_context.set("mode", mode);
 2112        if self.pending_rename.is_some() {
 2113            key_context.add("renaming");
 2114        }
 2115
 2116        match self.context_menu.borrow().as_ref() {
 2117            Some(CodeContextMenu::Completions(_)) => {
 2118                key_context.add("menu");
 2119                key_context.add("showing_completions");
 2120            }
 2121            Some(CodeContextMenu::CodeActions(_)) => {
 2122                key_context.add("menu");
 2123                key_context.add("showing_code_actions")
 2124            }
 2125            None => {}
 2126        }
 2127
 2128        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2129        if !self.focus_handle(cx).contains_focused(window, cx)
 2130            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2131        {
 2132            for addon in self.addons.values() {
 2133                addon.extend_key_context(&mut key_context, cx)
 2134            }
 2135        }
 2136
 2137        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2138            if let Some(extension) = singleton_buffer
 2139                .read(cx)
 2140                .file()
 2141                .and_then(|file| file.path().extension()?.to_str())
 2142            {
 2143                key_context.set("extension", extension.to_string());
 2144            }
 2145        } else {
 2146            key_context.add("multibuffer");
 2147        }
 2148
 2149        if has_active_edit_prediction {
 2150            if self.edit_prediction_in_conflict() {
 2151                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2152            } else {
 2153                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2154                key_context.add("copilot_suggestion");
 2155            }
 2156        }
 2157
 2158        if self.selection_mark_mode {
 2159            key_context.add("selection_mode");
 2160        }
 2161
 2162        key_context
 2163    }
 2164
 2165    fn show_mouse_cursor(&mut self) {
 2166        self.mouse_cursor_hidden = false;
 2167    }
 2168
 2169    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2170        self.mouse_cursor_hidden = match origin {
 2171            HideMouseCursorOrigin::TypingAction => {
 2172                matches!(
 2173                    self.hide_mouse_mode,
 2174                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2175                )
 2176            }
 2177            HideMouseCursorOrigin::MovementAction => {
 2178                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2179            }
 2180        };
 2181    }
 2182
 2183    pub fn edit_prediction_in_conflict(&self) -> bool {
 2184        if !self.show_edit_predictions_in_menu() {
 2185            return false;
 2186        }
 2187
 2188        let showing_completions = self
 2189            .context_menu
 2190            .borrow()
 2191            .as_ref()
 2192            .map_or(false, |context| {
 2193                matches!(context, CodeContextMenu::Completions(_))
 2194            });
 2195
 2196        showing_completions
 2197            || self.edit_prediction_requires_modifier()
 2198            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2199            // bindings to insert tab characters.
 2200            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2201    }
 2202
 2203    pub fn accept_edit_prediction_keybind(
 2204        &self,
 2205        window: &Window,
 2206        cx: &App,
 2207    ) -> AcceptEditPredictionBinding {
 2208        let key_context = self.key_context_internal(true, window, cx);
 2209        let in_conflict = self.edit_prediction_in_conflict();
 2210
 2211        AcceptEditPredictionBinding(
 2212            window
 2213                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2214                .into_iter()
 2215                .filter(|binding| {
 2216                    !in_conflict
 2217                        || binding
 2218                            .keystrokes()
 2219                            .first()
 2220                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2221                })
 2222                .rev()
 2223                .min_by_key(|binding| {
 2224                    binding
 2225                        .keystrokes()
 2226                        .first()
 2227                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2228                }),
 2229        )
 2230    }
 2231
 2232    pub fn new_file(
 2233        workspace: &mut Workspace,
 2234        _: &workspace::NewFile,
 2235        window: &mut Window,
 2236        cx: &mut Context<Workspace>,
 2237    ) {
 2238        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2239            "Failed to create buffer",
 2240            window,
 2241            cx,
 2242            |e, _, _| match e.error_code() {
 2243                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2244                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2245                e.error_tag("required").unwrap_or("the latest version")
 2246            )),
 2247                _ => None,
 2248            },
 2249        );
 2250    }
 2251
 2252    pub fn new_in_workspace(
 2253        workspace: &mut Workspace,
 2254        window: &mut Window,
 2255        cx: &mut Context<Workspace>,
 2256    ) -> Task<Result<Entity<Editor>>> {
 2257        let project = workspace.project().clone();
 2258        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2259
 2260        cx.spawn_in(window, async move |workspace, cx| {
 2261            let buffer = create.await?;
 2262            workspace.update_in(cx, |workspace, window, cx| {
 2263                let editor =
 2264                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2265                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2266                editor
 2267            })
 2268        })
 2269    }
 2270
 2271    fn new_file_vertical(
 2272        workspace: &mut Workspace,
 2273        _: &workspace::NewFileSplitVertical,
 2274        window: &mut Window,
 2275        cx: &mut Context<Workspace>,
 2276    ) {
 2277        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2278    }
 2279
 2280    fn new_file_horizontal(
 2281        workspace: &mut Workspace,
 2282        _: &workspace::NewFileSplitHorizontal,
 2283        window: &mut Window,
 2284        cx: &mut Context<Workspace>,
 2285    ) {
 2286        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2287    }
 2288
 2289    fn new_file_in_direction(
 2290        workspace: &mut Workspace,
 2291        direction: SplitDirection,
 2292        window: &mut Window,
 2293        cx: &mut Context<Workspace>,
 2294    ) {
 2295        let project = workspace.project().clone();
 2296        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2297
 2298        cx.spawn_in(window, async move |workspace, cx| {
 2299            let buffer = create.await?;
 2300            workspace.update_in(cx, move |workspace, window, cx| {
 2301                workspace.split_item(
 2302                    direction,
 2303                    Box::new(
 2304                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2305                    ),
 2306                    window,
 2307                    cx,
 2308                )
 2309            })?;
 2310            anyhow::Ok(())
 2311        })
 2312        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2313            match e.error_code() {
 2314                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2315                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2316                e.error_tag("required").unwrap_or("the latest version")
 2317            )),
 2318                _ => None,
 2319            }
 2320        });
 2321    }
 2322
 2323    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2324        self.leader_id
 2325    }
 2326
 2327    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2328        &self.buffer
 2329    }
 2330
 2331    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2332        self.workspace.as_ref()?.0.upgrade()
 2333    }
 2334
 2335    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2336        self.buffer().read(cx).title(cx)
 2337    }
 2338
 2339    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2340        let git_blame_gutter_max_author_length = self
 2341            .render_git_blame_gutter(cx)
 2342            .then(|| {
 2343                if let Some(blame) = self.blame.as_ref() {
 2344                    let max_author_length =
 2345                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2346                    Some(max_author_length)
 2347                } else {
 2348                    None
 2349                }
 2350            })
 2351            .flatten();
 2352
 2353        EditorSnapshot {
 2354            mode: self.mode.clone(),
 2355            show_gutter: self.show_gutter,
 2356            show_line_numbers: self.show_line_numbers,
 2357            show_git_diff_gutter: self.show_git_diff_gutter,
 2358            show_code_actions: self.show_code_actions,
 2359            show_runnables: self.show_runnables,
 2360            show_breakpoints: self.show_breakpoints,
 2361            git_blame_gutter_max_author_length,
 2362            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2363            scroll_anchor: self.scroll_manager.anchor(),
 2364            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2365            placeholder_text: self.placeholder_text.clone(),
 2366            is_focused: self.focus_handle.is_focused(window),
 2367            current_line_highlight: self
 2368                .current_line_highlight
 2369                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2370            gutter_hovered: self.gutter_hovered,
 2371        }
 2372    }
 2373
 2374    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2375        self.buffer.read(cx).language_at(point, cx)
 2376    }
 2377
 2378    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2379        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2380    }
 2381
 2382    pub fn active_excerpt(
 2383        &self,
 2384        cx: &App,
 2385    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2386        self.buffer
 2387            .read(cx)
 2388            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2389    }
 2390
 2391    pub fn mode(&self) -> &EditorMode {
 2392        &self.mode
 2393    }
 2394
 2395    pub fn set_mode(&mut self, mode: EditorMode) {
 2396        self.mode = mode;
 2397    }
 2398
 2399    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2400        self.collaboration_hub.as_deref()
 2401    }
 2402
 2403    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2404        self.collaboration_hub = Some(hub);
 2405    }
 2406
 2407    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2408        self.in_project_search = in_project_search;
 2409    }
 2410
 2411    pub fn set_custom_context_menu(
 2412        &mut self,
 2413        f: impl 'static
 2414        + Fn(
 2415            &mut Self,
 2416            DisplayPoint,
 2417            &mut Window,
 2418            &mut Context<Self>,
 2419        ) -> Option<Entity<ui::ContextMenu>>,
 2420    ) {
 2421        self.custom_context_menu = Some(Box::new(f))
 2422    }
 2423
 2424    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2425        self.completion_provider = provider;
 2426    }
 2427
 2428    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2429        self.semantics_provider.clone()
 2430    }
 2431
 2432    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2433        self.semantics_provider = provider;
 2434    }
 2435
 2436    pub fn set_edit_prediction_provider<T>(
 2437        &mut self,
 2438        provider: Option<Entity<T>>,
 2439        window: &mut Window,
 2440        cx: &mut Context<Self>,
 2441    ) where
 2442        T: EditPredictionProvider,
 2443    {
 2444        self.edit_prediction_provider =
 2445            provider.map(|provider| RegisteredInlineCompletionProvider {
 2446                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2447                    if this.focus_handle.is_focused(window) {
 2448                        this.update_visible_inline_completion(window, cx);
 2449                    }
 2450                }),
 2451                provider: Arc::new(provider),
 2452            });
 2453        self.update_edit_prediction_settings(cx);
 2454        self.refresh_inline_completion(false, false, window, cx);
 2455    }
 2456
 2457    pub fn placeholder_text(&self) -> Option<&str> {
 2458        self.placeholder_text.as_deref()
 2459    }
 2460
 2461    pub fn set_placeholder_text(
 2462        &mut self,
 2463        placeholder_text: impl Into<Arc<str>>,
 2464        cx: &mut Context<Self>,
 2465    ) {
 2466        let placeholder_text = Some(placeholder_text.into());
 2467        if self.placeholder_text != placeholder_text {
 2468            self.placeholder_text = placeholder_text;
 2469            cx.notify();
 2470        }
 2471    }
 2472
 2473    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2474        self.cursor_shape = cursor_shape;
 2475
 2476        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2477        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2478
 2479        cx.notify();
 2480    }
 2481
 2482    pub fn set_current_line_highlight(
 2483        &mut self,
 2484        current_line_highlight: Option<CurrentLineHighlight>,
 2485    ) {
 2486        self.current_line_highlight = current_line_highlight;
 2487    }
 2488
 2489    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2490        self.collapse_matches = collapse_matches;
 2491    }
 2492
 2493    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2494        let buffers = self.buffer.read(cx).all_buffers();
 2495        let Some(project) = self.project.as_ref() else {
 2496            return;
 2497        };
 2498        project.update(cx, |project, cx| {
 2499            for buffer in buffers {
 2500                self.registered_buffers
 2501                    .entry(buffer.read(cx).remote_id())
 2502                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2503            }
 2504        })
 2505    }
 2506
 2507    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2508        if self.collapse_matches {
 2509            return range.start..range.start;
 2510        }
 2511        range.clone()
 2512    }
 2513
 2514    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2515        if self.display_map.read(cx).clip_at_line_ends != clip {
 2516            self.display_map
 2517                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2518        }
 2519    }
 2520
 2521    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2522        self.input_enabled = input_enabled;
 2523    }
 2524
 2525    pub fn set_inline_completions_hidden_for_vim_mode(
 2526        &mut self,
 2527        hidden: bool,
 2528        window: &mut Window,
 2529        cx: &mut Context<Self>,
 2530    ) {
 2531        if hidden != self.inline_completions_hidden_for_vim_mode {
 2532            self.inline_completions_hidden_for_vim_mode = hidden;
 2533            if hidden {
 2534                self.update_visible_inline_completion(window, cx);
 2535            } else {
 2536                self.refresh_inline_completion(true, false, window, cx);
 2537            }
 2538        }
 2539    }
 2540
 2541    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2542        self.menu_inline_completions_policy = value;
 2543    }
 2544
 2545    pub fn set_autoindent(&mut self, autoindent: bool) {
 2546        if autoindent {
 2547            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2548        } else {
 2549            self.autoindent_mode = None;
 2550        }
 2551    }
 2552
 2553    pub fn read_only(&self, cx: &App) -> bool {
 2554        self.read_only || self.buffer.read(cx).read_only()
 2555    }
 2556
 2557    pub fn set_read_only(&mut self, read_only: bool) {
 2558        self.read_only = read_only;
 2559    }
 2560
 2561    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2562        self.use_autoclose = autoclose;
 2563    }
 2564
 2565    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2566        self.use_auto_surround = auto_surround;
 2567    }
 2568
 2569    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2570        self.auto_replace_emoji_shortcode = auto_replace;
 2571    }
 2572
 2573    pub fn toggle_edit_predictions(
 2574        &mut self,
 2575        _: &ToggleEditPrediction,
 2576        window: &mut Window,
 2577        cx: &mut Context<Self>,
 2578    ) {
 2579        if self.show_inline_completions_override.is_some() {
 2580            self.set_show_edit_predictions(None, window, cx);
 2581        } else {
 2582            let show_edit_predictions = !self.edit_predictions_enabled();
 2583            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2584        }
 2585    }
 2586
 2587    pub fn set_show_edit_predictions(
 2588        &mut self,
 2589        show_edit_predictions: Option<bool>,
 2590        window: &mut Window,
 2591        cx: &mut Context<Self>,
 2592    ) {
 2593        self.show_inline_completions_override = show_edit_predictions;
 2594        self.update_edit_prediction_settings(cx);
 2595
 2596        if let Some(false) = show_edit_predictions {
 2597            self.discard_inline_completion(false, cx);
 2598        } else {
 2599            self.refresh_inline_completion(false, true, window, cx);
 2600        }
 2601    }
 2602
 2603    fn inline_completions_disabled_in_scope(
 2604        &self,
 2605        buffer: &Entity<Buffer>,
 2606        buffer_position: language::Anchor,
 2607        cx: &App,
 2608    ) -> bool {
 2609        let snapshot = buffer.read(cx).snapshot();
 2610        let settings = snapshot.settings_at(buffer_position, cx);
 2611
 2612        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2613            return false;
 2614        };
 2615
 2616        scope.override_name().map_or(false, |scope_name| {
 2617            settings
 2618                .edit_predictions_disabled_in
 2619                .iter()
 2620                .any(|s| s == scope_name)
 2621        })
 2622    }
 2623
 2624    pub fn set_use_modal_editing(&mut self, to: bool) {
 2625        self.use_modal_editing = to;
 2626    }
 2627
 2628    pub fn use_modal_editing(&self) -> bool {
 2629        self.use_modal_editing
 2630    }
 2631
 2632    fn selections_did_change(
 2633        &mut self,
 2634        local: bool,
 2635        old_cursor_position: &Anchor,
 2636        show_completions: bool,
 2637        window: &mut Window,
 2638        cx: &mut Context<Self>,
 2639    ) {
 2640        window.invalidate_character_coordinates();
 2641
 2642        // Copy selections to primary selection buffer
 2643        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2644        if local {
 2645            let selections = self.selections.all::<usize>(cx);
 2646            let buffer_handle = self.buffer.read(cx).read(cx);
 2647
 2648            let mut text = String::new();
 2649            for (index, selection) in selections.iter().enumerate() {
 2650                let text_for_selection = buffer_handle
 2651                    .text_for_range(selection.start..selection.end)
 2652                    .collect::<String>();
 2653
 2654                text.push_str(&text_for_selection);
 2655                if index != selections.len() - 1 {
 2656                    text.push('\n');
 2657                }
 2658            }
 2659
 2660            if !text.is_empty() {
 2661                cx.write_to_primary(ClipboardItem::new_string(text));
 2662            }
 2663        }
 2664
 2665        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2666            self.buffer.update(cx, |buffer, cx| {
 2667                buffer.set_active_selections(
 2668                    &self.selections.disjoint_anchors(),
 2669                    self.selections.line_mode,
 2670                    self.cursor_shape,
 2671                    cx,
 2672                )
 2673            });
 2674        }
 2675        let display_map = self
 2676            .display_map
 2677            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2678        let buffer = &display_map.buffer_snapshot;
 2679        self.add_selections_state = None;
 2680        self.select_next_state = None;
 2681        self.select_prev_state = None;
 2682        self.select_syntax_node_history.try_clear();
 2683        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2684        self.snippet_stack
 2685            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2686        self.take_rename(false, window, cx);
 2687
 2688        let new_cursor_position = self.selections.newest_anchor().head();
 2689
 2690        self.push_to_nav_history(
 2691            *old_cursor_position,
 2692            Some(new_cursor_position.to_point(buffer)),
 2693            false,
 2694            cx,
 2695        );
 2696
 2697        if local {
 2698            let new_cursor_position = self.selections.newest_anchor().head();
 2699            let mut context_menu = self.context_menu.borrow_mut();
 2700            let completion_menu = match context_menu.as_ref() {
 2701                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2702                _ => {
 2703                    *context_menu = None;
 2704                    None
 2705                }
 2706            };
 2707            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2708                if !self.registered_buffers.contains_key(&buffer_id) {
 2709                    if let Some(project) = self.project.as_ref() {
 2710                        project.update(cx, |project, cx| {
 2711                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2712                                return;
 2713                            };
 2714                            self.registered_buffers.insert(
 2715                                buffer_id,
 2716                                project.register_buffer_with_language_servers(&buffer, cx),
 2717                            );
 2718                        })
 2719                    }
 2720                }
 2721            }
 2722
 2723            if let Some(completion_menu) = completion_menu {
 2724                let cursor_position = new_cursor_position.to_offset(buffer);
 2725                let (word_range, kind) =
 2726                    buffer.surrounding_word(completion_menu.initial_position, true);
 2727                if kind == Some(CharKind::Word)
 2728                    && word_range.to_inclusive().contains(&cursor_position)
 2729                {
 2730                    let mut completion_menu = completion_menu.clone();
 2731                    drop(context_menu);
 2732
 2733                    let query = Self::completion_query(buffer, cursor_position);
 2734                    let completion_provider = self.completion_provider.clone();
 2735                    cx.spawn_in(window, async move |this, cx| {
 2736                        completion_menu
 2737                            .filter(query.as_deref(), completion_provider, this.clone(), cx)
 2738                            .await;
 2739
 2740                        this.update(cx, |this, cx| {
 2741                            let mut context_menu = this.context_menu.borrow_mut();
 2742                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2743                            else {
 2744                                return;
 2745                            };
 2746
 2747                            if menu.id > completion_menu.id {
 2748                                return;
 2749                            }
 2750
 2751                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2752                            drop(context_menu);
 2753                            cx.notify();
 2754                        })
 2755                    })
 2756                    .detach();
 2757
 2758                    if show_completions {
 2759                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2760                    }
 2761                } else {
 2762                    drop(context_menu);
 2763                    self.hide_context_menu(window, cx);
 2764                }
 2765            } else {
 2766                drop(context_menu);
 2767            }
 2768
 2769            hide_hover(self, cx);
 2770
 2771            if old_cursor_position.to_display_point(&display_map).row()
 2772                != new_cursor_position.to_display_point(&display_map).row()
 2773            {
 2774                self.available_code_actions.take();
 2775            }
 2776            self.refresh_code_actions(window, cx);
 2777            self.refresh_document_highlights(cx);
 2778            self.refresh_selected_text_highlights(false, window, cx);
 2779            refresh_matching_bracket_highlights(self, window, cx);
 2780            self.update_visible_inline_completion(window, cx);
 2781            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2782            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2783            self.inline_blame_popover.take();
 2784            if self.git_blame_inline_enabled {
 2785                self.start_inline_blame_timer(window, cx);
 2786            }
 2787        }
 2788
 2789        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2790        cx.emit(EditorEvent::SelectionsChanged { local });
 2791
 2792        let selections = &self.selections.disjoint;
 2793        if selections.len() == 1 {
 2794            cx.emit(SearchEvent::ActiveMatchChanged)
 2795        }
 2796        if local {
 2797            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2798                let inmemory_selections = selections
 2799                    .iter()
 2800                    .map(|s| {
 2801                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2802                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2803                    })
 2804                    .collect();
 2805                self.update_restoration_data(cx, |data| {
 2806                    data.selections = inmemory_selections;
 2807                });
 2808
 2809                if WorkspaceSettings::get(None, cx).restore_on_startup
 2810                    != RestoreOnStartupBehavior::None
 2811                {
 2812                    if let Some(workspace_id) =
 2813                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2814                    {
 2815                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2816                        let selections = selections.clone();
 2817                        let background_executor = cx.background_executor().clone();
 2818                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2819                        self.serialize_selections = cx.background_spawn(async move {
 2820                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2821                    let db_selections = selections
 2822                        .iter()
 2823                        .map(|selection| {
 2824                            (
 2825                                selection.start.to_offset(&snapshot),
 2826                                selection.end.to_offset(&snapshot),
 2827                            )
 2828                        })
 2829                        .collect();
 2830
 2831                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2832                        .await
 2833                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2834                        .log_err();
 2835                });
 2836                    }
 2837                }
 2838            }
 2839        }
 2840
 2841        cx.notify();
 2842    }
 2843
 2844    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2845        use text::ToOffset as _;
 2846        use text::ToPoint as _;
 2847
 2848        if self.mode.is_minimap()
 2849            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2850        {
 2851            return;
 2852        }
 2853
 2854        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2855            return;
 2856        };
 2857
 2858        let snapshot = singleton.read(cx).snapshot();
 2859        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2860            let display_snapshot = display_map.snapshot(cx);
 2861
 2862            display_snapshot
 2863                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2864                .map(|fold| {
 2865                    fold.range.start.text_anchor.to_point(&snapshot)
 2866                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2867                })
 2868                .collect()
 2869        });
 2870        self.update_restoration_data(cx, |data| {
 2871            data.folds = inmemory_folds;
 2872        });
 2873
 2874        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2875            return;
 2876        };
 2877        let background_executor = cx.background_executor().clone();
 2878        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2879        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2880            display_map
 2881                .snapshot(cx)
 2882                .folds_in_range(0..snapshot.len())
 2883                .map(|fold| {
 2884                    (
 2885                        fold.range.start.text_anchor.to_offset(&snapshot),
 2886                        fold.range.end.text_anchor.to_offset(&snapshot),
 2887                    )
 2888                })
 2889                .collect()
 2890        });
 2891        self.serialize_folds = cx.background_spawn(async move {
 2892            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2893            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2894                .await
 2895                .with_context(|| {
 2896                    format!(
 2897                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2898                    )
 2899                })
 2900                .log_err();
 2901        });
 2902    }
 2903
 2904    pub fn sync_selections(
 2905        &mut self,
 2906        other: Entity<Editor>,
 2907        cx: &mut Context<Self>,
 2908    ) -> gpui::Subscription {
 2909        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2910        self.selections.change_with(cx, |selections| {
 2911            selections.select_anchors(other_selections);
 2912        });
 2913
 2914        let other_subscription =
 2915            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2916                EditorEvent::SelectionsChanged { local: true } => {
 2917                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2918                    if other_selections.is_empty() {
 2919                        return;
 2920                    }
 2921                    this.selections.change_with(cx, |selections| {
 2922                        selections.select_anchors(other_selections);
 2923                    });
 2924                }
 2925                _ => {}
 2926            });
 2927
 2928        let this_subscription =
 2929            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2930                EditorEvent::SelectionsChanged { local: true } => {
 2931                    let these_selections = this.selections.disjoint.to_vec();
 2932                    if these_selections.is_empty() {
 2933                        return;
 2934                    }
 2935                    other.update(cx, |other_editor, cx| {
 2936                        other_editor.selections.change_with(cx, |selections| {
 2937                            selections.select_anchors(these_selections);
 2938                        })
 2939                    });
 2940                }
 2941                _ => {}
 2942            });
 2943
 2944        Subscription::join(other_subscription, this_subscription)
 2945    }
 2946
 2947    pub fn change_selections<R>(
 2948        &mut self,
 2949        autoscroll: Option<Autoscroll>,
 2950        window: &mut Window,
 2951        cx: &mut Context<Self>,
 2952        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2953    ) -> R {
 2954        self.change_selections_inner(autoscroll, true, window, cx, change)
 2955    }
 2956
 2957    fn change_selections_inner<R>(
 2958        &mut self,
 2959        autoscroll: Option<Autoscroll>,
 2960        request_completions: bool,
 2961        window: &mut Window,
 2962        cx: &mut Context<Self>,
 2963        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2964    ) -> R {
 2965        let old_cursor_position = self.selections.newest_anchor().head();
 2966        self.push_to_selection_history();
 2967
 2968        let (changed, result) = self.selections.change_with(cx, change);
 2969
 2970        if changed {
 2971            if let Some(autoscroll) = autoscroll {
 2972                self.request_autoscroll(autoscroll, cx);
 2973            }
 2974            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2975
 2976            if self.should_open_signature_help_automatically(
 2977                &old_cursor_position,
 2978                self.signature_help_state.backspace_pressed(),
 2979                cx,
 2980            ) {
 2981                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2982            }
 2983            self.signature_help_state.set_backspace_pressed(false);
 2984        }
 2985
 2986        result
 2987    }
 2988
 2989    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2990    where
 2991        I: IntoIterator<Item = (Range<S>, T)>,
 2992        S: ToOffset,
 2993        T: Into<Arc<str>>,
 2994    {
 2995        if self.read_only(cx) {
 2996            return;
 2997        }
 2998
 2999        self.buffer
 3000            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3001    }
 3002
 3003    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3004    where
 3005        I: IntoIterator<Item = (Range<S>, T)>,
 3006        S: ToOffset,
 3007        T: Into<Arc<str>>,
 3008    {
 3009        if self.read_only(cx) {
 3010            return;
 3011        }
 3012
 3013        self.buffer.update(cx, |buffer, cx| {
 3014            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3015        });
 3016    }
 3017
 3018    pub fn edit_with_block_indent<I, S, T>(
 3019        &mut self,
 3020        edits: I,
 3021        original_indent_columns: Vec<Option<u32>>,
 3022        cx: &mut Context<Self>,
 3023    ) where
 3024        I: IntoIterator<Item = (Range<S>, T)>,
 3025        S: ToOffset,
 3026        T: Into<Arc<str>>,
 3027    {
 3028        if self.read_only(cx) {
 3029            return;
 3030        }
 3031
 3032        self.buffer.update(cx, |buffer, cx| {
 3033            buffer.edit(
 3034                edits,
 3035                Some(AutoindentMode::Block {
 3036                    original_indent_columns,
 3037                }),
 3038                cx,
 3039            )
 3040        });
 3041    }
 3042
 3043    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3044        self.hide_context_menu(window, cx);
 3045
 3046        match phase {
 3047            SelectPhase::Begin {
 3048                position,
 3049                add,
 3050                click_count,
 3051            } => self.begin_selection(position, add, click_count, window, cx),
 3052            SelectPhase::BeginColumnar {
 3053                position,
 3054                goal_column,
 3055                reset,
 3056            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3057            SelectPhase::Extend {
 3058                position,
 3059                click_count,
 3060            } => self.extend_selection(position, click_count, window, cx),
 3061            SelectPhase::Update {
 3062                position,
 3063                goal_column,
 3064                scroll_delta,
 3065            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3066            SelectPhase::End => self.end_selection(window, cx),
 3067        }
 3068    }
 3069
 3070    fn extend_selection(
 3071        &mut self,
 3072        position: DisplayPoint,
 3073        click_count: usize,
 3074        window: &mut Window,
 3075        cx: &mut Context<Self>,
 3076    ) {
 3077        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3078        let tail = self.selections.newest::<usize>(cx).tail();
 3079        self.begin_selection(position, false, click_count, window, cx);
 3080
 3081        let position = position.to_offset(&display_map, Bias::Left);
 3082        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3083
 3084        let mut pending_selection = self
 3085            .selections
 3086            .pending_anchor()
 3087            .expect("extend_selection not called with pending selection");
 3088        if position >= tail {
 3089            pending_selection.start = tail_anchor;
 3090        } else {
 3091            pending_selection.end = tail_anchor;
 3092            pending_selection.reversed = true;
 3093        }
 3094
 3095        let mut pending_mode = self.selections.pending_mode().unwrap();
 3096        match &mut pending_mode {
 3097            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3098            _ => {}
 3099        }
 3100
 3101        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3102
 3103        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3104            s.set_pending(pending_selection, pending_mode)
 3105        });
 3106    }
 3107
 3108    fn begin_selection(
 3109        &mut self,
 3110        position: DisplayPoint,
 3111        add: bool,
 3112        click_count: usize,
 3113        window: &mut Window,
 3114        cx: &mut Context<Self>,
 3115    ) {
 3116        if !self.focus_handle.is_focused(window) {
 3117            self.last_focused_descendant = None;
 3118            window.focus(&self.focus_handle);
 3119        }
 3120
 3121        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3122        let buffer = &display_map.buffer_snapshot;
 3123        let position = display_map.clip_point(position, Bias::Left);
 3124
 3125        let start;
 3126        let end;
 3127        let mode;
 3128        let mut auto_scroll;
 3129        match click_count {
 3130            1 => {
 3131                start = buffer.anchor_before(position.to_point(&display_map));
 3132                end = start;
 3133                mode = SelectMode::Character;
 3134                auto_scroll = true;
 3135            }
 3136            2 => {
 3137                let range = movement::surrounding_word(&display_map, position);
 3138                start = buffer.anchor_before(range.start.to_point(&display_map));
 3139                end = buffer.anchor_before(range.end.to_point(&display_map));
 3140                mode = SelectMode::Word(start..end);
 3141                auto_scroll = true;
 3142            }
 3143            3 => {
 3144                let position = display_map
 3145                    .clip_point(position, Bias::Left)
 3146                    .to_point(&display_map);
 3147                let line_start = display_map.prev_line_boundary(position).0;
 3148                let next_line_start = buffer.clip_point(
 3149                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3150                    Bias::Left,
 3151                );
 3152                start = buffer.anchor_before(line_start);
 3153                end = buffer.anchor_before(next_line_start);
 3154                mode = SelectMode::Line(start..end);
 3155                auto_scroll = true;
 3156            }
 3157            _ => {
 3158                start = buffer.anchor_before(0);
 3159                end = buffer.anchor_before(buffer.len());
 3160                mode = SelectMode::All;
 3161                auto_scroll = false;
 3162            }
 3163        }
 3164        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3165
 3166        let point_to_delete: Option<usize> = {
 3167            let selected_points: Vec<Selection<Point>> =
 3168                self.selections.disjoint_in_range(start..end, cx);
 3169
 3170            if !add || click_count > 1 {
 3171                None
 3172            } else if !selected_points.is_empty() {
 3173                Some(selected_points[0].id)
 3174            } else {
 3175                let clicked_point_already_selected =
 3176                    self.selections.disjoint.iter().find(|selection| {
 3177                        selection.start.to_point(buffer) == start.to_point(buffer)
 3178                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3179                    });
 3180
 3181                clicked_point_already_selected.map(|selection| selection.id)
 3182            }
 3183        };
 3184
 3185        let selections_count = self.selections.count();
 3186
 3187        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3188            if let Some(point_to_delete) = point_to_delete {
 3189                s.delete(point_to_delete);
 3190
 3191                if selections_count == 1 {
 3192                    s.set_pending_anchor_range(start..end, mode);
 3193                }
 3194            } else {
 3195                if !add {
 3196                    s.clear_disjoint();
 3197                }
 3198
 3199                s.set_pending_anchor_range(start..end, mode);
 3200            }
 3201        });
 3202    }
 3203
 3204    fn begin_columnar_selection(
 3205        &mut self,
 3206        position: DisplayPoint,
 3207        goal_column: u32,
 3208        reset: bool,
 3209        window: &mut Window,
 3210        cx: &mut Context<Self>,
 3211    ) {
 3212        if !self.focus_handle.is_focused(window) {
 3213            self.last_focused_descendant = None;
 3214            window.focus(&self.focus_handle);
 3215        }
 3216
 3217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3218
 3219        if reset {
 3220            let pointer_position = display_map
 3221                .buffer_snapshot
 3222                .anchor_before(position.to_point(&display_map));
 3223
 3224            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3225                s.clear_disjoint();
 3226                s.set_pending_anchor_range(
 3227                    pointer_position..pointer_position,
 3228                    SelectMode::Character,
 3229                );
 3230            });
 3231        }
 3232
 3233        let tail = self.selections.newest::<Point>(cx).tail();
 3234        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3235
 3236        if !reset {
 3237            self.select_columns(
 3238                tail.to_display_point(&display_map),
 3239                position,
 3240                goal_column,
 3241                &display_map,
 3242                window,
 3243                cx,
 3244            );
 3245        }
 3246    }
 3247
 3248    fn update_selection(
 3249        &mut self,
 3250        position: DisplayPoint,
 3251        goal_column: u32,
 3252        scroll_delta: gpui::Point<f32>,
 3253        window: &mut Window,
 3254        cx: &mut Context<Self>,
 3255    ) {
 3256        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3257
 3258        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3259            let tail = tail.to_display_point(&display_map);
 3260            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3261        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3262            let buffer = self.buffer.read(cx).snapshot(cx);
 3263            let head;
 3264            let tail;
 3265            let mode = self.selections.pending_mode().unwrap();
 3266            match &mode {
 3267                SelectMode::Character => {
 3268                    head = position.to_point(&display_map);
 3269                    tail = pending.tail().to_point(&buffer);
 3270                }
 3271                SelectMode::Word(original_range) => {
 3272                    let original_display_range = original_range.start.to_display_point(&display_map)
 3273                        ..original_range.end.to_display_point(&display_map);
 3274                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3275                        ..original_display_range.end.to_point(&display_map);
 3276                    if movement::is_inside_word(&display_map, position)
 3277                        || original_display_range.contains(&position)
 3278                    {
 3279                        let word_range = movement::surrounding_word(&display_map, position);
 3280                        if word_range.start < original_display_range.start {
 3281                            head = word_range.start.to_point(&display_map);
 3282                        } else {
 3283                            head = word_range.end.to_point(&display_map);
 3284                        }
 3285                    } else {
 3286                        head = position.to_point(&display_map);
 3287                    }
 3288
 3289                    if head <= original_buffer_range.start {
 3290                        tail = original_buffer_range.end;
 3291                    } else {
 3292                        tail = original_buffer_range.start;
 3293                    }
 3294                }
 3295                SelectMode::Line(original_range) => {
 3296                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3297
 3298                    let position = display_map
 3299                        .clip_point(position, Bias::Left)
 3300                        .to_point(&display_map);
 3301                    let line_start = display_map.prev_line_boundary(position).0;
 3302                    let next_line_start = buffer.clip_point(
 3303                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3304                        Bias::Left,
 3305                    );
 3306
 3307                    if line_start < original_range.start {
 3308                        head = line_start
 3309                    } else {
 3310                        head = next_line_start
 3311                    }
 3312
 3313                    if head <= original_range.start {
 3314                        tail = original_range.end;
 3315                    } else {
 3316                        tail = original_range.start;
 3317                    }
 3318                }
 3319                SelectMode::All => {
 3320                    return;
 3321                }
 3322            };
 3323
 3324            if head < tail {
 3325                pending.start = buffer.anchor_before(head);
 3326                pending.end = buffer.anchor_before(tail);
 3327                pending.reversed = true;
 3328            } else {
 3329                pending.start = buffer.anchor_before(tail);
 3330                pending.end = buffer.anchor_before(head);
 3331                pending.reversed = false;
 3332            }
 3333
 3334            self.change_selections(None, window, cx, |s| {
 3335                s.set_pending(pending, mode);
 3336            });
 3337        } else {
 3338            log::error!("update_selection dispatched with no pending selection");
 3339            return;
 3340        }
 3341
 3342        self.apply_scroll_delta(scroll_delta, window, cx);
 3343        cx.notify();
 3344    }
 3345
 3346    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3347        self.columnar_selection_tail.take();
 3348        if self.selections.pending_anchor().is_some() {
 3349            let selections = self.selections.all::<usize>(cx);
 3350            self.change_selections(None, window, cx, |s| {
 3351                s.select(selections);
 3352                s.clear_pending();
 3353            });
 3354        }
 3355    }
 3356
 3357    fn select_columns(
 3358        &mut self,
 3359        tail: DisplayPoint,
 3360        head: DisplayPoint,
 3361        goal_column: u32,
 3362        display_map: &DisplaySnapshot,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365    ) {
 3366        let start_row = cmp::min(tail.row(), head.row());
 3367        let end_row = cmp::max(tail.row(), head.row());
 3368        let start_column = cmp::min(tail.column(), goal_column);
 3369        let end_column = cmp::max(tail.column(), goal_column);
 3370        let reversed = start_column < tail.column();
 3371
 3372        let selection_ranges = (start_row.0..=end_row.0)
 3373            .map(DisplayRow)
 3374            .filter_map(|row| {
 3375                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3376                    let start = display_map
 3377                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3378                        .to_point(display_map);
 3379                    let end = display_map
 3380                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3381                        .to_point(display_map);
 3382                    if reversed {
 3383                        Some(end..start)
 3384                    } else {
 3385                        Some(start..end)
 3386                    }
 3387                } else {
 3388                    None
 3389                }
 3390            })
 3391            .collect::<Vec<_>>();
 3392
 3393        self.change_selections(None, window, cx, |s| {
 3394            s.select_ranges(selection_ranges);
 3395        });
 3396        cx.notify();
 3397    }
 3398
 3399    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3400        self.selections
 3401            .all_adjusted(cx)
 3402            .iter()
 3403            .any(|selection| !selection.is_empty())
 3404    }
 3405
 3406    pub fn has_pending_nonempty_selection(&self) -> bool {
 3407        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3408            Some(Selection { start, end, .. }) => start != end,
 3409            None => false,
 3410        };
 3411
 3412        pending_nonempty_selection
 3413            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3414    }
 3415
 3416    pub fn has_pending_selection(&self) -> bool {
 3417        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3418    }
 3419
 3420    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3421        self.selection_mark_mode = false;
 3422
 3423        if self.clear_expanded_diff_hunks(cx) {
 3424            cx.notify();
 3425            return;
 3426        }
 3427        if self.dismiss_menus_and_popups(true, window, cx) {
 3428            return;
 3429        }
 3430
 3431        if self.mode.is_full()
 3432            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3433        {
 3434            return;
 3435        }
 3436
 3437        cx.propagate();
 3438    }
 3439
 3440    pub fn dismiss_menus_and_popups(
 3441        &mut self,
 3442        is_user_requested: bool,
 3443        window: &mut Window,
 3444        cx: &mut Context<Self>,
 3445    ) -> bool {
 3446        if self.take_rename(false, window, cx).is_some() {
 3447            return true;
 3448        }
 3449
 3450        if hide_hover(self, cx) {
 3451            return true;
 3452        }
 3453
 3454        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3455            return true;
 3456        }
 3457
 3458        if self.hide_context_menu(window, cx).is_some() {
 3459            return true;
 3460        }
 3461
 3462        if self.mouse_context_menu.take().is_some() {
 3463            return true;
 3464        }
 3465
 3466        if is_user_requested && self.discard_inline_completion(true, cx) {
 3467            return true;
 3468        }
 3469
 3470        if self.snippet_stack.pop().is_some() {
 3471            return true;
 3472        }
 3473
 3474        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3475            self.dismiss_diagnostics(cx);
 3476            return true;
 3477        }
 3478
 3479        false
 3480    }
 3481
 3482    fn linked_editing_ranges_for(
 3483        &self,
 3484        selection: Range<text::Anchor>,
 3485        cx: &App,
 3486    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3487        if self.linked_edit_ranges.is_empty() {
 3488            return None;
 3489        }
 3490        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3491            selection.end.buffer_id.and_then(|end_buffer_id| {
 3492                if selection.start.buffer_id != Some(end_buffer_id) {
 3493                    return None;
 3494                }
 3495                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3496                let snapshot = buffer.read(cx).snapshot();
 3497                self.linked_edit_ranges
 3498                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3499                    .map(|ranges| (ranges, snapshot, buffer))
 3500            })?;
 3501        use text::ToOffset as TO;
 3502        // find offset from the start of current range to current cursor position
 3503        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3504
 3505        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3506        let start_difference = start_offset - start_byte_offset;
 3507        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3508        let end_difference = end_offset - start_byte_offset;
 3509        // Current range has associated linked ranges.
 3510        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3511        for range in linked_ranges.iter() {
 3512            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3513            let end_offset = start_offset + end_difference;
 3514            let start_offset = start_offset + start_difference;
 3515            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3516                continue;
 3517            }
 3518            if self.selections.disjoint_anchor_ranges().any(|s| {
 3519                if s.start.buffer_id != selection.start.buffer_id
 3520                    || s.end.buffer_id != selection.end.buffer_id
 3521                {
 3522                    return false;
 3523                }
 3524                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3525                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3526            }) {
 3527                continue;
 3528            }
 3529            let start = buffer_snapshot.anchor_after(start_offset);
 3530            let end = buffer_snapshot.anchor_after(end_offset);
 3531            linked_edits
 3532                .entry(buffer.clone())
 3533                .or_default()
 3534                .push(start..end);
 3535        }
 3536        Some(linked_edits)
 3537    }
 3538
 3539    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3540        let text: Arc<str> = text.into();
 3541
 3542        if self.read_only(cx) {
 3543            return;
 3544        }
 3545
 3546        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3547
 3548        let selections = self.selections.all_adjusted(cx);
 3549        let mut bracket_inserted = false;
 3550        let mut edits = Vec::new();
 3551        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3552        let mut new_selections = Vec::with_capacity(selections.len());
 3553        let mut new_autoclose_regions = Vec::new();
 3554        let snapshot = self.buffer.read(cx).read(cx);
 3555        let mut clear_linked_edit_ranges = false;
 3556
 3557        for (selection, autoclose_region) in
 3558            self.selections_with_autoclose_regions(selections, &snapshot)
 3559        {
 3560            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3561                // Determine if the inserted text matches the opening or closing
 3562                // bracket of any of this language's bracket pairs.
 3563                let mut bracket_pair = None;
 3564                let mut is_bracket_pair_start = false;
 3565                let mut is_bracket_pair_end = false;
 3566                if !text.is_empty() {
 3567                    let mut bracket_pair_matching_end = None;
 3568                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3569                    //  and they are removing the character that triggered IME popup.
 3570                    for (pair, enabled) in scope.brackets() {
 3571                        if !pair.close && !pair.surround {
 3572                            continue;
 3573                        }
 3574
 3575                        if enabled && pair.start.ends_with(text.as_ref()) {
 3576                            let prefix_len = pair.start.len() - text.len();
 3577                            let preceding_text_matches_prefix = prefix_len == 0
 3578                                || (selection.start.column >= (prefix_len as u32)
 3579                                    && snapshot.contains_str_at(
 3580                                        Point::new(
 3581                                            selection.start.row,
 3582                                            selection.start.column - (prefix_len as u32),
 3583                                        ),
 3584                                        &pair.start[..prefix_len],
 3585                                    ));
 3586                            if preceding_text_matches_prefix {
 3587                                bracket_pair = Some(pair.clone());
 3588                                is_bracket_pair_start = true;
 3589                                break;
 3590                            }
 3591                        }
 3592                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3593                        {
 3594                            // take first bracket pair matching end, but don't break in case a later bracket
 3595                            // pair matches start
 3596                            bracket_pair_matching_end = Some(pair.clone());
 3597                        }
 3598                    }
 3599                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3600                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3601                        is_bracket_pair_end = true;
 3602                    }
 3603                }
 3604
 3605                if let Some(bracket_pair) = bracket_pair {
 3606                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3607                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3608                    let auto_surround =
 3609                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3610                    if selection.is_empty() {
 3611                        if is_bracket_pair_start {
 3612                            // If the inserted text is a suffix of an opening bracket and the
 3613                            // selection is preceded by the rest of the opening bracket, then
 3614                            // insert the closing bracket.
 3615                            let following_text_allows_autoclose = snapshot
 3616                                .chars_at(selection.start)
 3617                                .next()
 3618                                .map_or(true, |c| scope.should_autoclose_before(c));
 3619
 3620                            let preceding_text_allows_autoclose = selection.start.column == 0
 3621                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3622                                    true,
 3623                                    |c| {
 3624                                        bracket_pair.start != bracket_pair.end
 3625                                            || !snapshot
 3626                                                .char_classifier_at(selection.start)
 3627                                                .is_word(c)
 3628                                    },
 3629                                );
 3630
 3631                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3632                                && bracket_pair.start.len() == 1
 3633                            {
 3634                                let target = bracket_pair.start.chars().next().unwrap();
 3635                                let current_line_count = snapshot
 3636                                    .reversed_chars_at(selection.start)
 3637                                    .take_while(|&c| c != '\n')
 3638                                    .filter(|&c| c == target)
 3639                                    .count();
 3640                                current_line_count % 2 == 1
 3641                            } else {
 3642                                false
 3643                            };
 3644
 3645                            if autoclose
 3646                                && bracket_pair.close
 3647                                && following_text_allows_autoclose
 3648                                && preceding_text_allows_autoclose
 3649                                && !is_closing_quote
 3650                            {
 3651                                let anchor = snapshot.anchor_before(selection.end);
 3652                                new_selections.push((selection.map(|_| anchor), text.len()));
 3653                                new_autoclose_regions.push((
 3654                                    anchor,
 3655                                    text.len(),
 3656                                    selection.id,
 3657                                    bracket_pair.clone(),
 3658                                ));
 3659                                edits.push((
 3660                                    selection.range(),
 3661                                    format!("{}{}", text, bracket_pair.end).into(),
 3662                                ));
 3663                                bracket_inserted = true;
 3664                                continue;
 3665                            }
 3666                        }
 3667
 3668                        if let Some(region) = autoclose_region {
 3669                            // If the selection is followed by an auto-inserted closing bracket,
 3670                            // then don't insert that closing bracket again; just move the selection
 3671                            // past the closing bracket.
 3672                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3673                                && text.as_ref() == region.pair.end.as_str();
 3674                            if should_skip {
 3675                                let anchor = snapshot.anchor_after(selection.end);
 3676                                new_selections
 3677                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3678                                continue;
 3679                            }
 3680                        }
 3681
 3682                        let always_treat_brackets_as_autoclosed = snapshot
 3683                            .language_settings_at(selection.start, cx)
 3684                            .always_treat_brackets_as_autoclosed;
 3685                        if always_treat_brackets_as_autoclosed
 3686                            && is_bracket_pair_end
 3687                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3688                        {
 3689                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3690                            // and the inserted text is a closing bracket and the selection is followed
 3691                            // by the closing bracket then move the selection past the closing bracket.
 3692                            let anchor = snapshot.anchor_after(selection.end);
 3693                            new_selections.push((selection.map(|_| anchor), text.len()));
 3694                            continue;
 3695                        }
 3696                    }
 3697                    // If an opening bracket is 1 character long and is typed while
 3698                    // text is selected, then surround that text with the bracket pair.
 3699                    else if auto_surround
 3700                        && bracket_pair.surround
 3701                        && is_bracket_pair_start
 3702                        && bracket_pair.start.chars().count() == 1
 3703                    {
 3704                        edits.push((selection.start..selection.start, text.clone()));
 3705                        edits.push((
 3706                            selection.end..selection.end,
 3707                            bracket_pair.end.as_str().into(),
 3708                        ));
 3709                        bracket_inserted = true;
 3710                        new_selections.push((
 3711                            Selection {
 3712                                id: selection.id,
 3713                                start: snapshot.anchor_after(selection.start),
 3714                                end: snapshot.anchor_before(selection.end),
 3715                                reversed: selection.reversed,
 3716                                goal: selection.goal,
 3717                            },
 3718                            0,
 3719                        ));
 3720                        continue;
 3721                    }
 3722                }
 3723            }
 3724
 3725            if self.auto_replace_emoji_shortcode
 3726                && selection.is_empty()
 3727                && text.as_ref().ends_with(':')
 3728            {
 3729                if let Some(possible_emoji_short_code) =
 3730                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3731                {
 3732                    if !possible_emoji_short_code.is_empty() {
 3733                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3734                            let emoji_shortcode_start = Point::new(
 3735                                selection.start.row,
 3736                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3737                            );
 3738
 3739                            // Remove shortcode from buffer
 3740                            edits.push((
 3741                                emoji_shortcode_start..selection.start,
 3742                                "".to_string().into(),
 3743                            ));
 3744                            new_selections.push((
 3745                                Selection {
 3746                                    id: selection.id,
 3747                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3748                                    end: snapshot.anchor_before(selection.start),
 3749                                    reversed: selection.reversed,
 3750                                    goal: selection.goal,
 3751                                },
 3752                                0,
 3753                            ));
 3754
 3755                            // Insert emoji
 3756                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3757                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3758                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3759
 3760                            continue;
 3761                        }
 3762                    }
 3763                }
 3764            }
 3765
 3766            // If not handling any auto-close operation, then just replace the selected
 3767            // text with the given input and move the selection to the end of the
 3768            // newly inserted text.
 3769            let anchor = snapshot.anchor_after(selection.end);
 3770            if !self.linked_edit_ranges.is_empty() {
 3771                let start_anchor = snapshot.anchor_before(selection.start);
 3772
 3773                let is_word_char = text.chars().next().map_or(true, |char| {
 3774                    let classifier = snapshot
 3775                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3776                        .ignore_punctuation(true);
 3777                    classifier.is_word(char)
 3778                });
 3779
 3780                if is_word_char {
 3781                    if let Some(ranges) = self
 3782                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3783                    {
 3784                        for (buffer, edits) in ranges {
 3785                            linked_edits
 3786                                .entry(buffer.clone())
 3787                                .or_default()
 3788                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3789                        }
 3790                    }
 3791                } else {
 3792                    clear_linked_edit_ranges = true;
 3793                }
 3794            }
 3795
 3796            new_selections.push((selection.map(|_| anchor), 0));
 3797            edits.push((selection.start..selection.end, text.clone()));
 3798        }
 3799
 3800        drop(snapshot);
 3801
 3802        self.transact(window, cx, |this, window, cx| {
 3803            if clear_linked_edit_ranges {
 3804                this.linked_edit_ranges.clear();
 3805            }
 3806            let initial_buffer_versions =
 3807                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3808
 3809            this.buffer.update(cx, |buffer, cx| {
 3810                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3811            });
 3812            for (buffer, edits) in linked_edits {
 3813                buffer.update(cx, |buffer, cx| {
 3814                    let snapshot = buffer.snapshot();
 3815                    let edits = edits
 3816                        .into_iter()
 3817                        .map(|(range, text)| {
 3818                            use text::ToPoint as TP;
 3819                            let end_point = TP::to_point(&range.end, &snapshot);
 3820                            let start_point = TP::to_point(&range.start, &snapshot);
 3821                            (start_point..end_point, text)
 3822                        })
 3823                        .sorted_by_key(|(range, _)| range.start);
 3824                    buffer.edit(edits, None, cx);
 3825                })
 3826            }
 3827            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3828            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3829            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3830            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3831                .zip(new_selection_deltas)
 3832                .map(|(selection, delta)| Selection {
 3833                    id: selection.id,
 3834                    start: selection.start + delta,
 3835                    end: selection.end + delta,
 3836                    reversed: selection.reversed,
 3837                    goal: SelectionGoal::None,
 3838                })
 3839                .collect::<Vec<_>>();
 3840
 3841            let mut i = 0;
 3842            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3843                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3844                let start = map.buffer_snapshot.anchor_before(position);
 3845                let end = map.buffer_snapshot.anchor_after(position);
 3846                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3847                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3848                        Ordering::Less => i += 1,
 3849                        Ordering::Greater => break,
 3850                        Ordering::Equal => {
 3851                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3852                                Ordering::Less => i += 1,
 3853                                Ordering::Equal => break,
 3854                                Ordering::Greater => break,
 3855                            }
 3856                        }
 3857                    }
 3858                }
 3859                this.autoclose_regions.insert(
 3860                    i,
 3861                    AutocloseRegion {
 3862                        selection_id,
 3863                        range: start..end,
 3864                        pair,
 3865                    },
 3866                );
 3867            }
 3868
 3869            let had_active_inline_completion = this.has_active_inline_completion();
 3870            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3871                s.select(new_selections)
 3872            });
 3873
 3874            if !bracket_inserted {
 3875                if let Some(on_type_format_task) =
 3876                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3877                {
 3878                    on_type_format_task.detach_and_log_err(cx);
 3879                }
 3880            }
 3881
 3882            let editor_settings = EditorSettings::get_global(cx);
 3883            if bracket_inserted
 3884                && (editor_settings.auto_signature_help
 3885                    || editor_settings.show_signature_help_after_edits)
 3886            {
 3887                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3888            }
 3889
 3890            let trigger_in_words =
 3891                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3892            if this.hard_wrap.is_some() {
 3893                let latest: Range<Point> = this.selections.newest(cx).range();
 3894                if latest.is_empty()
 3895                    && this
 3896                        .buffer()
 3897                        .read(cx)
 3898                        .snapshot(cx)
 3899                        .line_len(MultiBufferRow(latest.start.row))
 3900                        == latest.start.column
 3901                {
 3902                    this.rewrap_impl(
 3903                        RewrapOptions {
 3904                            override_language_settings: true,
 3905                            preserve_existing_whitespace: true,
 3906                        },
 3907                        cx,
 3908                    )
 3909                }
 3910            }
 3911            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3912            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3913            this.refresh_inline_completion(true, false, window, cx);
 3914            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3915        });
 3916    }
 3917
 3918    fn find_possible_emoji_shortcode_at_position(
 3919        snapshot: &MultiBufferSnapshot,
 3920        position: Point,
 3921    ) -> Option<String> {
 3922        let mut chars = Vec::new();
 3923        let mut found_colon = false;
 3924        for char in snapshot.reversed_chars_at(position).take(100) {
 3925            // Found a possible emoji shortcode in the middle of the buffer
 3926            if found_colon {
 3927                if char.is_whitespace() {
 3928                    chars.reverse();
 3929                    return Some(chars.iter().collect());
 3930                }
 3931                // If the previous character is not a whitespace, we are in the middle of a word
 3932                // and we only want to complete the shortcode if the word is made up of other emojis
 3933                let mut containing_word = String::new();
 3934                for ch in snapshot
 3935                    .reversed_chars_at(position)
 3936                    .skip(chars.len() + 1)
 3937                    .take(100)
 3938                {
 3939                    if ch.is_whitespace() {
 3940                        break;
 3941                    }
 3942                    containing_word.push(ch);
 3943                }
 3944                let containing_word = containing_word.chars().rev().collect::<String>();
 3945                if util::word_consists_of_emojis(containing_word.as_str()) {
 3946                    chars.reverse();
 3947                    return Some(chars.iter().collect());
 3948                }
 3949            }
 3950
 3951            if char.is_whitespace() || !char.is_ascii() {
 3952                return None;
 3953            }
 3954            if char == ':' {
 3955                found_colon = true;
 3956            } else {
 3957                chars.push(char);
 3958            }
 3959        }
 3960        // Found a possible emoji shortcode at the beginning of the buffer
 3961        chars.reverse();
 3962        Some(chars.iter().collect())
 3963    }
 3964
 3965    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3966        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3967        self.transact(window, cx, |this, window, cx| {
 3968            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3969                let selections = this.selections.all::<usize>(cx);
 3970                let multi_buffer = this.buffer.read(cx);
 3971                let buffer = multi_buffer.snapshot(cx);
 3972                selections
 3973                    .iter()
 3974                    .map(|selection| {
 3975                        let start_point = selection.start.to_point(&buffer);
 3976                        let mut existing_indent =
 3977                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3978                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3979                        let start = selection.start;
 3980                        let end = selection.end;
 3981                        let selection_is_empty = start == end;
 3982                        let language_scope = buffer.language_scope_at(start);
 3983                        let (
 3984                            comment_delimiter,
 3985                            doc_delimiter,
 3986                            insert_extra_newline,
 3987                            indent_on_newline,
 3988                            indent_on_extra_newline,
 3989                        ) = if let Some(language) = &language_scope {
 3990                            let mut insert_extra_newline =
 3991                                insert_extra_newline_brackets(&buffer, start..end, language)
 3992                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3993
 3994                            // Comment extension on newline is allowed only for cursor selections
 3995                            let comment_delimiter = maybe!({
 3996                                if !selection_is_empty {
 3997                                    return None;
 3998                                }
 3999
 4000                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4001                                    return None;
 4002                                }
 4003
 4004                                let delimiters = language.line_comment_prefixes();
 4005                                let max_len_of_delimiter =
 4006                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4007                                let (snapshot, range) =
 4008                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4009
 4010                                let num_of_whitespaces = snapshot
 4011                                    .chars_for_range(range.clone())
 4012                                    .take_while(|c| c.is_whitespace())
 4013                                    .count();
 4014                                let comment_candidate = snapshot
 4015                                    .chars_for_range(range)
 4016                                    .skip(num_of_whitespaces)
 4017                                    .take(max_len_of_delimiter)
 4018                                    .collect::<String>();
 4019                                let (delimiter, trimmed_len) = delimiters
 4020                                    .iter()
 4021                                    .filter_map(|delimiter| {
 4022                                        let prefix = delimiter.trim_end();
 4023                                        if comment_candidate.starts_with(prefix) {
 4024                                            Some((delimiter, prefix.len()))
 4025                                        } else {
 4026                                            None
 4027                                        }
 4028                                    })
 4029                                    .max_by_key(|(_, len)| *len)?;
 4030
 4031                                let cursor_is_placed_after_comment_marker =
 4032                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4033                                if cursor_is_placed_after_comment_marker {
 4034                                    Some(delimiter.clone())
 4035                                } else {
 4036                                    None
 4037                                }
 4038                            });
 4039
 4040                            let mut indent_on_newline = IndentSize::spaces(0);
 4041                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4042
 4043                            let doc_delimiter = maybe!({
 4044                                if !selection_is_empty {
 4045                                    return None;
 4046                                }
 4047
 4048                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4049                                    return None;
 4050                                }
 4051
 4052                                let DocumentationConfig {
 4053                                    start: start_tag,
 4054                                    end: end_tag,
 4055                                    prefix: delimiter,
 4056                                    tab_size: len,
 4057                                } = language.documentation()?;
 4058
 4059                                let is_within_block_comment = buffer
 4060                                    .language_scope_at(start_point)
 4061                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4062                                if !is_within_block_comment {
 4063                                    return None;
 4064                                }
 4065
 4066                                let (snapshot, range) =
 4067                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4068
 4069                                let num_of_whitespaces = snapshot
 4070                                    .chars_for_range(range.clone())
 4071                                    .take_while(|c| c.is_whitespace())
 4072                                    .count();
 4073
 4074                                // 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.
 4075                                let column = start_point.column;
 4076                                let cursor_is_after_start_tag = {
 4077                                    let start_tag_len = start_tag.len();
 4078                                    let start_tag_line = snapshot
 4079                                        .chars_for_range(range.clone())
 4080                                        .skip(num_of_whitespaces)
 4081                                        .take(start_tag_len)
 4082                                        .collect::<String>();
 4083                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4084                                        num_of_whitespaces + start_tag_len <= column as usize
 4085                                    } else {
 4086                                        false
 4087                                    }
 4088                                };
 4089
 4090                                let cursor_is_after_delimiter = {
 4091                                    let delimiter_trim = delimiter.trim_end();
 4092                                    let delimiter_line = snapshot
 4093                                        .chars_for_range(range.clone())
 4094                                        .skip(num_of_whitespaces)
 4095                                        .take(delimiter_trim.len())
 4096                                        .collect::<String>();
 4097                                    if delimiter_line.starts_with(delimiter_trim) {
 4098                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4099                                    } else {
 4100                                        false
 4101                                    }
 4102                                };
 4103
 4104                                let cursor_is_before_end_tag_if_exists = {
 4105                                    let mut char_position = 0u32;
 4106                                    let mut end_tag_offset = None;
 4107
 4108                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4109                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4110                                            let chars_before_match =
 4111                                                chunk[..byte_pos].chars().count() as u32;
 4112                                            end_tag_offset =
 4113                                                Some(char_position + chars_before_match);
 4114                                            break 'outer;
 4115                                        }
 4116                                        char_position += chunk.chars().count() as u32;
 4117                                    }
 4118
 4119                                    if let Some(end_tag_offset) = end_tag_offset {
 4120                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4121                                        if cursor_is_after_start_tag {
 4122                                            if cursor_is_before_end_tag {
 4123                                                insert_extra_newline = true;
 4124                                            }
 4125                                            let cursor_is_at_start_of_end_tag =
 4126                                                column == end_tag_offset;
 4127                                            if cursor_is_at_start_of_end_tag {
 4128                                                indent_on_extra_newline.len = (*len).into();
 4129                                            }
 4130                                        }
 4131                                        cursor_is_before_end_tag
 4132                                    } else {
 4133                                        true
 4134                                    }
 4135                                };
 4136
 4137                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4138                                    && cursor_is_before_end_tag_if_exists
 4139                                {
 4140                                    if cursor_is_after_start_tag {
 4141                                        indent_on_newline.len = (*len).into();
 4142                                    }
 4143                                    Some(delimiter.clone())
 4144                                } else {
 4145                                    None
 4146                                }
 4147                            });
 4148
 4149                            (
 4150                                comment_delimiter,
 4151                                doc_delimiter,
 4152                                insert_extra_newline,
 4153                                indent_on_newline,
 4154                                indent_on_extra_newline,
 4155                            )
 4156                        } else {
 4157                            (
 4158                                None,
 4159                                None,
 4160                                false,
 4161                                IndentSize::default(),
 4162                                IndentSize::default(),
 4163                            )
 4164                        };
 4165
 4166                        let prevent_auto_indent = doc_delimiter.is_some();
 4167                        let delimiter = comment_delimiter.or(doc_delimiter);
 4168
 4169                        let capacity_for_delimiter =
 4170                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4171                        let mut new_text = String::with_capacity(
 4172                            1 + capacity_for_delimiter
 4173                                + existing_indent.len as usize
 4174                                + indent_on_newline.len as usize
 4175                                + indent_on_extra_newline.len as usize,
 4176                        );
 4177                        new_text.push('\n');
 4178                        new_text.extend(existing_indent.chars());
 4179                        new_text.extend(indent_on_newline.chars());
 4180
 4181                        if let Some(delimiter) = &delimiter {
 4182                            new_text.push_str(delimiter);
 4183                        }
 4184
 4185                        if insert_extra_newline {
 4186                            new_text.push('\n');
 4187                            new_text.extend(existing_indent.chars());
 4188                            new_text.extend(indent_on_extra_newline.chars());
 4189                        }
 4190
 4191                        let anchor = buffer.anchor_after(end);
 4192                        let new_selection = selection.map(|_| anchor);
 4193                        (
 4194                            ((start..end, new_text), prevent_auto_indent),
 4195                            (insert_extra_newline, new_selection),
 4196                        )
 4197                    })
 4198                    .unzip()
 4199            };
 4200
 4201            let mut auto_indent_edits = Vec::new();
 4202            let mut edits = Vec::new();
 4203            for (edit, prevent_auto_indent) in edits_with_flags {
 4204                if prevent_auto_indent {
 4205                    edits.push(edit);
 4206                } else {
 4207                    auto_indent_edits.push(edit);
 4208                }
 4209            }
 4210            if !edits.is_empty() {
 4211                this.edit(edits, cx);
 4212            }
 4213            if !auto_indent_edits.is_empty() {
 4214                this.edit_with_autoindent(auto_indent_edits, cx);
 4215            }
 4216
 4217            let buffer = this.buffer.read(cx).snapshot(cx);
 4218            let new_selections = selection_info
 4219                .into_iter()
 4220                .map(|(extra_newline_inserted, new_selection)| {
 4221                    let mut cursor = new_selection.end.to_point(&buffer);
 4222                    if extra_newline_inserted {
 4223                        cursor.row -= 1;
 4224                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4225                    }
 4226                    new_selection.map(|_| cursor)
 4227                })
 4228                .collect();
 4229
 4230            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4231                s.select(new_selections)
 4232            });
 4233            this.refresh_inline_completion(true, false, window, cx);
 4234        });
 4235    }
 4236
 4237    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4238        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4239
 4240        let buffer = self.buffer.read(cx);
 4241        let snapshot = buffer.snapshot(cx);
 4242
 4243        let mut edits = Vec::new();
 4244        let mut rows = Vec::new();
 4245
 4246        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4247            let cursor = selection.head();
 4248            let row = cursor.row;
 4249
 4250            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4251
 4252            let newline = "\n".to_string();
 4253            edits.push((start_of_line..start_of_line, newline));
 4254
 4255            rows.push(row + rows_inserted as u32);
 4256        }
 4257
 4258        self.transact(window, cx, |editor, window, cx| {
 4259            editor.edit(edits, cx);
 4260
 4261            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4262                let mut index = 0;
 4263                s.move_cursors_with(|map, _, _| {
 4264                    let row = rows[index];
 4265                    index += 1;
 4266
 4267                    let point = Point::new(row, 0);
 4268                    let boundary = map.next_line_boundary(point).1;
 4269                    let clipped = map.clip_point(boundary, Bias::Left);
 4270
 4271                    (clipped, SelectionGoal::None)
 4272                });
 4273            });
 4274
 4275            let mut indent_edits = Vec::new();
 4276            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4277            for row in rows {
 4278                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4279                for (row, indent) in indents {
 4280                    if indent.len == 0 {
 4281                        continue;
 4282                    }
 4283
 4284                    let text = match indent.kind {
 4285                        IndentKind::Space => " ".repeat(indent.len as usize),
 4286                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4287                    };
 4288                    let point = Point::new(row.0, 0);
 4289                    indent_edits.push((point..point, text));
 4290                }
 4291            }
 4292            editor.edit(indent_edits, cx);
 4293        });
 4294    }
 4295
 4296    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4297        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4298
 4299        let buffer = self.buffer.read(cx);
 4300        let snapshot = buffer.snapshot(cx);
 4301
 4302        let mut edits = Vec::new();
 4303        let mut rows = Vec::new();
 4304        let mut rows_inserted = 0;
 4305
 4306        for selection in self.selections.all_adjusted(cx) {
 4307            let cursor = selection.head();
 4308            let row = cursor.row;
 4309
 4310            let point = Point::new(row + 1, 0);
 4311            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4312
 4313            let newline = "\n".to_string();
 4314            edits.push((start_of_line..start_of_line, newline));
 4315
 4316            rows_inserted += 1;
 4317            rows.push(row + rows_inserted);
 4318        }
 4319
 4320        self.transact(window, cx, |editor, window, cx| {
 4321            editor.edit(edits, cx);
 4322
 4323            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4324                let mut index = 0;
 4325                s.move_cursors_with(|map, _, _| {
 4326                    let row = rows[index];
 4327                    index += 1;
 4328
 4329                    let point = Point::new(row, 0);
 4330                    let boundary = map.next_line_boundary(point).1;
 4331                    let clipped = map.clip_point(boundary, Bias::Left);
 4332
 4333                    (clipped, SelectionGoal::None)
 4334                });
 4335            });
 4336
 4337            let mut indent_edits = Vec::new();
 4338            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4339            for row in rows {
 4340                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4341                for (row, indent) in indents {
 4342                    if indent.len == 0 {
 4343                        continue;
 4344                    }
 4345
 4346                    let text = match indent.kind {
 4347                        IndentKind::Space => " ".repeat(indent.len as usize),
 4348                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4349                    };
 4350                    let point = Point::new(row.0, 0);
 4351                    indent_edits.push((point..point, text));
 4352                }
 4353            }
 4354            editor.edit(indent_edits, cx);
 4355        });
 4356    }
 4357
 4358    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4359        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4360            original_indent_columns: Vec::new(),
 4361        });
 4362        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4363    }
 4364
 4365    fn insert_with_autoindent_mode(
 4366        &mut self,
 4367        text: &str,
 4368        autoindent_mode: Option<AutoindentMode>,
 4369        window: &mut Window,
 4370        cx: &mut Context<Self>,
 4371    ) {
 4372        if self.read_only(cx) {
 4373            return;
 4374        }
 4375
 4376        let text: Arc<str> = text.into();
 4377        self.transact(window, cx, |this, window, cx| {
 4378            let old_selections = this.selections.all_adjusted(cx);
 4379            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4380                let anchors = {
 4381                    let snapshot = buffer.read(cx);
 4382                    old_selections
 4383                        .iter()
 4384                        .map(|s| {
 4385                            let anchor = snapshot.anchor_after(s.head());
 4386                            s.map(|_| anchor)
 4387                        })
 4388                        .collect::<Vec<_>>()
 4389                };
 4390                buffer.edit(
 4391                    old_selections
 4392                        .iter()
 4393                        .map(|s| (s.start..s.end, text.clone())),
 4394                    autoindent_mode,
 4395                    cx,
 4396                );
 4397                anchors
 4398            });
 4399
 4400            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4401                s.select_anchors(selection_anchors);
 4402            });
 4403
 4404            cx.notify();
 4405        });
 4406    }
 4407
 4408    fn trigger_completion_on_input(
 4409        &mut self,
 4410        text: &str,
 4411        trigger_in_words: bool,
 4412        window: &mut Window,
 4413        cx: &mut Context<Self>,
 4414    ) {
 4415        let ignore_completion_provider = self
 4416            .context_menu
 4417            .borrow()
 4418            .as_ref()
 4419            .map(|menu| match menu {
 4420                CodeContextMenu::Completions(completions_menu) => {
 4421                    completions_menu.ignore_completion_provider
 4422                }
 4423                CodeContextMenu::CodeActions(_) => false,
 4424            })
 4425            .unwrap_or(false);
 4426
 4427        if ignore_completion_provider {
 4428            self.show_word_completions(&ShowWordCompletions, window, cx);
 4429        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4430            self.show_completions(
 4431                &ShowCompletions {
 4432                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4433                },
 4434                window,
 4435                cx,
 4436            );
 4437        } else {
 4438            self.hide_context_menu(window, cx);
 4439        }
 4440    }
 4441
 4442    fn is_completion_trigger(
 4443        &self,
 4444        text: &str,
 4445        trigger_in_words: bool,
 4446        cx: &mut Context<Self>,
 4447    ) -> bool {
 4448        let position = self.selections.newest_anchor().head();
 4449        let multibuffer = self.buffer.read(cx);
 4450        let Some(buffer) = position
 4451            .buffer_id
 4452            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4453        else {
 4454            return false;
 4455        };
 4456
 4457        if let Some(completion_provider) = &self.completion_provider {
 4458            completion_provider.is_completion_trigger(
 4459                &buffer,
 4460                position.text_anchor,
 4461                text,
 4462                trigger_in_words,
 4463                cx,
 4464            )
 4465        } else {
 4466            false
 4467        }
 4468    }
 4469
 4470    /// If any empty selections is touching the start of its innermost containing autoclose
 4471    /// region, expand it to select the brackets.
 4472    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4473        let selections = self.selections.all::<usize>(cx);
 4474        let buffer = self.buffer.read(cx).read(cx);
 4475        let new_selections = self
 4476            .selections_with_autoclose_regions(selections, &buffer)
 4477            .map(|(mut selection, region)| {
 4478                if !selection.is_empty() {
 4479                    return selection;
 4480                }
 4481
 4482                if let Some(region) = region {
 4483                    let mut range = region.range.to_offset(&buffer);
 4484                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4485                        range.start -= region.pair.start.len();
 4486                        if buffer.contains_str_at(range.start, &region.pair.start)
 4487                            && buffer.contains_str_at(range.end, &region.pair.end)
 4488                        {
 4489                            range.end += region.pair.end.len();
 4490                            selection.start = range.start;
 4491                            selection.end = range.end;
 4492
 4493                            return selection;
 4494                        }
 4495                    }
 4496                }
 4497
 4498                let always_treat_brackets_as_autoclosed = buffer
 4499                    .language_settings_at(selection.start, cx)
 4500                    .always_treat_brackets_as_autoclosed;
 4501
 4502                if !always_treat_brackets_as_autoclosed {
 4503                    return selection;
 4504                }
 4505
 4506                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4507                    for (pair, enabled) in scope.brackets() {
 4508                        if !enabled || !pair.close {
 4509                            continue;
 4510                        }
 4511
 4512                        if buffer.contains_str_at(selection.start, &pair.end) {
 4513                            let pair_start_len = pair.start.len();
 4514                            if buffer.contains_str_at(
 4515                                selection.start.saturating_sub(pair_start_len),
 4516                                &pair.start,
 4517                            ) {
 4518                                selection.start -= pair_start_len;
 4519                                selection.end += pair.end.len();
 4520
 4521                                return selection;
 4522                            }
 4523                        }
 4524                    }
 4525                }
 4526
 4527                selection
 4528            })
 4529            .collect();
 4530
 4531        drop(buffer);
 4532        self.change_selections(None, window, cx, |selections| {
 4533            selections.select(new_selections)
 4534        });
 4535    }
 4536
 4537    /// Iterate the given selections, and for each one, find the smallest surrounding
 4538    /// autoclose region. This uses the ordering of the selections and the autoclose
 4539    /// regions to avoid repeated comparisons.
 4540    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4541        &'a self,
 4542        selections: impl IntoIterator<Item = Selection<D>>,
 4543        buffer: &'a MultiBufferSnapshot,
 4544    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4545        let mut i = 0;
 4546        let mut regions = self.autoclose_regions.as_slice();
 4547        selections.into_iter().map(move |selection| {
 4548            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4549
 4550            let mut enclosing = None;
 4551            while let Some(pair_state) = regions.get(i) {
 4552                if pair_state.range.end.to_offset(buffer) < range.start {
 4553                    regions = &regions[i + 1..];
 4554                    i = 0;
 4555                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4556                    break;
 4557                } else {
 4558                    if pair_state.selection_id == selection.id {
 4559                        enclosing = Some(pair_state);
 4560                    }
 4561                    i += 1;
 4562                }
 4563            }
 4564
 4565            (selection, enclosing)
 4566        })
 4567    }
 4568
 4569    /// Remove any autoclose regions that no longer contain their selection.
 4570    fn invalidate_autoclose_regions(
 4571        &mut self,
 4572        mut selections: &[Selection<Anchor>],
 4573        buffer: &MultiBufferSnapshot,
 4574    ) {
 4575        self.autoclose_regions.retain(|state| {
 4576            let mut i = 0;
 4577            while let Some(selection) = selections.get(i) {
 4578                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4579                    selections = &selections[1..];
 4580                    continue;
 4581                }
 4582                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4583                    break;
 4584                }
 4585                if selection.id == state.selection_id {
 4586                    return true;
 4587                } else {
 4588                    i += 1;
 4589                }
 4590            }
 4591            false
 4592        });
 4593    }
 4594
 4595    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4596        let offset = position.to_offset(buffer);
 4597        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4598        if offset > word_range.start && kind == Some(CharKind::Word) {
 4599            Some(
 4600                buffer
 4601                    .text_for_range(word_range.start..offset)
 4602                    .collect::<String>(),
 4603            )
 4604        } else {
 4605            None
 4606        }
 4607    }
 4608
 4609    pub fn toggle_inline_values(
 4610        &mut self,
 4611        _: &ToggleInlineValues,
 4612        _: &mut Window,
 4613        cx: &mut Context<Self>,
 4614    ) {
 4615        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4616
 4617        self.refresh_inline_values(cx);
 4618    }
 4619
 4620    pub fn toggle_inlay_hints(
 4621        &mut self,
 4622        _: &ToggleInlayHints,
 4623        _: &mut Window,
 4624        cx: &mut Context<Self>,
 4625    ) {
 4626        self.refresh_inlay_hints(
 4627            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4628            cx,
 4629        );
 4630    }
 4631
 4632    pub fn inlay_hints_enabled(&self) -> bool {
 4633        self.inlay_hint_cache.enabled
 4634    }
 4635
 4636    pub fn inline_values_enabled(&self) -> bool {
 4637        self.inline_value_cache.enabled
 4638    }
 4639
 4640    #[cfg(any(test, feature = "test-support"))]
 4641    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4642        self.display_map
 4643            .read(cx)
 4644            .current_inlays()
 4645            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4646            .cloned()
 4647            .collect()
 4648    }
 4649
 4650    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4651        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4652            return;
 4653        }
 4654
 4655        let reason_description = reason.description();
 4656        let ignore_debounce = matches!(
 4657            reason,
 4658            InlayHintRefreshReason::SettingsChange(_)
 4659                | InlayHintRefreshReason::Toggle(_)
 4660                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4661                | InlayHintRefreshReason::ModifiersChanged(_)
 4662        );
 4663        let (invalidate_cache, required_languages) = match reason {
 4664            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4665                match self.inlay_hint_cache.modifiers_override(enabled) {
 4666                    Some(enabled) => {
 4667                        if enabled {
 4668                            (InvalidationStrategy::RefreshRequested, None)
 4669                        } else {
 4670                            self.splice_inlays(
 4671                                &self
 4672                                    .visible_inlay_hints(cx)
 4673                                    .iter()
 4674                                    .map(|inlay| inlay.id)
 4675                                    .collect::<Vec<InlayId>>(),
 4676                                Vec::new(),
 4677                                cx,
 4678                            );
 4679                            return;
 4680                        }
 4681                    }
 4682                    None => return,
 4683                }
 4684            }
 4685            InlayHintRefreshReason::Toggle(enabled) => {
 4686                if self.inlay_hint_cache.toggle(enabled) {
 4687                    if enabled {
 4688                        (InvalidationStrategy::RefreshRequested, None)
 4689                    } else {
 4690                        self.splice_inlays(
 4691                            &self
 4692                                .visible_inlay_hints(cx)
 4693                                .iter()
 4694                                .map(|inlay| inlay.id)
 4695                                .collect::<Vec<InlayId>>(),
 4696                            Vec::new(),
 4697                            cx,
 4698                        );
 4699                        return;
 4700                    }
 4701                } else {
 4702                    return;
 4703                }
 4704            }
 4705            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4706                match self.inlay_hint_cache.update_settings(
 4707                    &self.buffer,
 4708                    new_settings,
 4709                    self.visible_inlay_hints(cx),
 4710                    cx,
 4711                ) {
 4712                    ControlFlow::Break(Some(InlaySplice {
 4713                        to_remove,
 4714                        to_insert,
 4715                    })) => {
 4716                        self.splice_inlays(&to_remove, to_insert, cx);
 4717                        return;
 4718                    }
 4719                    ControlFlow::Break(None) => return,
 4720                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4721                }
 4722            }
 4723            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4724                if let Some(InlaySplice {
 4725                    to_remove,
 4726                    to_insert,
 4727                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4728                {
 4729                    self.splice_inlays(&to_remove, to_insert, cx);
 4730                }
 4731                self.display_map.update(cx, |display_map, _| {
 4732                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4733                });
 4734                return;
 4735            }
 4736            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4737            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4738                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4739            }
 4740            InlayHintRefreshReason::RefreshRequested => {
 4741                (InvalidationStrategy::RefreshRequested, None)
 4742            }
 4743        };
 4744
 4745        if let Some(InlaySplice {
 4746            to_remove,
 4747            to_insert,
 4748        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4749            reason_description,
 4750            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4751            invalidate_cache,
 4752            ignore_debounce,
 4753            cx,
 4754        ) {
 4755            self.splice_inlays(&to_remove, to_insert, cx);
 4756        }
 4757    }
 4758
 4759    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4760        self.display_map
 4761            .read(cx)
 4762            .current_inlays()
 4763            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4764            .cloned()
 4765            .collect()
 4766    }
 4767
 4768    pub fn excerpts_for_inlay_hints_query(
 4769        &self,
 4770        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4771        cx: &mut Context<Editor>,
 4772    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4773        let Some(project) = self.project.as_ref() else {
 4774            return HashMap::default();
 4775        };
 4776        let project = project.read(cx);
 4777        let multi_buffer = self.buffer().read(cx);
 4778        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4779        let multi_buffer_visible_start = self
 4780            .scroll_manager
 4781            .anchor()
 4782            .anchor
 4783            .to_point(&multi_buffer_snapshot);
 4784        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4785            multi_buffer_visible_start
 4786                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4787            Bias::Left,
 4788        );
 4789        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4790        multi_buffer_snapshot
 4791            .range_to_buffer_ranges(multi_buffer_visible_range)
 4792            .into_iter()
 4793            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4794            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4795                let buffer_file = project::File::from_dyn(buffer.file())?;
 4796                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4797                let worktree_entry = buffer_worktree
 4798                    .read(cx)
 4799                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4800                if worktree_entry.is_ignored {
 4801                    return None;
 4802                }
 4803
 4804                let language = buffer.language()?;
 4805                if let Some(restrict_to_languages) = restrict_to_languages {
 4806                    if !restrict_to_languages.contains(language) {
 4807                        return None;
 4808                    }
 4809                }
 4810                Some((
 4811                    excerpt_id,
 4812                    (
 4813                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4814                        buffer.version().clone(),
 4815                        excerpt_visible_range,
 4816                    ),
 4817                ))
 4818            })
 4819            .collect()
 4820    }
 4821
 4822    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4823        TextLayoutDetails {
 4824            text_system: window.text_system().clone(),
 4825            editor_style: self.style.clone().unwrap(),
 4826            rem_size: window.rem_size(),
 4827            scroll_anchor: self.scroll_manager.anchor(),
 4828            visible_rows: self.visible_line_count(),
 4829            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4830        }
 4831    }
 4832
 4833    pub fn splice_inlays(
 4834        &self,
 4835        to_remove: &[InlayId],
 4836        to_insert: Vec<Inlay>,
 4837        cx: &mut Context<Self>,
 4838    ) {
 4839        self.display_map.update(cx, |display_map, cx| {
 4840            display_map.splice_inlays(to_remove, to_insert, cx)
 4841        });
 4842        cx.notify();
 4843    }
 4844
 4845    fn trigger_on_type_formatting(
 4846        &self,
 4847        input: String,
 4848        window: &mut Window,
 4849        cx: &mut Context<Self>,
 4850    ) -> Option<Task<Result<()>>> {
 4851        if input.len() != 1 {
 4852            return None;
 4853        }
 4854
 4855        let project = self.project.as_ref()?;
 4856        let position = self.selections.newest_anchor().head();
 4857        let (buffer, buffer_position) = self
 4858            .buffer
 4859            .read(cx)
 4860            .text_anchor_for_position(position, cx)?;
 4861
 4862        let settings = language_settings::language_settings(
 4863            buffer
 4864                .read(cx)
 4865                .language_at(buffer_position)
 4866                .map(|l| l.name()),
 4867            buffer.read(cx).file(),
 4868            cx,
 4869        );
 4870        if !settings.use_on_type_format {
 4871            return None;
 4872        }
 4873
 4874        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4875        // hence we do LSP request & edit on host side only — add formats to host's history.
 4876        let push_to_lsp_host_history = true;
 4877        // If this is not the host, append its history with new edits.
 4878        let push_to_client_history = project.read(cx).is_via_collab();
 4879
 4880        let on_type_formatting = project.update(cx, |project, cx| {
 4881            project.on_type_format(
 4882                buffer.clone(),
 4883                buffer_position,
 4884                input,
 4885                push_to_lsp_host_history,
 4886                cx,
 4887            )
 4888        });
 4889        Some(cx.spawn_in(window, async move |editor, cx| {
 4890            if let Some(transaction) = on_type_formatting.await? {
 4891                if push_to_client_history {
 4892                    buffer
 4893                        .update(cx, |buffer, _| {
 4894                            buffer.push_transaction(transaction, Instant::now());
 4895                            buffer.finalize_last_transaction();
 4896                        })
 4897                        .ok();
 4898                }
 4899                editor.update(cx, |editor, cx| {
 4900                    editor.refresh_document_highlights(cx);
 4901                })?;
 4902            }
 4903            Ok(())
 4904        }))
 4905    }
 4906
 4907    pub fn show_word_completions(
 4908        &mut self,
 4909        _: &ShowWordCompletions,
 4910        window: &mut Window,
 4911        cx: &mut Context<Self>,
 4912    ) {
 4913        self.open_completions_menu(true, None, window, cx);
 4914    }
 4915
 4916    pub fn show_completions(
 4917        &mut self,
 4918        options: &ShowCompletions,
 4919        window: &mut Window,
 4920        cx: &mut Context<Self>,
 4921    ) {
 4922        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4923    }
 4924
 4925    fn open_completions_menu(
 4926        &mut self,
 4927        ignore_completion_provider: bool,
 4928        trigger: Option<&str>,
 4929        window: &mut Window,
 4930        cx: &mut Context<Self>,
 4931    ) {
 4932        if self.pending_rename.is_some() {
 4933            return;
 4934        }
 4935        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4936            return;
 4937        }
 4938
 4939        let position = self.selections.newest_anchor().head();
 4940        if position.diff_base_anchor.is_some() {
 4941            return;
 4942        }
 4943        let (buffer, buffer_position) =
 4944            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4945                output
 4946            } else {
 4947                return;
 4948            };
 4949        let buffer_snapshot = buffer.read(cx).snapshot();
 4950        let show_completion_documentation = buffer_snapshot
 4951            .settings_at(buffer_position, cx)
 4952            .show_completion_documentation;
 4953
 4954        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4955
 4956        let trigger_kind = match trigger {
 4957            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4958                CompletionTriggerKind::TRIGGER_CHARACTER
 4959            }
 4960            _ => CompletionTriggerKind::INVOKED,
 4961        };
 4962        let completion_context = CompletionContext {
 4963            trigger_character: trigger.and_then(|trigger| {
 4964                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4965                    Some(String::from(trigger))
 4966                } else {
 4967                    None
 4968                }
 4969            }),
 4970            trigger_kind,
 4971        };
 4972
 4973        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4974        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4975            let word_to_exclude = buffer_snapshot
 4976                .text_for_range(old_range.clone())
 4977                .collect::<String>();
 4978            (
 4979                buffer_snapshot.anchor_before(old_range.start)
 4980                    ..buffer_snapshot.anchor_after(old_range.end),
 4981                Some(word_to_exclude),
 4982            )
 4983        } else {
 4984            (buffer_position..buffer_position, None)
 4985        };
 4986
 4987        let completion_settings = language_settings(
 4988            buffer_snapshot
 4989                .language_at(buffer_position)
 4990                .map(|language| language.name()),
 4991            buffer_snapshot.file(),
 4992            cx,
 4993        )
 4994        .completions;
 4995
 4996        // The document can be large, so stay in reasonable bounds when searching for words,
 4997        // otherwise completion pop-up might be slow to appear.
 4998        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4999        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5000        let min_word_search = buffer_snapshot.clip_point(
 5001            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5002            Bias::Left,
 5003        );
 5004        let max_word_search = buffer_snapshot.clip_point(
 5005            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5006            Bias::Right,
 5007        );
 5008        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5009            ..buffer_snapshot.point_to_offset(max_word_search);
 5010
 5011        let provider = if ignore_completion_provider {
 5012            None
 5013        } else {
 5014            self.completion_provider.clone()
 5015        };
 5016        let skip_digits = query
 5017            .as_ref()
 5018            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5019
 5020        let (mut words, provided_completions) = match &provider {
 5021            Some(provider) => {
 5022                let completions = provider.completions(
 5023                    position.excerpt_id,
 5024                    &buffer,
 5025                    buffer_position,
 5026                    completion_context,
 5027                    window,
 5028                    cx,
 5029                );
 5030
 5031                let words = match completion_settings.words {
 5032                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5033                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5034                        .background_spawn(async move {
 5035                            buffer_snapshot.words_in_range(WordsQuery {
 5036                                fuzzy_contents: None,
 5037                                range: word_search_range,
 5038                                skip_digits,
 5039                            })
 5040                        }),
 5041                };
 5042
 5043                (words, completions)
 5044            }
 5045            None => (
 5046                cx.background_spawn(async move {
 5047                    buffer_snapshot.words_in_range(WordsQuery {
 5048                        fuzzy_contents: None,
 5049                        range: word_search_range,
 5050                        skip_digits,
 5051                    })
 5052                }),
 5053                Task::ready(Ok(None)),
 5054            ),
 5055        };
 5056
 5057        let sort_completions = provider
 5058            .as_ref()
 5059            .map_or(false, |provider| provider.sort_completions());
 5060
 5061        let filter_completions = provider
 5062            .as_ref()
 5063            .map_or(true, |provider| provider.filter_completions());
 5064
 5065        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5066
 5067        let id = post_inc(&mut self.next_completion_id);
 5068        let task = cx.spawn_in(window, async move |editor, cx| {
 5069            async move {
 5070                editor.update(cx, |this, _| {
 5071                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5072                })?;
 5073
 5074                let mut completions = Vec::new();
 5075                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5076                    completions.extend(provided_completions);
 5077                    if completion_settings.words == WordsCompletionMode::Fallback {
 5078                        words = Task::ready(BTreeMap::default());
 5079                    }
 5080                }
 5081
 5082                let mut words = words.await;
 5083                if let Some(word_to_exclude) = &word_to_exclude {
 5084                    words.remove(word_to_exclude);
 5085                }
 5086                for lsp_completion in &completions {
 5087                    words.remove(&lsp_completion.new_text);
 5088                }
 5089                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5090                    replace_range: old_range.clone(),
 5091                    new_text: word.clone(),
 5092                    label: CodeLabel::plain(word, None),
 5093                    icon_path: None,
 5094                    documentation: None,
 5095                    source: CompletionSource::BufferWord {
 5096                        word_range,
 5097                        resolved: false,
 5098                    },
 5099                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5100                    confirm: None,
 5101                }));
 5102
 5103                let menu = if completions.is_empty() {
 5104                    None
 5105                } else {
 5106                    let mut menu = CompletionsMenu::new(
 5107                        id,
 5108                        sort_completions,
 5109                        show_completion_documentation,
 5110                        ignore_completion_provider,
 5111                        position,
 5112                        buffer.clone(),
 5113                        completions.into(),
 5114                        snippet_sort_order,
 5115                    );
 5116
 5117                    menu.filter(
 5118                        if filter_completions {
 5119                            query.as_deref()
 5120                        } else {
 5121                            None
 5122                        },
 5123                        provider,
 5124                        editor.clone(),
 5125                        cx,
 5126                    )
 5127                    .await;
 5128
 5129                    menu.visible().then_some(menu)
 5130                };
 5131
 5132                editor.update_in(cx, |editor, window, cx| {
 5133                    match editor.context_menu.borrow().as_ref() {
 5134                        None => {}
 5135                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5136                            if prev_menu.id > id {
 5137                                return;
 5138                            }
 5139                        }
 5140                        _ => return,
 5141                    }
 5142
 5143                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5144                        let mut menu = menu.unwrap();
 5145                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5146                        crate::hover_popover::hide_hover(editor, cx);
 5147                        *editor.context_menu.borrow_mut() =
 5148                            Some(CodeContextMenu::Completions(menu));
 5149
 5150                        if editor.show_edit_predictions_in_menu() {
 5151                            editor.update_visible_inline_completion(window, cx);
 5152                        } else {
 5153                            editor.discard_inline_completion(false, cx);
 5154                        }
 5155
 5156                        cx.notify();
 5157                    } else if editor.completion_tasks.len() <= 1 {
 5158                        // If there are no more completion tasks and the last menu was
 5159                        // empty, we should hide it.
 5160                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5161                        // If it was already hidden and we don't show inline
 5162                        // completions in the menu, we should also show the
 5163                        // inline-completion when available.
 5164                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5165                            editor.update_visible_inline_completion(window, cx);
 5166                        }
 5167                    }
 5168                })?;
 5169
 5170                anyhow::Ok(())
 5171            }
 5172            .log_err()
 5173            .await
 5174        });
 5175
 5176        self.completion_tasks.push((id, task));
 5177    }
 5178
 5179    #[cfg(feature = "test-support")]
 5180    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5181        let menu = self.context_menu.borrow();
 5182        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5183            let completions = menu.completions.borrow();
 5184            Some(completions.to_vec())
 5185        } else {
 5186            None
 5187        }
 5188    }
 5189
 5190    pub fn confirm_completion(
 5191        &mut self,
 5192        action: &ConfirmCompletion,
 5193        window: &mut Window,
 5194        cx: &mut Context<Self>,
 5195    ) -> Option<Task<Result<()>>> {
 5196        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5197        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5198    }
 5199
 5200    pub fn confirm_completion_insert(
 5201        &mut self,
 5202        _: &ConfirmCompletionInsert,
 5203        window: &mut Window,
 5204        cx: &mut Context<Self>,
 5205    ) -> Option<Task<Result<()>>> {
 5206        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5207        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5208    }
 5209
 5210    pub fn confirm_completion_replace(
 5211        &mut self,
 5212        _: &ConfirmCompletionReplace,
 5213        window: &mut Window,
 5214        cx: &mut Context<Self>,
 5215    ) -> Option<Task<Result<()>>> {
 5216        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5217        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5218    }
 5219
 5220    pub fn compose_completion(
 5221        &mut self,
 5222        action: &ComposeCompletion,
 5223        window: &mut Window,
 5224        cx: &mut Context<Self>,
 5225    ) -> Option<Task<Result<()>>> {
 5226        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5227        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5228    }
 5229
 5230    fn do_completion(
 5231        &mut self,
 5232        item_ix: Option<usize>,
 5233        intent: CompletionIntent,
 5234        window: &mut Window,
 5235        cx: &mut Context<Editor>,
 5236    ) -> Option<Task<Result<()>>> {
 5237        use language::ToOffset as _;
 5238
 5239        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5240        else {
 5241            return None;
 5242        };
 5243
 5244        let candidate_id = {
 5245            let entries = completions_menu.entries.borrow();
 5246            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5247            if self.show_edit_predictions_in_menu() {
 5248                self.discard_inline_completion(true, cx);
 5249            }
 5250            mat.candidate_id
 5251        };
 5252
 5253        let buffer_handle = completions_menu.buffer;
 5254        let completion = completions_menu
 5255            .completions
 5256            .borrow()
 5257            .get(candidate_id)?
 5258            .clone();
 5259        cx.stop_propagation();
 5260
 5261        let snapshot = self.buffer.read(cx).snapshot(cx);
 5262        let newest_anchor = self.selections.newest_anchor();
 5263
 5264        let snippet;
 5265        let new_text;
 5266        if completion.is_snippet() {
 5267            let mut snippet_source = completion.new_text.clone();
 5268            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5269                if scope.prefers_label_for_snippet_in_completion() {
 5270                    if let Some(label) = completion.label() {
 5271                        if matches!(
 5272                            completion.kind(),
 5273                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5274                        ) {
 5275                            snippet_source = label;
 5276                        }
 5277                    }
 5278                }
 5279            }
 5280            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5281            new_text = snippet.as_ref().unwrap().text.clone();
 5282        } else {
 5283            snippet = None;
 5284            new_text = completion.new_text.clone();
 5285        };
 5286
 5287        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5288        let buffer = buffer_handle.read(cx);
 5289        let replace_range_multibuffer = {
 5290            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5291            let multibuffer_anchor = snapshot
 5292                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5293                .unwrap()
 5294                ..snapshot
 5295                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5296                    .unwrap();
 5297            multibuffer_anchor.start.to_offset(&snapshot)
 5298                ..multibuffer_anchor.end.to_offset(&snapshot)
 5299        };
 5300        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5301            return None;
 5302        }
 5303
 5304        let old_text = buffer
 5305            .text_for_range(replace_range.clone())
 5306            .collect::<String>();
 5307        let lookbehind = newest_anchor
 5308            .start
 5309            .text_anchor
 5310            .to_offset(buffer)
 5311            .saturating_sub(replace_range.start);
 5312        let lookahead = replace_range
 5313            .end
 5314            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5315        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5316        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5317
 5318        let selections = self.selections.all::<usize>(cx);
 5319        let mut ranges = Vec::new();
 5320        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5321
 5322        for selection in &selections {
 5323            let range = if selection.id == newest_anchor.id {
 5324                replace_range_multibuffer.clone()
 5325            } else {
 5326                let mut range = selection.range();
 5327
 5328                // if prefix is present, don't duplicate it
 5329                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5330                    range.start = range.start.saturating_sub(lookbehind);
 5331
 5332                    // if suffix is also present, mimic the newest cursor and replace it
 5333                    if selection.id != newest_anchor.id
 5334                        && snapshot.contains_str_at(range.end, suffix)
 5335                    {
 5336                        range.end += lookahead;
 5337                    }
 5338                }
 5339                range
 5340            };
 5341
 5342            ranges.push(range.clone());
 5343
 5344            if !self.linked_edit_ranges.is_empty() {
 5345                let start_anchor = snapshot.anchor_before(range.start);
 5346                let end_anchor = snapshot.anchor_after(range.end);
 5347                if let Some(ranges) = self
 5348                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5349                {
 5350                    for (buffer, edits) in ranges {
 5351                        linked_edits
 5352                            .entry(buffer.clone())
 5353                            .or_default()
 5354                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5355                    }
 5356                }
 5357            }
 5358        }
 5359
 5360        cx.emit(EditorEvent::InputHandled {
 5361            utf16_range_to_replace: None,
 5362            text: new_text.clone().into(),
 5363        });
 5364
 5365        self.transact(window, cx, |this, window, cx| {
 5366            if let Some(mut snippet) = snippet {
 5367                snippet.text = new_text.to_string();
 5368                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5369            } else {
 5370                this.buffer.update(cx, |buffer, cx| {
 5371                    let auto_indent = match completion.insert_text_mode {
 5372                        Some(InsertTextMode::AS_IS) => None,
 5373                        _ => this.autoindent_mode.clone(),
 5374                    };
 5375                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5376                    buffer.edit(edits, auto_indent, cx);
 5377                });
 5378            }
 5379            for (buffer, edits) in linked_edits {
 5380                buffer.update(cx, |buffer, cx| {
 5381                    let snapshot = buffer.snapshot();
 5382                    let edits = edits
 5383                        .into_iter()
 5384                        .map(|(range, text)| {
 5385                            use text::ToPoint as TP;
 5386                            let end_point = TP::to_point(&range.end, &snapshot);
 5387                            let start_point = TP::to_point(&range.start, &snapshot);
 5388                            (start_point..end_point, text)
 5389                        })
 5390                        .sorted_by_key(|(range, _)| range.start);
 5391                    buffer.edit(edits, None, cx);
 5392                })
 5393            }
 5394
 5395            this.refresh_inline_completion(true, false, window, cx);
 5396        });
 5397
 5398        let show_new_completions_on_confirm = completion
 5399            .confirm
 5400            .as_ref()
 5401            .map_or(false, |confirm| confirm(intent, window, cx));
 5402        if show_new_completions_on_confirm {
 5403            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5404        }
 5405
 5406        let provider = self.completion_provider.as_ref()?;
 5407        drop(completion);
 5408        let apply_edits = provider.apply_additional_edits_for_completion(
 5409            buffer_handle,
 5410            completions_menu.completions.clone(),
 5411            candidate_id,
 5412            true,
 5413            cx,
 5414        );
 5415
 5416        let editor_settings = EditorSettings::get_global(cx);
 5417        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5418            // After the code completion is finished, users often want to know what signatures are needed.
 5419            // so we should automatically call signature_help
 5420            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5421        }
 5422
 5423        Some(cx.foreground_executor().spawn(async move {
 5424            apply_edits.await?;
 5425            Ok(())
 5426        }))
 5427    }
 5428
 5429    pub fn toggle_code_actions(
 5430        &mut self,
 5431        action: &ToggleCodeActions,
 5432        window: &mut Window,
 5433        cx: &mut Context<Self>,
 5434    ) {
 5435        let quick_launch = action.quick_launch;
 5436        let mut context_menu = self.context_menu.borrow_mut();
 5437        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5438            if code_actions.deployed_from == action.deployed_from {
 5439                // Toggle if we're selecting the same one
 5440                *context_menu = None;
 5441                cx.notify();
 5442                return;
 5443            } else {
 5444                // Otherwise, clear it and start a new one
 5445                *context_menu = None;
 5446                cx.notify();
 5447            }
 5448        }
 5449        drop(context_menu);
 5450        let snapshot = self.snapshot(window, cx);
 5451        let deployed_from = action.deployed_from.clone();
 5452        let mut task = self.code_actions_task.take();
 5453        let action = action.clone();
 5454        cx.spawn_in(window, async move |editor, cx| {
 5455            while let Some(prev_task) = task {
 5456                prev_task.await.log_err();
 5457                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5458            }
 5459
 5460            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5461                if editor.focus_handle.is_focused(window) {
 5462                    let multibuffer_point = match &action.deployed_from {
 5463                        Some(CodeActionSource::Indicator(row)) => {
 5464                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5465                        }
 5466                        _ => editor.selections.newest::<Point>(cx).head(),
 5467                    };
 5468                    let (buffer, buffer_row) = snapshot
 5469                        .buffer_snapshot
 5470                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5471                        .and_then(|(buffer_snapshot, range)| {
 5472                            editor
 5473                                .buffer
 5474                                .read(cx)
 5475                                .buffer(buffer_snapshot.remote_id())
 5476                                .map(|buffer| (buffer, range.start.row))
 5477                        })?;
 5478                    let (_, code_actions) = editor
 5479                        .available_code_actions
 5480                        .clone()
 5481                        .and_then(|(location, code_actions)| {
 5482                            let snapshot = location.buffer.read(cx).snapshot();
 5483                            let point_range = location.range.to_point(&snapshot);
 5484                            let point_range = point_range.start.row..=point_range.end.row;
 5485                            if point_range.contains(&buffer_row) {
 5486                                Some((location, code_actions))
 5487                            } else {
 5488                                None
 5489                            }
 5490                        })
 5491                        .unzip();
 5492                    let buffer_id = buffer.read(cx).remote_id();
 5493                    let tasks = editor
 5494                        .tasks
 5495                        .get(&(buffer_id, buffer_row))
 5496                        .map(|t| Arc::new(t.to_owned()));
 5497                    if tasks.is_none() && code_actions.is_none() {
 5498                        return None;
 5499                    }
 5500
 5501                    editor.completion_tasks.clear();
 5502                    editor.discard_inline_completion(false, cx);
 5503                    let task_context =
 5504                        tasks
 5505                            .as_ref()
 5506                            .zip(editor.project.clone())
 5507                            .map(|(tasks, project)| {
 5508                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5509                            });
 5510
 5511                    Some(cx.spawn_in(window, async move |editor, cx| {
 5512                        let task_context = match task_context {
 5513                            Some(task_context) => task_context.await,
 5514                            None => None,
 5515                        };
 5516                        let resolved_tasks =
 5517                            tasks
 5518                                .zip(task_context.clone())
 5519                                .map(|(tasks, task_context)| ResolvedTasks {
 5520                                    templates: tasks.resolve(&task_context).collect(),
 5521                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5522                                        multibuffer_point.row,
 5523                                        tasks.column,
 5524                                    )),
 5525                                });
 5526                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5527                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5528                                maybe!({
 5529                                    let project = editor.project.as_ref()?;
 5530                                    let dap_store = project.read(cx).dap_store();
 5531                                    let mut scenarios = vec![];
 5532                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5533                                    let buffer = buffer.read(cx);
 5534                                    let language = buffer.language()?;
 5535                                    let file = buffer.file();
 5536                                    let debug_adapter =
 5537                                        language_settings(language.name().into(), file, cx)
 5538                                            .debuggers
 5539                                            .first()
 5540                                            .map(SharedString::from)
 5541                                            .or_else(|| {
 5542                                                language
 5543                                                    .config()
 5544                                                    .debuggers
 5545                                                    .first()
 5546                                                    .map(SharedString::from)
 5547                                            })?;
 5548
 5549                                    dap_store.update(cx, |dap_store, cx| {
 5550                                        for (_, task) in &resolved_tasks.templates {
 5551                                            if let Some(scenario) = dap_store
 5552                                                .debug_scenario_for_build_task(
 5553                                                    task.original_task().clone(),
 5554                                                    debug_adapter.clone().into(),
 5555                                                    task.display_label().to_owned().into(),
 5556                                                    cx,
 5557                                                )
 5558                                            {
 5559                                                scenarios.push(scenario);
 5560                                            }
 5561                                        }
 5562                                    });
 5563                                    Some(scenarios)
 5564                                })
 5565                                .unwrap_or_default()
 5566                            } else {
 5567                                vec![]
 5568                            }
 5569                        })?;
 5570                        let spawn_straight_away = quick_launch
 5571                            && resolved_tasks
 5572                                .as_ref()
 5573                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5574                            && code_actions
 5575                                .as_ref()
 5576                                .map_or(true, |actions| actions.is_empty())
 5577                            && debug_scenarios.is_empty();
 5578                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5579                            crate::hover_popover::hide_hover(editor, cx);
 5580                            *editor.context_menu.borrow_mut() =
 5581                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5582                                    buffer,
 5583                                    actions: CodeActionContents::new(
 5584                                        resolved_tasks,
 5585                                        code_actions,
 5586                                        debug_scenarios,
 5587                                        task_context.unwrap_or_default(),
 5588                                    ),
 5589                                    selected_item: Default::default(),
 5590                                    scroll_handle: UniformListScrollHandle::default(),
 5591                                    deployed_from,
 5592                                }));
 5593                            if spawn_straight_away {
 5594                                if let Some(task) = editor.confirm_code_action(
 5595                                    &ConfirmCodeAction { item_ix: Some(0) },
 5596                                    window,
 5597                                    cx,
 5598                                ) {
 5599                                    cx.notify();
 5600                                    return task;
 5601                                }
 5602                            }
 5603                            cx.notify();
 5604                            Task::ready(Ok(()))
 5605                        }) {
 5606                            task.await
 5607                        } else {
 5608                            Ok(())
 5609                        }
 5610                    }))
 5611                } else {
 5612                    Some(Task::ready(Ok(())))
 5613                }
 5614            })?;
 5615            if let Some(task) = spawned_test_task {
 5616                task.await?;
 5617            }
 5618
 5619            anyhow::Ok(())
 5620        })
 5621        .detach_and_log_err(cx);
 5622    }
 5623
 5624    pub fn confirm_code_action(
 5625        &mut self,
 5626        action: &ConfirmCodeAction,
 5627        window: &mut Window,
 5628        cx: &mut Context<Self>,
 5629    ) -> Option<Task<Result<()>>> {
 5630        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5631
 5632        let actions_menu =
 5633            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5634                menu
 5635            } else {
 5636                return None;
 5637            };
 5638
 5639        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5640        let action = actions_menu.actions.get(action_ix)?;
 5641        let title = action.label();
 5642        let buffer = actions_menu.buffer;
 5643        let workspace = self.workspace()?;
 5644
 5645        match action {
 5646            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5647                workspace.update(cx, |workspace, cx| {
 5648                    workspace.schedule_resolved_task(
 5649                        task_source_kind,
 5650                        resolved_task,
 5651                        false,
 5652                        window,
 5653                        cx,
 5654                    );
 5655
 5656                    Some(Task::ready(Ok(())))
 5657                })
 5658            }
 5659            CodeActionsItem::CodeAction {
 5660                excerpt_id,
 5661                action,
 5662                provider,
 5663            } => {
 5664                let apply_code_action =
 5665                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5666                let workspace = workspace.downgrade();
 5667                Some(cx.spawn_in(window, async move |editor, cx| {
 5668                    let project_transaction = apply_code_action.await?;
 5669                    Self::open_project_transaction(
 5670                        &editor,
 5671                        workspace,
 5672                        project_transaction,
 5673                        title,
 5674                        cx,
 5675                    )
 5676                    .await
 5677                }))
 5678            }
 5679            CodeActionsItem::DebugScenario(scenario) => {
 5680                let context = actions_menu.actions.context.clone();
 5681
 5682                workspace.update(cx, |workspace, cx| {
 5683                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5684                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5685                });
 5686                Some(Task::ready(Ok(())))
 5687            }
 5688        }
 5689    }
 5690
 5691    pub async fn open_project_transaction(
 5692        this: &WeakEntity<Editor>,
 5693        workspace: WeakEntity<Workspace>,
 5694        transaction: ProjectTransaction,
 5695        title: String,
 5696        cx: &mut AsyncWindowContext,
 5697    ) -> Result<()> {
 5698        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5699        cx.update(|_, cx| {
 5700            entries.sort_unstable_by_key(|(buffer, _)| {
 5701                buffer.read(cx).file().map(|f| f.path().clone())
 5702            });
 5703        })?;
 5704
 5705        // If the project transaction's edits are all contained within this editor, then
 5706        // avoid opening a new editor to display them.
 5707
 5708        if let Some((buffer, transaction)) = entries.first() {
 5709            if entries.len() == 1 {
 5710                let excerpt = this.update(cx, |editor, cx| {
 5711                    editor
 5712                        .buffer()
 5713                        .read(cx)
 5714                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5715                })?;
 5716                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5717                    if excerpted_buffer == *buffer {
 5718                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5719                            let excerpt_range = excerpt_range.to_offset(buffer);
 5720                            buffer
 5721                                .edited_ranges_for_transaction::<usize>(transaction)
 5722                                .all(|range| {
 5723                                    excerpt_range.start <= range.start
 5724                                        && excerpt_range.end >= range.end
 5725                                })
 5726                        })?;
 5727
 5728                        if all_edits_within_excerpt {
 5729                            return Ok(());
 5730                        }
 5731                    }
 5732                }
 5733            }
 5734        } else {
 5735            return Ok(());
 5736        }
 5737
 5738        let mut ranges_to_highlight = Vec::new();
 5739        let excerpt_buffer = cx.new(|cx| {
 5740            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5741            for (buffer_handle, transaction) in &entries {
 5742                let edited_ranges = buffer_handle
 5743                    .read(cx)
 5744                    .edited_ranges_for_transaction::<Point>(transaction)
 5745                    .collect::<Vec<_>>();
 5746                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5747                    PathKey::for_buffer(buffer_handle, cx),
 5748                    buffer_handle.clone(),
 5749                    edited_ranges,
 5750                    DEFAULT_MULTIBUFFER_CONTEXT,
 5751                    cx,
 5752                );
 5753
 5754                ranges_to_highlight.extend(ranges);
 5755            }
 5756            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5757            multibuffer
 5758        })?;
 5759
 5760        workspace.update_in(cx, |workspace, window, cx| {
 5761            let project = workspace.project().clone();
 5762            let editor =
 5763                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5764            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5765            editor.update(cx, |editor, cx| {
 5766                editor.highlight_background::<Self>(
 5767                    &ranges_to_highlight,
 5768                    |theme| theme.editor_highlighted_line_background,
 5769                    cx,
 5770                );
 5771            });
 5772        })?;
 5773
 5774        Ok(())
 5775    }
 5776
 5777    pub fn clear_code_action_providers(&mut self) {
 5778        self.code_action_providers.clear();
 5779        self.available_code_actions.take();
 5780    }
 5781
 5782    pub fn add_code_action_provider(
 5783        &mut self,
 5784        provider: Rc<dyn CodeActionProvider>,
 5785        window: &mut Window,
 5786        cx: &mut Context<Self>,
 5787    ) {
 5788        if self
 5789            .code_action_providers
 5790            .iter()
 5791            .any(|existing_provider| existing_provider.id() == provider.id())
 5792        {
 5793            return;
 5794        }
 5795
 5796        self.code_action_providers.push(provider);
 5797        self.refresh_code_actions(window, cx);
 5798    }
 5799
 5800    pub fn remove_code_action_provider(
 5801        &mut self,
 5802        id: Arc<str>,
 5803        window: &mut Window,
 5804        cx: &mut Context<Self>,
 5805    ) {
 5806        self.code_action_providers
 5807            .retain(|provider| provider.id() != id);
 5808        self.refresh_code_actions(window, cx);
 5809    }
 5810
 5811    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5812        !self.code_action_providers.is_empty()
 5813            && EditorSettings::get_global(cx).toolbar.code_actions
 5814    }
 5815
 5816    pub fn has_available_code_actions(&self) -> bool {
 5817        self.available_code_actions
 5818            .as_ref()
 5819            .is_some_and(|(_, actions)| !actions.is_empty())
 5820    }
 5821
 5822    fn render_inline_code_actions(
 5823        &self,
 5824        icon_size: ui::IconSize,
 5825        display_row: DisplayRow,
 5826        is_active: bool,
 5827        cx: &mut Context<Self>,
 5828    ) -> AnyElement {
 5829        let show_tooltip = !self.context_menu_visible();
 5830        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5831            .icon_size(icon_size)
 5832            .shape(ui::IconButtonShape::Square)
 5833            .style(ButtonStyle::Transparent)
 5834            .icon_color(ui::Color::Hidden)
 5835            .toggle_state(is_active)
 5836            .when(show_tooltip, |this| {
 5837                this.tooltip({
 5838                    let focus_handle = self.focus_handle.clone();
 5839                    move |window, cx| {
 5840                        Tooltip::for_action_in(
 5841                            "Toggle Code Actions",
 5842                            &ToggleCodeActions {
 5843                                deployed_from: None,
 5844                                quick_launch: false,
 5845                            },
 5846                            &focus_handle,
 5847                            window,
 5848                            cx,
 5849                        )
 5850                    }
 5851                })
 5852            })
 5853            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5854                window.focus(&editor.focus_handle(cx));
 5855                editor.toggle_code_actions(
 5856                    &crate::actions::ToggleCodeActions {
 5857                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5858                            display_row,
 5859                        )),
 5860                        quick_launch: false,
 5861                    },
 5862                    window,
 5863                    cx,
 5864                );
 5865            }))
 5866            .into_any_element()
 5867    }
 5868
 5869    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5870        &self.context_menu
 5871    }
 5872
 5873    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5874        let newest_selection = self.selections.newest_anchor().clone();
 5875        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5876        let buffer = self.buffer.read(cx);
 5877        if newest_selection.head().diff_base_anchor.is_some() {
 5878            return None;
 5879        }
 5880        let (start_buffer, start) =
 5881            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5882        let (end_buffer, end) =
 5883            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5884        if start_buffer != end_buffer {
 5885            return None;
 5886        }
 5887
 5888        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5889            cx.background_executor()
 5890                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5891                .await;
 5892
 5893            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5894                let providers = this.code_action_providers.clone();
 5895                let tasks = this
 5896                    .code_action_providers
 5897                    .iter()
 5898                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5899                    .collect::<Vec<_>>();
 5900                (providers, tasks)
 5901            })?;
 5902
 5903            let mut actions = Vec::new();
 5904            for (provider, provider_actions) in
 5905                providers.into_iter().zip(future::join_all(tasks).await)
 5906            {
 5907                if let Some(provider_actions) = provider_actions.log_err() {
 5908                    actions.extend(provider_actions.into_iter().map(|action| {
 5909                        AvailableCodeAction {
 5910                            excerpt_id: newest_selection.start.excerpt_id,
 5911                            action,
 5912                            provider: provider.clone(),
 5913                        }
 5914                    }));
 5915                }
 5916            }
 5917
 5918            this.update(cx, |this, cx| {
 5919                this.available_code_actions = if actions.is_empty() {
 5920                    None
 5921                } else {
 5922                    Some((
 5923                        Location {
 5924                            buffer: start_buffer,
 5925                            range: start..end,
 5926                        },
 5927                        actions.into(),
 5928                    ))
 5929                };
 5930                cx.notify();
 5931            })
 5932        }));
 5933        None
 5934    }
 5935
 5936    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5937        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5938            self.show_git_blame_inline = false;
 5939
 5940            self.show_git_blame_inline_delay_task =
 5941                Some(cx.spawn_in(window, async move |this, cx| {
 5942                    cx.background_executor().timer(delay).await;
 5943
 5944                    this.update(cx, |this, cx| {
 5945                        this.show_git_blame_inline = true;
 5946                        cx.notify();
 5947                    })
 5948                    .log_err();
 5949                }));
 5950        }
 5951    }
 5952
 5953    fn show_blame_popover(
 5954        &mut self,
 5955        blame_entry: &BlameEntry,
 5956        position: gpui::Point<Pixels>,
 5957        cx: &mut Context<Self>,
 5958    ) {
 5959        if let Some(state) = &mut self.inline_blame_popover {
 5960            state.hide_task.take();
 5961            cx.notify();
 5962        } else {
 5963            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5964            let show_task = cx.spawn(async move |editor, cx| {
 5965                cx.background_executor()
 5966                    .timer(std::time::Duration::from_millis(delay))
 5967                    .await;
 5968                editor
 5969                    .update(cx, |editor, cx| {
 5970                        if let Some(state) = &mut editor.inline_blame_popover {
 5971                            state.show_task = None;
 5972                            cx.notify();
 5973                        }
 5974                    })
 5975                    .ok();
 5976            });
 5977            let Some(blame) = self.blame.as_ref() else {
 5978                return;
 5979            };
 5980            let blame = blame.read(cx);
 5981            let details = blame.details_for_entry(&blame_entry);
 5982            let markdown = cx.new(|cx| {
 5983                Markdown::new(
 5984                    details
 5985                        .as_ref()
 5986                        .map(|message| message.message.clone())
 5987                        .unwrap_or_default(),
 5988                    None,
 5989                    None,
 5990                    cx,
 5991                )
 5992            });
 5993            self.inline_blame_popover = Some(InlineBlamePopover {
 5994                position,
 5995                show_task: Some(show_task),
 5996                hide_task: None,
 5997                popover_bounds: None,
 5998                popover_state: InlineBlamePopoverState {
 5999                    scroll_handle: ScrollHandle::new(),
 6000                    commit_message: details,
 6001                    markdown,
 6002                },
 6003            });
 6004        }
 6005    }
 6006
 6007    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6008        if let Some(state) = &mut self.inline_blame_popover {
 6009            if state.show_task.is_some() {
 6010                self.inline_blame_popover.take();
 6011                cx.notify();
 6012            } else {
 6013                let hide_task = cx.spawn(async move |editor, cx| {
 6014                    cx.background_executor()
 6015                        .timer(std::time::Duration::from_millis(100))
 6016                        .await;
 6017                    editor
 6018                        .update(cx, |editor, cx| {
 6019                            editor.inline_blame_popover.take();
 6020                            cx.notify();
 6021                        })
 6022                        .ok();
 6023                });
 6024                state.hide_task = Some(hide_task);
 6025            }
 6026        }
 6027    }
 6028
 6029    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6030        if self.pending_rename.is_some() {
 6031            return None;
 6032        }
 6033
 6034        let provider = self.semantics_provider.clone()?;
 6035        let buffer = self.buffer.read(cx);
 6036        let newest_selection = self.selections.newest_anchor().clone();
 6037        let cursor_position = newest_selection.head();
 6038        let (cursor_buffer, cursor_buffer_position) =
 6039            buffer.text_anchor_for_position(cursor_position, cx)?;
 6040        let (tail_buffer, tail_buffer_position) =
 6041            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6042        if cursor_buffer != tail_buffer {
 6043            return None;
 6044        }
 6045
 6046        let snapshot = cursor_buffer.read(cx).snapshot();
 6047        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6048        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6049        if start_word_range != end_word_range {
 6050            self.document_highlights_task.take();
 6051            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6052            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6053            return None;
 6054        }
 6055
 6056        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6057        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6058            cx.background_executor()
 6059                .timer(Duration::from_millis(debounce))
 6060                .await;
 6061
 6062            let highlights = if let Some(highlights) = cx
 6063                .update(|cx| {
 6064                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6065                })
 6066                .ok()
 6067                .flatten()
 6068            {
 6069                highlights.await.log_err()
 6070            } else {
 6071                None
 6072            };
 6073
 6074            if let Some(highlights) = highlights {
 6075                this.update(cx, |this, cx| {
 6076                    if this.pending_rename.is_some() {
 6077                        return;
 6078                    }
 6079
 6080                    let buffer_id = cursor_position.buffer_id;
 6081                    let buffer = this.buffer.read(cx);
 6082                    if !buffer
 6083                        .text_anchor_for_position(cursor_position, cx)
 6084                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6085                    {
 6086                        return;
 6087                    }
 6088
 6089                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6090                    let mut write_ranges = Vec::new();
 6091                    let mut read_ranges = Vec::new();
 6092                    for highlight in highlights {
 6093                        for (excerpt_id, excerpt_range) in
 6094                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6095                        {
 6096                            let start = highlight
 6097                                .range
 6098                                .start
 6099                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6100                            let end = highlight
 6101                                .range
 6102                                .end
 6103                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6104                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6105                                continue;
 6106                            }
 6107
 6108                            let range = Anchor {
 6109                                buffer_id,
 6110                                excerpt_id,
 6111                                text_anchor: start,
 6112                                diff_base_anchor: None,
 6113                            }..Anchor {
 6114                                buffer_id,
 6115                                excerpt_id,
 6116                                text_anchor: end,
 6117                                diff_base_anchor: None,
 6118                            };
 6119                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6120                                write_ranges.push(range);
 6121                            } else {
 6122                                read_ranges.push(range);
 6123                            }
 6124                        }
 6125                    }
 6126
 6127                    this.highlight_background::<DocumentHighlightRead>(
 6128                        &read_ranges,
 6129                        |theme| theme.editor_document_highlight_read_background,
 6130                        cx,
 6131                    );
 6132                    this.highlight_background::<DocumentHighlightWrite>(
 6133                        &write_ranges,
 6134                        |theme| theme.editor_document_highlight_write_background,
 6135                        cx,
 6136                    );
 6137                    cx.notify();
 6138                })
 6139                .log_err();
 6140            }
 6141        }));
 6142        None
 6143    }
 6144
 6145    fn prepare_highlight_query_from_selection(
 6146        &mut self,
 6147        cx: &mut Context<Editor>,
 6148    ) -> Option<(String, Range<Anchor>)> {
 6149        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6150            return None;
 6151        }
 6152        if !EditorSettings::get_global(cx).selection_highlight {
 6153            return None;
 6154        }
 6155        if self.selections.count() != 1 || self.selections.line_mode {
 6156            return None;
 6157        }
 6158        let selection = self.selections.newest::<Point>(cx);
 6159        if selection.is_empty() || selection.start.row != selection.end.row {
 6160            return None;
 6161        }
 6162        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6163        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6164        let query = multi_buffer_snapshot
 6165            .text_for_range(selection_anchor_range.clone())
 6166            .collect::<String>();
 6167        if query.trim().is_empty() {
 6168            return None;
 6169        }
 6170        Some((query, selection_anchor_range))
 6171    }
 6172
 6173    fn update_selection_occurrence_highlights(
 6174        &mut self,
 6175        query_text: String,
 6176        query_range: Range<Anchor>,
 6177        multi_buffer_range_to_query: Range<Point>,
 6178        use_debounce: bool,
 6179        window: &mut Window,
 6180        cx: &mut Context<Editor>,
 6181    ) -> Task<()> {
 6182        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6183        cx.spawn_in(window, async move |editor, cx| {
 6184            if use_debounce {
 6185                cx.background_executor()
 6186                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6187                    .await;
 6188            }
 6189            let match_task = cx.background_spawn(async move {
 6190                let buffer_ranges = multi_buffer_snapshot
 6191                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6192                    .into_iter()
 6193                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6194                let mut match_ranges = Vec::new();
 6195                let Ok(regex) = project::search::SearchQuery::text(
 6196                    query_text.clone(),
 6197                    false,
 6198                    false,
 6199                    false,
 6200                    Default::default(),
 6201                    Default::default(),
 6202                    false,
 6203                    None,
 6204                ) else {
 6205                    return Vec::default();
 6206                };
 6207                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6208                    match_ranges.extend(
 6209                        regex
 6210                            .search(&buffer_snapshot, Some(search_range.clone()))
 6211                            .await
 6212                            .into_iter()
 6213                            .filter_map(|match_range| {
 6214                                let match_start = buffer_snapshot
 6215                                    .anchor_after(search_range.start + match_range.start);
 6216                                let match_end = buffer_snapshot
 6217                                    .anchor_before(search_range.start + match_range.end);
 6218                                let match_anchor_range = Anchor::range_in_buffer(
 6219                                    excerpt_id,
 6220                                    buffer_snapshot.remote_id(),
 6221                                    match_start..match_end,
 6222                                );
 6223                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6224                            }),
 6225                    );
 6226                }
 6227                match_ranges
 6228            });
 6229            let match_ranges = match_task.await;
 6230            editor
 6231                .update_in(cx, |editor, _, cx| {
 6232                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6233                    if !match_ranges.is_empty() {
 6234                        editor.highlight_background::<SelectedTextHighlight>(
 6235                            &match_ranges,
 6236                            |theme| theme.editor_document_highlight_bracket_background,
 6237                            cx,
 6238                        )
 6239                    }
 6240                })
 6241                .log_err();
 6242        })
 6243    }
 6244
 6245    fn refresh_selected_text_highlights(
 6246        &mut self,
 6247        on_buffer_edit: bool,
 6248        window: &mut Window,
 6249        cx: &mut Context<Editor>,
 6250    ) {
 6251        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6252        else {
 6253            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6254            self.quick_selection_highlight_task.take();
 6255            self.debounced_selection_highlight_task.take();
 6256            return;
 6257        };
 6258        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6259        if on_buffer_edit
 6260            || self
 6261                .quick_selection_highlight_task
 6262                .as_ref()
 6263                .map_or(true, |(prev_anchor_range, _)| {
 6264                    prev_anchor_range != &query_range
 6265                })
 6266        {
 6267            let multi_buffer_visible_start = self
 6268                .scroll_manager
 6269                .anchor()
 6270                .anchor
 6271                .to_point(&multi_buffer_snapshot);
 6272            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6273                multi_buffer_visible_start
 6274                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6275                Bias::Left,
 6276            );
 6277            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6278            self.quick_selection_highlight_task = Some((
 6279                query_range.clone(),
 6280                self.update_selection_occurrence_highlights(
 6281                    query_text.clone(),
 6282                    query_range.clone(),
 6283                    multi_buffer_visible_range,
 6284                    false,
 6285                    window,
 6286                    cx,
 6287                ),
 6288            ));
 6289        }
 6290        if on_buffer_edit
 6291            || self
 6292                .debounced_selection_highlight_task
 6293                .as_ref()
 6294                .map_or(true, |(prev_anchor_range, _)| {
 6295                    prev_anchor_range != &query_range
 6296                })
 6297        {
 6298            let multi_buffer_start = multi_buffer_snapshot
 6299                .anchor_before(0)
 6300                .to_point(&multi_buffer_snapshot);
 6301            let multi_buffer_end = multi_buffer_snapshot
 6302                .anchor_after(multi_buffer_snapshot.len())
 6303                .to_point(&multi_buffer_snapshot);
 6304            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6305            self.debounced_selection_highlight_task = Some((
 6306                query_range.clone(),
 6307                self.update_selection_occurrence_highlights(
 6308                    query_text,
 6309                    query_range,
 6310                    multi_buffer_full_range,
 6311                    true,
 6312                    window,
 6313                    cx,
 6314                ),
 6315            ));
 6316        }
 6317    }
 6318
 6319    pub fn refresh_inline_completion(
 6320        &mut self,
 6321        debounce: bool,
 6322        user_requested: bool,
 6323        window: &mut Window,
 6324        cx: &mut Context<Self>,
 6325    ) -> Option<()> {
 6326        let provider = self.edit_prediction_provider()?;
 6327        let cursor = self.selections.newest_anchor().head();
 6328        let (buffer, cursor_buffer_position) =
 6329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6330
 6331        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6332            self.discard_inline_completion(false, cx);
 6333            return None;
 6334        }
 6335
 6336        if !user_requested
 6337            && (!self.should_show_edit_predictions()
 6338                || !self.is_focused(window)
 6339                || buffer.read(cx).is_empty())
 6340        {
 6341            self.discard_inline_completion(false, cx);
 6342            return None;
 6343        }
 6344
 6345        self.update_visible_inline_completion(window, cx);
 6346        provider.refresh(
 6347            self.project.clone(),
 6348            buffer,
 6349            cursor_buffer_position,
 6350            debounce,
 6351            cx,
 6352        );
 6353        Some(())
 6354    }
 6355
 6356    fn show_edit_predictions_in_menu(&self) -> bool {
 6357        match self.edit_prediction_settings {
 6358            EditPredictionSettings::Disabled => false,
 6359            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6360        }
 6361    }
 6362
 6363    pub fn edit_predictions_enabled(&self) -> bool {
 6364        match self.edit_prediction_settings {
 6365            EditPredictionSettings::Disabled => false,
 6366            EditPredictionSettings::Enabled { .. } => true,
 6367        }
 6368    }
 6369
 6370    fn edit_prediction_requires_modifier(&self) -> bool {
 6371        match self.edit_prediction_settings {
 6372            EditPredictionSettings::Disabled => false,
 6373            EditPredictionSettings::Enabled {
 6374                preview_requires_modifier,
 6375                ..
 6376            } => preview_requires_modifier,
 6377        }
 6378    }
 6379
 6380    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6381        if self.edit_prediction_provider.is_none() {
 6382            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6383        } else {
 6384            let selection = self.selections.newest_anchor();
 6385            let cursor = selection.head();
 6386
 6387            if let Some((buffer, cursor_buffer_position)) =
 6388                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6389            {
 6390                self.edit_prediction_settings =
 6391                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6392            }
 6393        }
 6394    }
 6395
 6396    fn edit_prediction_settings_at_position(
 6397        &self,
 6398        buffer: &Entity<Buffer>,
 6399        buffer_position: language::Anchor,
 6400        cx: &App,
 6401    ) -> EditPredictionSettings {
 6402        if !self.mode.is_full()
 6403            || !self.show_inline_completions_override.unwrap_or(true)
 6404            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6405        {
 6406            return EditPredictionSettings::Disabled;
 6407        }
 6408
 6409        let buffer = buffer.read(cx);
 6410
 6411        let file = buffer.file();
 6412
 6413        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6414            return EditPredictionSettings::Disabled;
 6415        };
 6416
 6417        let by_provider = matches!(
 6418            self.menu_inline_completions_policy,
 6419            MenuInlineCompletionsPolicy::ByProvider
 6420        );
 6421
 6422        let show_in_menu = by_provider
 6423            && self
 6424                .edit_prediction_provider
 6425                .as_ref()
 6426                .map_or(false, |provider| {
 6427                    provider.provider.show_completions_in_menu()
 6428                });
 6429
 6430        let preview_requires_modifier =
 6431            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6432
 6433        EditPredictionSettings::Enabled {
 6434            show_in_menu,
 6435            preview_requires_modifier,
 6436        }
 6437    }
 6438
 6439    fn should_show_edit_predictions(&self) -> bool {
 6440        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6441    }
 6442
 6443    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6444        matches!(
 6445            self.edit_prediction_preview,
 6446            EditPredictionPreview::Active { .. }
 6447        )
 6448    }
 6449
 6450    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6451        let cursor = self.selections.newest_anchor().head();
 6452        if let Some((buffer, cursor_position)) =
 6453            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6454        {
 6455            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6456        } else {
 6457            false
 6458        }
 6459    }
 6460
 6461    pub fn supports_minimap(&self, cx: &App) -> bool {
 6462        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6463    }
 6464
 6465    fn edit_predictions_enabled_in_buffer(
 6466        &self,
 6467        buffer: &Entity<Buffer>,
 6468        buffer_position: language::Anchor,
 6469        cx: &App,
 6470    ) -> bool {
 6471        maybe!({
 6472            if self.read_only(cx) {
 6473                return Some(false);
 6474            }
 6475            let provider = self.edit_prediction_provider()?;
 6476            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6477                return Some(false);
 6478            }
 6479            let buffer = buffer.read(cx);
 6480            let Some(file) = buffer.file() else {
 6481                return Some(true);
 6482            };
 6483            let settings = all_language_settings(Some(file), cx);
 6484            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6485        })
 6486        .unwrap_or(false)
 6487    }
 6488
 6489    fn cycle_inline_completion(
 6490        &mut self,
 6491        direction: Direction,
 6492        window: &mut Window,
 6493        cx: &mut Context<Self>,
 6494    ) -> Option<()> {
 6495        let provider = self.edit_prediction_provider()?;
 6496        let cursor = self.selections.newest_anchor().head();
 6497        let (buffer, cursor_buffer_position) =
 6498            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6499        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6500            return None;
 6501        }
 6502
 6503        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6504        self.update_visible_inline_completion(window, cx);
 6505
 6506        Some(())
 6507    }
 6508
 6509    pub fn show_inline_completion(
 6510        &mut self,
 6511        _: &ShowEditPrediction,
 6512        window: &mut Window,
 6513        cx: &mut Context<Self>,
 6514    ) {
 6515        if !self.has_active_inline_completion() {
 6516            self.refresh_inline_completion(false, true, window, cx);
 6517            return;
 6518        }
 6519
 6520        self.update_visible_inline_completion(window, cx);
 6521    }
 6522
 6523    pub fn display_cursor_names(
 6524        &mut self,
 6525        _: &DisplayCursorNames,
 6526        window: &mut Window,
 6527        cx: &mut Context<Self>,
 6528    ) {
 6529        self.show_cursor_names(window, cx);
 6530    }
 6531
 6532    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6533        self.show_cursor_names = true;
 6534        cx.notify();
 6535        cx.spawn_in(window, async move |this, cx| {
 6536            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6537            this.update(cx, |this, cx| {
 6538                this.show_cursor_names = false;
 6539                cx.notify()
 6540            })
 6541            .ok()
 6542        })
 6543        .detach();
 6544    }
 6545
 6546    pub fn next_edit_prediction(
 6547        &mut self,
 6548        _: &NextEditPrediction,
 6549        window: &mut Window,
 6550        cx: &mut Context<Self>,
 6551    ) {
 6552        if self.has_active_inline_completion() {
 6553            self.cycle_inline_completion(Direction::Next, window, cx);
 6554        } else {
 6555            let is_copilot_disabled = self
 6556                .refresh_inline_completion(false, true, window, cx)
 6557                .is_none();
 6558            if is_copilot_disabled {
 6559                cx.propagate();
 6560            }
 6561        }
 6562    }
 6563
 6564    pub fn previous_edit_prediction(
 6565        &mut self,
 6566        _: &PreviousEditPrediction,
 6567        window: &mut Window,
 6568        cx: &mut Context<Self>,
 6569    ) {
 6570        if self.has_active_inline_completion() {
 6571            self.cycle_inline_completion(Direction::Prev, window, cx);
 6572        } else {
 6573            let is_copilot_disabled = self
 6574                .refresh_inline_completion(false, true, window, cx)
 6575                .is_none();
 6576            if is_copilot_disabled {
 6577                cx.propagate();
 6578            }
 6579        }
 6580    }
 6581
 6582    pub fn accept_edit_prediction(
 6583        &mut self,
 6584        _: &AcceptEditPrediction,
 6585        window: &mut Window,
 6586        cx: &mut Context<Self>,
 6587    ) {
 6588        if self.show_edit_predictions_in_menu() {
 6589            self.hide_context_menu(window, cx);
 6590        }
 6591
 6592        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6593            return;
 6594        };
 6595
 6596        self.report_inline_completion_event(
 6597            active_inline_completion.completion_id.clone(),
 6598            true,
 6599            cx,
 6600        );
 6601
 6602        match &active_inline_completion.completion {
 6603            InlineCompletion::Move { target, .. } => {
 6604                let target = *target;
 6605
 6606                if let Some(position_map) = &self.last_position_map {
 6607                    if position_map
 6608                        .visible_row_range
 6609                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6610                        || !self.edit_prediction_requires_modifier()
 6611                    {
 6612                        self.unfold_ranges(&[target..target], true, false, cx);
 6613                        // Note that this is also done in vim's handler of the Tab action.
 6614                        self.change_selections(
 6615                            Some(Autoscroll::newest()),
 6616                            window,
 6617                            cx,
 6618                            |selections| {
 6619                                selections.select_anchor_ranges([target..target]);
 6620                            },
 6621                        );
 6622                        self.clear_row_highlights::<EditPredictionPreview>();
 6623
 6624                        self.edit_prediction_preview
 6625                            .set_previous_scroll_position(None);
 6626                    } else {
 6627                        self.edit_prediction_preview
 6628                            .set_previous_scroll_position(Some(
 6629                                position_map.snapshot.scroll_anchor,
 6630                            ));
 6631
 6632                        self.highlight_rows::<EditPredictionPreview>(
 6633                            target..target,
 6634                            cx.theme().colors().editor_highlighted_line_background,
 6635                            RowHighlightOptions {
 6636                                autoscroll: true,
 6637                                ..Default::default()
 6638                            },
 6639                            cx,
 6640                        );
 6641                        self.request_autoscroll(Autoscroll::fit(), cx);
 6642                    }
 6643                }
 6644            }
 6645            InlineCompletion::Edit { edits, .. } => {
 6646                if let Some(provider) = self.edit_prediction_provider() {
 6647                    provider.accept(cx);
 6648                }
 6649
 6650                // Store the transaction ID and selections before applying the edit
 6651                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6652
 6653                let snapshot = self.buffer.read(cx).snapshot(cx);
 6654                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6655
 6656                self.buffer.update(cx, |buffer, cx| {
 6657                    buffer.edit(edits.iter().cloned(), None, cx)
 6658                });
 6659
 6660                self.change_selections(None, window, cx, |s| {
 6661                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6662                });
 6663
 6664                let selections = self.selections.disjoint_anchors();
 6665                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6666                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6667                    if has_new_transaction {
 6668                        self.selection_history
 6669                            .insert_transaction(transaction_id_now, selections);
 6670                    }
 6671                }
 6672
 6673                self.update_visible_inline_completion(window, cx);
 6674                if self.active_inline_completion.is_none() {
 6675                    self.refresh_inline_completion(true, true, window, cx);
 6676                }
 6677
 6678                cx.notify();
 6679            }
 6680        }
 6681
 6682        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6683    }
 6684
 6685    pub fn accept_partial_inline_completion(
 6686        &mut self,
 6687        _: &AcceptPartialEditPrediction,
 6688        window: &mut Window,
 6689        cx: &mut Context<Self>,
 6690    ) {
 6691        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6692            return;
 6693        };
 6694        if self.selections.count() != 1 {
 6695            return;
 6696        }
 6697
 6698        self.report_inline_completion_event(
 6699            active_inline_completion.completion_id.clone(),
 6700            true,
 6701            cx,
 6702        );
 6703
 6704        match &active_inline_completion.completion {
 6705            InlineCompletion::Move { target, .. } => {
 6706                let target = *target;
 6707                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6708                    selections.select_anchor_ranges([target..target]);
 6709                });
 6710            }
 6711            InlineCompletion::Edit { edits, .. } => {
 6712                // Find an insertion that starts at the cursor position.
 6713                let snapshot = self.buffer.read(cx).snapshot(cx);
 6714                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6715                let insertion = edits.iter().find_map(|(range, text)| {
 6716                    let range = range.to_offset(&snapshot);
 6717                    if range.is_empty() && range.start == cursor_offset {
 6718                        Some(text)
 6719                    } else {
 6720                        None
 6721                    }
 6722                });
 6723
 6724                if let Some(text) = insertion {
 6725                    let mut partial_completion = text
 6726                        .chars()
 6727                        .by_ref()
 6728                        .take_while(|c| c.is_alphabetic())
 6729                        .collect::<String>();
 6730                    if partial_completion.is_empty() {
 6731                        partial_completion = text
 6732                            .chars()
 6733                            .by_ref()
 6734                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6735                            .collect::<String>();
 6736                    }
 6737
 6738                    cx.emit(EditorEvent::InputHandled {
 6739                        utf16_range_to_replace: None,
 6740                        text: partial_completion.clone().into(),
 6741                    });
 6742
 6743                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6744
 6745                    self.refresh_inline_completion(true, true, window, cx);
 6746                    cx.notify();
 6747                } else {
 6748                    self.accept_edit_prediction(&Default::default(), window, cx);
 6749                }
 6750            }
 6751        }
 6752    }
 6753
 6754    fn discard_inline_completion(
 6755        &mut self,
 6756        should_report_inline_completion_event: bool,
 6757        cx: &mut Context<Self>,
 6758    ) -> bool {
 6759        if should_report_inline_completion_event {
 6760            let completion_id = self
 6761                .active_inline_completion
 6762                .as_ref()
 6763                .and_then(|active_completion| active_completion.completion_id.clone());
 6764
 6765            self.report_inline_completion_event(completion_id, false, cx);
 6766        }
 6767
 6768        if let Some(provider) = self.edit_prediction_provider() {
 6769            provider.discard(cx);
 6770        }
 6771
 6772        self.take_active_inline_completion(cx)
 6773    }
 6774
 6775    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6776        let Some(provider) = self.edit_prediction_provider() else {
 6777            return;
 6778        };
 6779
 6780        let Some((_, buffer, _)) = self
 6781            .buffer
 6782            .read(cx)
 6783            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6784        else {
 6785            return;
 6786        };
 6787
 6788        let extension = buffer
 6789            .read(cx)
 6790            .file()
 6791            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6792
 6793        let event_type = match accepted {
 6794            true => "Edit Prediction Accepted",
 6795            false => "Edit Prediction Discarded",
 6796        };
 6797        telemetry::event!(
 6798            event_type,
 6799            provider = provider.name(),
 6800            prediction_id = id,
 6801            suggestion_accepted = accepted,
 6802            file_extension = extension,
 6803        );
 6804    }
 6805
 6806    pub fn has_active_inline_completion(&self) -> bool {
 6807        self.active_inline_completion.is_some()
 6808    }
 6809
 6810    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6811        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6812            return false;
 6813        };
 6814
 6815        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6816        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6817        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6818        true
 6819    }
 6820
 6821    /// Returns true when we're displaying the edit prediction popover below the cursor
 6822    /// like we are not previewing and the LSP autocomplete menu is visible
 6823    /// or we are in `when_holding_modifier` mode.
 6824    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6825        if self.edit_prediction_preview_is_active()
 6826            || !self.show_edit_predictions_in_menu()
 6827            || !self.edit_predictions_enabled()
 6828        {
 6829            return false;
 6830        }
 6831
 6832        if self.has_visible_completions_menu() {
 6833            return true;
 6834        }
 6835
 6836        has_completion && self.edit_prediction_requires_modifier()
 6837    }
 6838
 6839    fn handle_modifiers_changed(
 6840        &mut self,
 6841        modifiers: Modifiers,
 6842        position_map: &PositionMap,
 6843        window: &mut Window,
 6844        cx: &mut Context<Self>,
 6845    ) {
 6846        if self.show_edit_predictions_in_menu() {
 6847            self.update_edit_prediction_preview(&modifiers, window, cx);
 6848        }
 6849
 6850        self.update_selection_mode(&modifiers, position_map, window, cx);
 6851
 6852        let mouse_position = window.mouse_position();
 6853        if !position_map.text_hitbox.is_hovered(window) {
 6854            return;
 6855        }
 6856
 6857        self.update_hovered_link(
 6858            position_map.point_for_position(mouse_position),
 6859            &position_map.snapshot,
 6860            modifiers,
 6861            window,
 6862            cx,
 6863        )
 6864    }
 6865
 6866    fn update_selection_mode(
 6867        &mut self,
 6868        modifiers: &Modifiers,
 6869        position_map: &PositionMap,
 6870        window: &mut Window,
 6871        cx: &mut Context<Self>,
 6872    ) {
 6873        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6874            return;
 6875        }
 6876
 6877        let mouse_position = window.mouse_position();
 6878        let point_for_position = position_map.point_for_position(mouse_position);
 6879        let position = point_for_position.previous_valid;
 6880
 6881        self.select(
 6882            SelectPhase::BeginColumnar {
 6883                position,
 6884                reset: false,
 6885                goal_column: point_for_position.exact_unclipped.column(),
 6886            },
 6887            window,
 6888            cx,
 6889        );
 6890    }
 6891
 6892    fn update_edit_prediction_preview(
 6893        &mut self,
 6894        modifiers: &Modifiers,
 6895        window: &mut Window,
 6896        cx: &mut Context<Self>,
 6897    ) {
 6898        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6899        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6900            return;
 6901        };
 6902
 6903        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6904            if matches!(
 6905                self.edit_prediction_preview,
 6906                EditPredictionPreview::Inactive { .. }
 6907            ) {
 6908                self.edit_prediction_preview = EditPredictionPreview::Active {
 6909                    previous_scroll_position: None,
 6910                    since: Instant::now(),
 6911                };
 6912
 6913                self.update_visible_inline_completion(window, cx);
 6914                cx.notify();
 6915            }
 6916        } else if let EditPredictionPreview::Active {
 6917            previous_scroll_position,
 6918            since,
 6919        } = self.edit_prediction_preview
 6920        {
 6921            if let (Some(previous_scroll_position), Some(position_map)) =
 6922                (previous_scroll_position, self.last_position_map.as_ref())
 6923            {
 6924                self.set_scroll_position(
 6925                    previous_scroll_position
 6926                        .scroll_position(&position_map.snapshot.display_snapshot),
 6927                    window,
 6928                    cx,
 6929                );
 6930            }
 6931
 6932            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6933                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6934            };
 6935            self.clear_row_highlights::<EditPredictionPreview>();
 6936            self.update_visible_inline_completion(window, cx);
 6937            cx.notify();
 6938        }
 6939    }
 6940
 6941    fn update_visible_inline_completion(
 6942        &mut self,
 6943        _window: &mut Window,
 6944        cx: &mut Context<Self>,
 6945    ) -> Option<()> {
 6946        let selection = self.selections.newest_anchor();
 6947        let cursor = selection.head();
 6948        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6949        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6950        let excerpt_id = cursor.excerpt_id;
 6951
 6952        let show_in_menu = self.show_edit_predictions_in_menu();
 6953        let completions_menu_has_precedence = !show_in_menu
 6954            && (self.context_menu.borrow().is_some()
 6955                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6956
 6957        if completions_menu_has_precedence
 6958            || !offset_selection.is_empty()
 6959            || self
 6960                .active_inline_completion
 6961                .as_ref()
 6962                .map_or(false, |completion| {
 6963                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6964                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6965                    !invalidation_range.contains(&offset_selection.head())
 6966                })
 6967        {
 6968            self.discard_inline_completion(false, cx);
 6969            return None;
 6970        }
 6971
 6972        self.take_active_inline_completion(cx);
 6973        let Some(provider) = self.edit_prediction_provider() else {
 6974            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6975            return None;
 6976        };
 6977
 6978        let (buffer, cursor_buffer_position) =
 6979            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6980
 6981        self.edit_prediction_settings =
 6982            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6983
 6984        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6985
 6986        if self.edit_prediction_indent_conflict {
 6987            let cursor_point = cursor.to_point(&multibuffer);
 6988
 6989            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6990
 6991            if let Some((_, indent)) = indents.iter().next() {
 6992                if indent.len == cursor_point.column {
 6993                    self.edit_prediction_indent_conflict = false;
 6994                }
 6995            }
 6996        }
 6997
 6998        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6999        let edits = inline_completion
 7000            .edits
 7001            .into_iter()
 7002            .flat_map(|(range, new_text)| {
 7003                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7004                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7005                Some((start..end, new_text))
 7006            })
 7007            .collect::<Vec<_>>();
 7008        if edits.is_empty() {
 7009            return None;
 7010        }
 7011
 7012        let first_edit_start = edits.first().unwrap().0.start;
 7013        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7014        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7015
 7016        let last_edit_end = edits.last().unwrap().0.end;
 7017        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7018        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7019
 7020        let cursor_row = cursor.to_point(&multibuffer).row;
 7021
 7022        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7023
 7024        let mut inlay_ids = Vec::new();
 7025        let invalidation_row_range;
 7026        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7027            Some(cursor_row..edit_end_row)
 7028        } else if cursor_row > edit_end_row {
 7029            Some(edit_start_row..cursor_row)
 7030        } else {
 7031            None
 7032        };
 7033        let is_move =
 7034            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7035        let completion = if is_move {
 7036            invalidation_row_range =
 7037                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7038            let target = first_edit_start;
 7039            InlineCompletion::Move { target, snapshot }
 7040        } else {
 7041            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7042                && !self.inline_completions_hidden_for_vim_mode;
 7043
 7044            if show_completions_in_buffer {
 7045                if edits
 7046                    .iter()
 7047                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7048                {
 7049                    let mut inlays = Vec::new();
 7050                    for (range, new_text) in &edits {
 7051                        let inlay = Inlay::inline_completion(
 7052                            post_inc(&mut self.next_inlay_id),
 7053                            range.start,
 7054                            new_text.as_str(),
 7055                        );
 7056                        inlay_ids.push(inlay.id);
 7057                        inlays.push(inlay);
 7058                    }
 7059
 7060                    self.splice_inlays(&[], inlays, cx);
 7061                } else {
 7062                    let background_color = cx.theme().status().deleted_background;
 7063                    self.highlight_text::<InlineCompletionHighlight>(
 7064                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7065                        HighlightStyle {
 7066                            background_color: Some(background_color),
 7067                            ..Default::default()
 7068                        },
 7069                        cx,
 7070                    );
 7071                }
 7072            }
 7073
 7074            invalidation_row_range = edit_start_row..edit_end_row;
 7075
 7076            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7077                if provider.show_tab_accept_marker() {
 7078                    EditDisplayMode::TabAccept
 7079                } else {
 7080                    EditDisplayMode::Inline
 7081                }
 7082            } else {
 7083                EditDisplayMode::DiffPopover
 7084            };
 7085
 7086            InlineCompletion::Edit {
 7087                edits,
 7088                edit_preview: inline_completion.edit_preview,
 7089                display_mode,
 7090                snapshot,
 7091            }
 7092        };
 7093
 7094        let invalidation_range = multibuffer
 7095            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7096            ..multibuffer.anchor_after(Point::new(
 7097                invalidation_row_range.end,
 7098                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7099            ));
 7100
 7101        self.stale_inline_completion_in_menu = None;
 7102        self.active_inline_completion = Some(InlineCompletionState {
 7103            inlay_ids,
 7104            completion,
 7105            completion_id: inline_completion.id,
 7106            invalidation_range,
 7107        });
 7108
 7109        cx.notify();
 7110
 7111        Some(())
 7112    }
 7113
 7114    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7115        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7116    }
 7117
 7118    fn clear_tasks(&mut self) {
 7119        self.tasks.clear()
 7120    }
 7121
 7122    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7123        if self.tasks.insert(key, value).is_some() {
 7124            // This case should hopefully be rare, but just in case...
 7125            log::error!(
 7126                "multiple different run targets found on a single line, only the last target will be rendered"
 7127            )
 7128        }
 7129    }
 7130
 7131    /// Get all display points of breakpoints that will be rendered within editor
 7132    ///
 7133    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7134    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7135    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7136    fn active_breakpoints(
 7137        &self,
 7138        range: Range<DisplayRow>,
 7139        window: &mut Window,
 7140        cx: &mut Context<Self>,
 7141    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7142        let mut breakpoint_display_points = HashMap::default();
 7143
 7144        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7145            return breakpoint_display_points;
 7146        };
 7147
 7148        let snapshot = self.snapshot(window, cx);
 7149
 7150        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7151        let Some(project) = self.project.as_ref() else {
 7152            return breakpoint_display_points;
 7153        };
 7154
 7155        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7156            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7157
 7158        for (buffer_snapshot, range, excerpt_id) in
 7159            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7160        {
 7161            let Some(buffer) = project
 7162                .read(cx)
 7163                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7164            else {
 7165                continue;
 7166            };
 7167            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7168                &buffer,
 7169                Some(
 7170                    buffer_snapshot.anchor_before(range.start)
 7171                        ..buffer_snapshot.anchor_after(range.end),
 7172                ),
 7173                buffer_snapshot,
 7174                cx,
 7175            );
 7176            for (breakpoint, state) in breakpoints {
 7177                let multi_buffer_anchor =
 7178                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7179                let position = multi_buffer_anchor
 7180                    .to_point(&multi_buffer_snapshot)
 7181                    .to_display_point(&snapshot);
 7182
 7183                breakpoint_display_points.insert(
 7184                    position.row(),
 7185                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7186                );
 7187            }
 7188        }
 7189
 7190        breakpoint_display_points
 7191    }
 7192
 7193    fn breakpoint_context_menu(
 7194        &self,
 7195        anchor: Anchor,
 7196        window: &mut Window,
 7197        cx: &mut Context<Self>,
 7198    ) -> Entity<ui::ContextMenu> {
 7199        let weak_editor = cx.weak_entity();
 7200        let focus_handle = self.focus_handle(cx);
 7201
 7202        let row = self
 7203            .buffer
 7204            .read(cx)
 7205            .snapshot(cx)
 7206            .summary_for_anchor::<Point>(&anchor)
 7207            .row;
 7208
 7209        let breakpoint = self
 7210            .breakpoint_at_row(row, window, cx)
 7211            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7212
 7213        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7214            "Edit Log Breakpoint"
 7215        } else {
 7216            "Set Log Breakpoint"
 7217        };
 7218
 7219        let condition_breakpoint_msg = if breakpoint
 7220            .as_ref()
 7221            .is_some_and(|bp| bp.1.condition.is_some())
 7222        {
 7223            "Edit Condition Breakpoint"
 7224        } else {
 7225            "Set Condition Breakpoint"
 7226        };
 7227
 7228        let hit_condition_breakpoint_msg = if breakpoint
 7229            .as_ref()
 7230            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7231        {
 7232            "Edit Hit Condition Breakpoint"
 7233        } else {
 7234            "Set Hit Condition Breakpoint"
 7235        };
 7236
 7237        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7238            "Unset Breakpoint"
 7239        } else {
 7240            "Set Breakpoint"
 7241        };
 7242
 7243        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7244            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7245
 7246        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7247            BreakpointState::Enabled => Some("Disable"),
 7248            BreakpointState::Disabled => Some("Enable"),
 7249        });
 7250
 7251        let (anchor, breakpoint) =
 7252            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7253
 7254        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7255            menu.on_blur_subscription(Subscription::new(|| {}))
 7256                .context(focus_handle)
 7257                .when(run_to_cursor, |this| {
 7258                    let weak_editor = weak_editor.clone();
 7259                    this.entry("Run to cursor", None, move |window, cx| {
 7260                        weak_editor
 7261                            .update(cx, |editor, cx| {
 7262                                editor.change_selections(None, window, cx, |s| {
 7263                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7264                                });
 7265                            })
 7266                            .ok();
 7267
 7268                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7269                    })
 7270                    .separator()
 7271                })
 7272                .when_some(toggle_state_msg, |this, msg| {
 7273                    this.entry(msg, None, {
 7274                        let weak_editor = weak_editor.clone();
 7275                        let breakpoint = breakpoint.clone();
 7276                        move |_window, cx| {
 7277                            weak_editor
 7278                                .update(cx, |this, cx| {
 7279                                    this.edit_breakpoint_at_anchor(
 7280                                        anchor,
 7281                                        breakpoint.as_ref().clone(),
 7282                                        BreakpointEditAction::InvertState,
 7283                                        cx,
 7284                                    );
 7285                                })
 7286                                .log_err();
 7287                        }
 7288                    })
 7289                })
 7290                .entry(set_breakpoint_msg, None, {
 7291                    let weak_editor = weak_editor.clone();
 7292                    let breakpoint = breakpoint.clone();
 7293                    move |_window, cx| {
 7294                        weak_editor
 7295                            .update(cx, |this, cx| {
 7296                                this.edit_breakpoint_at_anchor(
 7297                                    anchor,
 7298                                    breakpoint.as_ref().clone(),
 7299                                    BreakpointEditAction::Toggle,
 7300                                    cx,
 7301                                );
 7302                            })
 7303                            .log_err();
 7304                    }
 7305                })
 7306                .entry(log_breakpoint_msg, None, {
 7307                    let breakpoint = breakpoint.clone();
 7308                    let weak_editor = weak_editor.clone();
 7309                    move |window, cx| {
 7310                        weak_editor
 7311                            .update(cx, |this, cx| {
 7312                                this.add_edit_breakpoint_block(
 7313                                    anchor,
 7314                                    breakpoint.as_ref(),
 7315                                    BreakpointPromptEditAction::Log,
 7316                                    window,
 7317                                    cx,
 7318                                );
 7319                            })
 7320                            .log_err();
 7321                    }
 7322                })
 7323                .entry(condition_breakpoint_msg, None, {
 7324                    let breakpoint = breakpoint.clone();
 7325                    let weak_editor = weak_editor.clone();
 7326                    move |window, cx| {
 7327                        weak_editor
 7328                            .update(cx, |this, cx| {
 7329                                this.add_edit_breakpoint_block(
 7330                                    anchor,
 7331                                    breakpoint.as_ref(),
 7332                                    BreakpointPromptEditAction::Condition,
 7333                                    window,
 7334                                    cx,
 7335                                );
 7336                            })
 7337                            .log_err();
 7338                    }
 7339                })
 7340                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7341                    weak_editor
 7342                        .update(cx, |this, cx| {
 7343                            this.add_edit_breakpoint_block(
 7344                                anchor,
 7345                                breakpoint.as_ref(),
 7346                                BreakpointPromptEditAction::HitCondition,
 7347                                window,
 7348                                cx,
 7349                            );
 7350                        })
 7351                        .log_err();
 7352                })
 7353        })
 7354    }
 7355
 7356    fn render_breakpoint(
 7357        &self,
 7358        position: Anchor,
 7359        row: DisplayRow,
 7360        breakpoint: &Breakpoint,
 7361        state: Option<BreakpointSessionState>,
 7362        cx: &mut Context<Self>,
 7363    ) -> IconButton {
 7364        let is_rejected = state.is_some_and(|s| !s.verified);
 7365        // Is it a breakpoint that shows up when hovering over gutter?
 7366        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7367            (false, false),
 7368            |PhantomBreakpointIndicator {
 7369                 is_active,
 7370                 display_row,
 7371                 collides_with_existing_breakpoint,
 7372             }| {
 7373                (
 7374                    is_active && display_row == row,
 7375                    collides_with_existing_breakpoint,
 7376                )
 7377            },
 7378        );
 7379
 7380        let (color, icon) = {
 7381            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7382                (false, false) => ui::IconName::DebugBreakpoint,
 7383                (true, false) => ui::IconName::DebugLogBreakpoint,
 7384                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7385                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7386            };
 7387
 7388            let color = if is_phantom {
 7389                Color::Hint
 7390            } else if is_rejected {
 7391                Color::Disabled
 7392            } else {
 7393                Color::Debugger
 7394            };
 7395
 7396            (color, icon)
 7397        };
 7398
 7399        let breakpoint = Arc::from(breakpoint.clone());
 7400
 7401        let alt_as_text = gpui::Keystroke {
 7402            modifiers: Modifiers::secondary_key(),
 7403            ..Default::default()
 7404        };
 7405        let primary_action_text = if breakpoint.is_disabled() {
 7406            "Enable breakpoint"
 7407        } else if is_phantom && !collides_with_existing {
 7408            "Set breakpoint"
 7409        } else {
 7410            "Unset breakpoint"
 7411        };
 7412        let focus_handle = self.focus_handle.clone();
 7413
 7414        let meta = if is_rejected {
 7415            SharedString::from("No executable code is associated with this line.")
 7416        } else if collides_with_existing && !breakpoint.is_disabled() {
 7417            SharedString::from(format!(
 7418                "{alt_as_text}-click to disable,\nright-click for more options."
 7419            ))
 7420        } else {
 7421            SharedString::from("Right-click for more options.")
 7422        };
 7423        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7424            .icon_size(IconSize::XSmall)
 7425            .size(ui::ButtonSize::None)
 7426            .when(is_rejected, |this| {
 7427                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7428            })
 7429            .icon_color(color)
 7430            .style(ButtonStyle::Transparent)
 7431            .on_click(cx.listener({
 7432                let breakpoint = breakpoint.clone();
 7433
 7434                move |editor, event: &ClickEvent, window, cx| {
 7435                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7436                        BreakpointEditAction::InvertState
 7437                    } else {
 7438                        BreakpointEditAction::Toggle
 7439                    };
 7440
 7441                    window.focus(&editor.focus_handle(cx));
 7442                    editor.edit_breakpoint_at_anchor(
 7443                        position,
 7444                        breakpoint.as_ref().clone(),
 7445                        edit_action,
 7446                        cx,
 7447                    );
 7448                }
 7449            }))
 7450            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7451                editor.set_breakpoint_context_menu(
 7452                    row,
 7453                    Some(position),
 7454                    event.down.position,
 7455                    window,
 7456                    cx,
 7457                );
 7458            }))
 7459            .tooltip(move |window, cx| {
 7460                Tooltip::with_meta_in(
 7461                    primary_action_text,
 7462                    Some(&ToggleBreakpoint),
 7463                    meta.clone(),
 7464                    &focus_handle,
 7465                    window,
 7466                    cx,
 7467                )
 7468            })
 7469    }
 7470
 7471    fn build_tasks_context(
 7472        project: &Entity<Project>,
 7473        buffer: &Entity<Buffer>,
 7474        buffer_row: u32,
 7475        tasks: &Arc<RunnableTasks>,
 7476        cx: &mut Context<Self>,
 7477    ) -> Task<Option<task::TaskContext>> {
 7478        let position = Point::new(buffer_row, tasks.column);
 7479        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7480        let location = Location {
 7481            buffer: buffer.clone(),
 7482            range: range_start..range_start,
 7483        };
 7484        // Fill in the environmental variables from the tree-sitter captures
 7485        let mut captured_task_variables = TaskVariables::default();
 7486        for (capture_name, value) in tasks.extra_variables.clone() {
 7487            captured_task_variables.insert(
 7488                task::VariableName::Custom(capture_name.into()),
 7489                value.clone(),
 7490            );
 7491        }
 7492        project.update(cx, |project, cx| {
 7493            project.task_store().update(cx, |task_store, cx| {
 7494                task_store.task_context_for_location(captured_task_variables, location, cx)
 7495            })
 7496        })
 7497    }
 7498
 7499    pub fn spawn_nearest_task(
 7500        &mut self,
 7501        action: &SpawnNearestTask,
 7502        window: &mut Window,
 7503        cx: &mut Context<Self>,
 7504    ) {
 7505        let Some((workspace, _)) = self.workspace.clone() else {
 7506            return;
 7507        };
 7508        let Some(project) = self.project.clone() else {
 7509            return;
 7510        };
 7511
 7512        // Try to find a closest, enclosing node using tree-sitter that has a
 7513        // task
 7514        let Some((buffer, buffer_row, tasks)) = self
 7515            .find_enclosing_node_task(cx)
 7516            // Or find the task that's closest in row-distance.
 7517            .or_else(|| self.find_closest_task(cx))
 7518        else {
 7519            return;
 7520        };
 7521
 7522        let reveal_strategy = action.reveal;
 7523        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7524        cx.spawn_in(window, async move |_, cx| {
 7525            let context = task_context.await?;
 7526            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7527
 7528            let resolved = &mut resolved_task.resolved;
 7529            resolved.reveal = reveal_strategy;
 7530
 7531            workspace
 7532                .update_in(cx, |workspace, window, cx| {
 7533                    workspace.schedule_resolved_task(
 7534                        task_source_kind,
 7535                        resolved_task,
 7536                        false,
 7537                        window,
 7538                        cx,
 7539                    );
 7540                })
 7541                .ok()
 7542        })
 7543        .detach();
 7544    }
 7545
 7546    fn find_closest_task(
 7547        &mut self,
 7548        cx: &mut Context<Self>,
 7549    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7550        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7551
 7552        let ((buffer_id, row), tasks) = self
 7553            .tasks
 7554            .iter()
 7555            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7556
 7557        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7558        let tasks = Arc::new(tasks.to_owned());
 7559        Some((buffer, *row, tasks))
 7560    }
 7561
 7562    fn find_enclosing_node_task(
 7563        &mut self,
 7564        cx: &mut Context<Self>,
 7565    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7566        let snapshot = self.buffer.read(cx).snapshot(cx);
 7567        let offset = self.selections.newest::<usize>(cx).head();
 7568        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7569        let buffer_id = excerpt.buffer().remote_id();
 7570
 7571        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7572        let mut cursor = layer.node().walk();
 7573
 7574        while cursor.goto_first_child_for_byte(offset).is_some() {
 7575            if cursor.node().end_byte() == offset {
 7576                cursor.goto_next_sibling();
 7577            }
 7578        }
 7579
 7580        // Ascend to the smallest ancestor that contains the range and has a task.
 7581        loop {
 7582            let node = cursor.node();
 7583            let node_range = node.byte_range();
 7584            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7585
 7586            // Check if this node contains our offset
 7587            if node_range.start <= offset && node_range.end >= offset {
 7588                // If it contains offset, check for task
 7589                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7590                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7591                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7592                }
 7593            }
 7594
 7595            if !cursor.goto_parent() {
 7596                break;
 7597            }
 7598        }
 7599        None
 7600    }
 7601
 7602    fn render_run_indicator(
 7603        &self,
 7604        _style: &EditorStyle,
 7605        is_active: bool,
 7606        row: DisplayRow,
 7607        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7608        cx: &mut Context<Self>,
 7609    ) -> IconButton {
 7610        let color = Color::Muted;
 7611        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7612
 7613        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7614            .shape(ui::IconButtonShape::Square)
 7615            .icon_size(IconSize::XSmall)
 7616            .icon_color(color)
 7617            .toggle_state(is_active)
 7618            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7619                let quick_launch = e.down.button == MouseButton::Left;
 7620                window.focus(&editor.focus_handle(cx));
 7621                editor.toggle_code_actions(
 7622                    &ToggleCodeActions {
 7623                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7624                        quick_launch,
 7625                    },
 7626                    window,
 7627                    cx,
 7628                );
 7629            }))
 7630            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7631                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7632            }))
 7633    }
 7634
 7635    pub fn context_menu_visible(&self) -> bool {
 7636        !self.edit_prediction_preview_is_active()
 7637            && self
 7638                .context_menu
 7639                .borrow()
 7640                .as_ref()
 7641                .map_or(false, |menu| menu.visible())
 7642    }
 7643
 7644    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7645        self.context_menu
 7646            .borrow()
 7647            .as_ref()
 7648            .map(|menu| menu.origin())
 7649    }
 7650
 7651    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7652        self.context_menu_options = Some(options);
 7653    }
 7654
 7655    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7656    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7657
 7658    fn render_edit_prediction_popover(
 7659        &mut self,
 7660        text_bounds: &Bounds<Pixels>,
 7661        content_origin: gpui::Point<Pixels>,
 7662        right_margin: Pixels,
 7663        editor_snapshot: &EditorSnapshot,
 7664        visible_row_range: Range<DisplayRow>,
 7665        scroll_top: f32,
 7666        scroll_bottom: f32,
 7667        line_layouts: &[LineWithInvisibles],
 7668        line_height: Pixels,
 7669        scroll_pixel_position: gpui::Point<Pixels>,
 7670        newest_selection_head: Option<DisplayPoint>,
 7671        editor_width: Pixels,
 7672        style: &EditorStyle,
 7673        window: &mut Window,
 7674        cx: &mut App,
 7675    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7676        if self.mode().is_minimap() {
 7677            return None;
 7678        }
 7679        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7680
 7681        if self.edit_prediction_visible_in_cursor_popover(true) {
 7682            return None;
 7683        }
 7684
 7685        match &active_inline_completion.completion {
 7686            InlineCompletion::Move { target, .. } => {
 7687                let target_display_point = target.to_display_point(editor_snapshot);
 7688
 7689                if self.edit_prediction_requires_modifier() {
 7690                    if !self.edit_prediction_preview_is_active() {
 7691                        return None;
 7692                    }
 7693
 7694                    self.render_edit_prediction_modifier_jump_popover(
 7695                        text_bounds,
 7696                        content_origin,
 7697                        visible_row_range,
 7698                        line_layouts,
 7699                        line_height,
 7700                        scroll_pixel_position,
 7701                        newest_selection_head,
 7702                        target_display_point,
 7703                        window,
 7704                        cx,
 7705                    )
 7706                } else {
 7707                    self.render_edit_prediction_eager_jump_popover(
 7708                        text_bounds,
 7709                        content_origin,
 7710                        editor_snapshot,
 7711                        visible_row_range,
 7712                        scroll_top,
 7713                        scroll_bottom,
 7714                        line_height,
 7715                        scroll_pixel_position,
 7716                        target_display_point,
 7717                        editor_width,
 7718                        window,
 7719                        cx,
 7720                    )
 7721                }
 7722            }
 7723            InlineCompletion::Edit {
 7724                display_mode: EditDisplayMode::Inline,
 7725                ..
 7726            } => None,
 7727            InlineCompletion::Edit {
 7728                display_mode: EditDisplayMode::TabAccept,
 7729                edits,
 7730                ..
 7731            } => {
 7732                let range = &edits.first()?.0;
 7733                let target_display_point = range.end.to_display_point(editor_snapshot);
 7734
 7735                self.render_edit_prediction_end_of_line_popover(
 7736                    "Accept",
 7737                    editor_snapshot,
 7738                    visible_row_range,
 7739                    target_display_point,
 7740                    line_height,
 7741                    scroll_pixel_position,
 7742                    content_origin,
 7743                    editor_width,
 7744                    window,
 7745                    cx,
 7746                )
 7747            }
 7748            InlineCompletion::Edit {
 7749                edits,
 7750                edit_preview,
 7751                display_mode: EditDisplayMode::DiffPopover,
 7752                snapshot,
 7753            } => self.render_edit_prediction_diff_popover(
 7754                text_bounds,
 7755                content_origin,
 7756                right_margin,
 7757                editor_snapshot,
 7758                visible_row_range,
 7759                line_layouts,
 7760                line_height,
 7761                scroll_pixel_position,
 7762                newest_selection_head,
 7763                editor_width,
 7764                style,
 7765                edits,
 7766                edit_preview,
 7767                snapshot,
 7768                window,
 7769                cx,
 7770            ),
 7771        }
 7772    }
 7773
 7774    fn render_edit_prediction_modifier_jump_popover(
 7775        &mut self,
 7776        text_bounds: &Bounds<Pixels>,
 7777        content_origin: gpui::Point<Pixels>,
 7778        visible_row_range: Range<DisplayRow>,
 7779        line_layouts: &[LineWithInvisibles],
 7780        line_height: Pixels,
 7781        scroll_pixel_position: gpui::Point<Pixels>,
 7782        newest_selection_head: Option<DisplayPoint>,
 7783        target_display_point: DisplayPoint,
 7784        window: &mut Window,
 7785        cx: &mut App,
 7786    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7787        let scrolled_content_origin =
 7788            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7789
 7790        const SCROLL_PADDING_Y: Pixels = px(12.);
 7791
 7792        if target_display_point.row() < visible_row_range.start {
 7793            return self.render_edit_prediction_scroll_popover(
 7794                |_| SCROLL_PADDING_Y,
 7795                IconName::ArrowUp,
 7796                visible_row_range,
 7797                line_layouts,
 7798                newest_selection_head,
 7799                scrolled_content_origin,
 7800                window,
 7801                cx,
 7802            );
 7803        } else if target_display_point.row() >= visible_row_range.end {
 7804            return self.render_edit_prediction_scroll_popover(
 7805                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7806                IconName::ArrowDown,
 7807                visible_row_range,
 7808                line_layouts,
 7809                newest_selection_head,
 7810                scrolled_content_origin,
 7811                window,
 7812                cx,
 7813            );
 7814        }
 7815
 7816        const POLE_WIDTH: Pixels = px(2.);
 7817
 7818        let line_layout =
 7819            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7820        let target_column = target_display_point.column() as usize;
 7821
 7822        let target_x = line_layout.x_for_index(target_column);
 7823        let target_y =
 7824            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7825
 7826        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7827
 7828        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7829        border_color.l += 0.001;
 7830
 7831        let mut element = v_flex()
 7832            .items_end()
 7833            .when(flag_on_right, |el| el.items_start())
 7834            .child(if flag_on_right {
 7835                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7836                    .rounded_bl(px(0.))
 7837                    .rounded_tl(px(0.))
 7838                    .border_l_2()
 7839                    .border_color(border_color)
 7840            } else {
 7841                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7842                    .rounded_br(px(0.))
 7843                    .rounded_tr(px(0.))
 7844                    .border_r_2()
 7845                    .border_color(border_color)
 7846            })
 7847            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7848            .into_any();
 7849
 7850        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7851
 7852        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7853            - point(
 7854                if flag_on_right {
 7855                    POLE_WIDTH
 7856                } else {
 7857                    size.width - POLE_WIDTH
 7858                },
 7859                size.height - line_height,
 7860            );
 7861
 7862        origin.x = origin.x.max(content_origin.x);
 7863
 7864        element.prepaint_at(origin, window, cx);
 7865
 7866        Some((element, origin))
 7867    }
 7868
 7869    fn render_edit_prediction_scroll_popover(
 7870        &mut self,
 7871        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7872        scroll_icon: IconName,
 7873        visible_row_range: Range<DisplayRow>,
 7874        line_layouts: &[LineWithInvisibles],
 7875        newest_selection_head: Option<DisplayPoint>,
 7876        scrolled_content_origin: gpui::Point<Pixels>,
 7877        window: &mut Window,
 7878        cx: &mut App,
 7879    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7880        let mut element = self
 7881            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7882            .into_any();
 7883
 7884        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7885
 7886        let cursor = newest_selection_head?;
 7887        let cursor_row_layout =
 7888            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7889        let cursor_column = cursor.column() as usize;
 7890
 7891        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7892
 7893        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7894
 7895        element.prepaint_at(origin, window, cx);
 7896        Some((element, origin))
 7897    }
 7898
 7899    fn render_edit_prediction_eager_jump_popover(
 7900        &mut self,
 7901        text_bounds: &Bounds<Pixels>,
 7902        content_origin: gpui::Point<Pixels>,
 7903        editor_snapshot: &EditorSnapshot,
 7904        visible_row_range: Range<DisplayRow>,
 7905        scroll_top: f32,
 7906        scroll_bottom: f32,
 7907        line_height: Pixels,
 7908        scroll_pixel_position: gpui::Point<Pixels>,
 7909        target_display_point: DisplayPoint,
 7910        editor_width: Pixels,
 7911        window: &mut Window,
 7912        cx: &mut App,
 7913    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7914        if target_display_point.row().as_f32() < scroll_top {
 7915            let mut element = self
 7916                .render_edit_prediction_line_popover(
 7917                    "Jump to Edit",
 7918                    Some(IconName::ArrowUp),
 7919                    window,
 7920                    cx,
 7921                )?
 7922                .into_any();
 7923
 7924            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7925            let offset = point(
 7926                (text_bounds.size.width - size.width) / 2.,
 7927                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7928            );
 7929
 7930            let origin = text_bounds.origin + offset;
 7931            element.prepaint_at(origin, window, cx);
 7932            Some((element, origin))
 7933        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7934            let mut element = self
 7935                .render_edit_prediction_line_popover(
 7936                    "Jump to Edit",
 7937                    Some(IconName::ArrowDown),
 7938                    window,
 7939                    cx,
 7940                )?
 7941                .into_any();
 7942
 7943            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7944            let offset = point(
 7945                (text_bounds.size.width - size.width) / 2.,
 7946                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7947            );
 7948
 7949            let origin = text_bounds.origin + offset;
 7950            element.prepaint_at(origin, window, cx);
 7951            Some((element, origin))
 7952        } else {
 7953            self.render_edit_prediction_end_of_line_popover(
 7954                "Jump to Edit",
 7955                editor_snapshot,
 7956                visible_row_range,
 7957                target_display_point,
 7958                line_height,
 7959                scroll_pixel_position,
 7960                content_origin,
 7961                editor_width,
 7962                window,
 7963                cx,
 7964            )
 7965        }
 7966    }
 7967
 7968    fn render_edit_prediction_end_of_line_popover(
 7969        self: &mut Editor,
 7970        label: &'static str,
 7971        editor_snapshot: &EditorSnapshot,
 7972        visible_row_range: Range<DisplayRow>,
 7973        target_display_point: DisplayPoint,
 7974        line_height: Pixels,
 7975        scroll_pixel_position: gpui::Point<Pixels>,
 7976        content_origin: gpui::Point<Pixels>,
 7977        editor_width: Pixels,
 7978        window: &mut Window,
 7979        cx: &mut App,
 7980    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7981        let target_line_end = DisplayPoint::new(
 7982            target_display_point.row(),
 7983            editor_snapshot.line_len(target_display_point.row()),
 7984        );
 7985
 7986        let mut element = self
 7987            .render_edit_prediction_line_popover(label, None, window, cx)?
 7988            .into_any();
 7989
 7990        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7991
 7992        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7993
 7994        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7995        let mut origin = start_point
 7996            + line_origin
 7997            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7998        origin.x = origin.x.max(content_origin.x);
 7999
 8000        let max_x = content_origin.x + editor_width - size.width;
 8001
 8002        if origin.x > max_x {
 8003            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8004
 8005            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8006                origin.y += offset;
 8007                IconName::ArrowUp
 8008            } else {
 8009                origin.y -= offset;
 8010                IconName::ArrowDown
 8011            };
 8012
 8013            element = self
 8014                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8015                .into_any();
 8016
 8017            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8018
 8019            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8020        }
 8021
 8022        element.prepaint_at(origin, window, cx);
 8023        Some((element, origin))
 8024    }
 8025
 8026    fn render_edit_prediction_diff_popover(
 8027        self: &Editor,
 8028        text_bounds: &Bounds<Pixels>,
 8029        content_origin: gpui::Point<Pixels>,
 8030        right_margin: Pixels,
 8031        editor_snapshot: &EditorSnapshot,
 8032        visible_row_range: Range<DisplayRow>,
 8033        line_layouts: &[LineWithInvisibles],
 8034        line_height: Pixels,
 8035        scroll_pixel_position: gpui::Point<Pixels>,
 8036        newest_selection_head: Option<DisplayPoint>,
 8037        editor_width: Pixels,
 8038        style: &EditorStyle,
 8039        edits: &Vec<(Range<Anchor>, String)>,
 8040        edit_preview: &Option<language::EditPreview>,
 8041        snapshot: &language::BufferSnapshot,
 8042        window: &mut Window,
 8043        cx: &mut App,
 8044    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8045        let edit_start = edits
 8046            .first()
 8047            .unwrap()
 8048            .0
 8049            .start
 8050            .to_display_point(editor_snapshot);
 8051        let edit_end = edits
 8052            .last()
 8053            .unwrap()
 8054            .0
 8055            .end
 8056            .to_display_point(editor_snapshot);
 8057
 8058        let is_visible = visible_row_range.contains(&edit_start.row())
 8059            || visible_row_range.contains(&edit_end.row());
 8060        if !is_visible {
 8061            return None;
 8062        }
 8063
 8064        let highlighted_edits =
 8065            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8066
 8067        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8068        let line_count = highlighted_edits.text.lines().count();
 8069
 8070        const BORDER_WIDTH: Pixels = px(1.);
 8071
 8072        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8073        let has_keybind = keybind.is_some();
 8074
 8075        let mut element = h_flex()
 8076            .items_start()
 8077            .child(
 8078                h_flex()
 8079                    .bg(cx.theme().colors().editor_background)
 8080                    .border(BORDER_WIDTH)
 8081                    .shadow_sm()
 8082                    .border_color(cx.theme().colors().border)
 8083                    .rounded_l_lg()
 8084                    .when(line_count > 1, |el| el.rounded_br_lg())
 8085                    .pr_1()
 8086                    .child(styled_text),
 8087            )
 8088            .child(
 8089                h_flex()
 8090                    .h(line_height + BORDER_WIDTH * 2.)
 8091                    .px_1p5()
 8092                    .gap_1()
 8093                    // Workaround: For some reason, there's a gap if we don't do this
 8094                    .ml(-BORDER_WIDTH)
 8095                    .shadow(vec![gpui::BoxShadow {
 8096                        color: gpui::black().opacity(0.05),
 8097                        offset: point(px(1.), px(1.)),
 8098                        blur_radius: px(2.),
 8099                        spread_radius: px(0.),
 8100                    }])
 8101                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8102                    .border(BORDER_WIDTH)
 8103                    .border_color(cx.theme().colors().border)
 8104                    .rounded_r_lg()
 8105                    .id("edit_prediction_diff_popover_keybind")
 8106                    .when(!has_keybind, |el| {
 8107                        let status_colors = cx.theme().status();
 8108
 8109                        el.bg(status_colors.error_background)
 8110                            .border_color(status_colors.error.opacity(0.6))
 8111                            .child(Icon::new(IconName::Info).color(Color::Error))
 8112                            .cursor_default()
 8113                            .hoverable_tooltip(move |_window, cx| {
 8114                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8115                            })
 8116                    })
 8117                    .children(keybind),
 8118            )
 8119            .into_any();
 8120
 8121        let longest_row =
 8122            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8123        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8124            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8125        } else {
 8126            layout_line(
 8127                longest_row,
 8128                editor_snapshot,
 8129                style,
 8130                editor_width,
 8131                |_| false,
 8132                window,
 8133                cx,
 8134            )
 8135            .width
 8136        };
 8137
 8138        let viewport_bounds =
 8139            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8140                right: -right_margin,
 8141                ..Default::default()
 8142            });
 8143
 8144        let x_after_longest =
 8145            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8146                - scroll_pixel_position.x;
 8147
 8148        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8149
 8150        // Fully visible if it can be displayed within the window (allow overlapping other
 8151        // panes). However, this is only allowed if the popover starts within text_bounds.
 8152        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8153            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8154
 8155        let mut origin = if can_position_to_the_right {
 8156            point(
 8157                x_after_longest,
 8158                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8159                    - scroll_pixel_position.y,
 8160            )
 8161        } else {
 8162            let cursor_row = newest_selection_head.map(|head| head.row());
 8163            let above_edit = edit_start
 8164                .row()
 8165                .0
 8166                .checked_sub(line_count as u32)
 8167                .map(DisplayRow);
 8168            let below_edit = Some(edit_end.row() + 1);
 8169            let above_cursor =
 8170                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8171            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8172
 8173            // Place the edit popover adjacent to the edit if there is a location
 8174            // available that is onscreen and does not obscure the cursor. Otherwise,
 8175            // place it adjacent to the cursor.
 8176            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8177                .into_iter()
 8178                .flatten()
 8179                .find(|&start_row| {
 8180                    let end_row = start_row + line_count as u32;
 8181                    visible_row_range.contains(&start_row)
 8182                        && visible_row_range.contains(&end_row)
 8183                        && cursor_row.map_or(true, |cursor_row| {
 8184                            !((start_row..end_row).contains(&cursor_row))
 8185                        })
 8186                })?;
 8187
 8188            content_origin
 8189                + point(
 8190                    -scroll_pixel_position.x,
 8191                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8192                )
 8193        };
 8194
 8195        origin.x -= BORDER_WIDTH;
 8196
 8197        window.defer_draw(element, origin, 1);
 8198
 8199        // Do not return an element, since it will already be drawn due to defer_draw.
 8200        None
 8201    }
 8202
 8203    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8204        px(30.)
 8205    }
 8206
 8207    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8208        if self.read_only(cx) {
 8209            cx.theme().players().read_only()
 8210        } else {
 8211            self.style.as_ref().unwrap().local_player
 8212        }
 8213    }
 8214
 8215    fn render_edit_prediction_accept_keybind(
 8216        &self,
 8217        window: &mut Window,
 8218        cx: &App,
 8219    ) -> Option<AnyElement> {
 8220        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8221        let accept_keystroke = accept_binding.keystroke()?;
 8222
 8223        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8224
 8225        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8226            Color::Accent
 8227        } else {
 8228            Color::Muted
 8229        };
 8230
 8231        h_flex()
 8232            .px_0p5()
 8233            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8234            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8235            .text_size(TextSize::XSmall.rems(cx))
 8236            .child(h_flex().children(ui::render_modifiers(
 8237                &accept_keystroke.modifiers,
 8238                PlatformStyle::platform(),
 8239                Some(modifiers_color),
 8240                Some(IconSize::XSmall.rems().into()),
 8241                true,
 8242            )))
 8243            .when(is_platform_style_mac, |parent| {
 8244                parent.child(accept_keystroke.key.clone())
 8245            })
 8246            .when(!is_platform_style_mac, |parent| {
 8247                parent.child(
 8248                    Key::new(
 8249                        util::capitalize(&accept_keystroke.key),
 8250                        Some(Color::Default),
 8251                    )
 8252                    .size(Some(IconSize::XSmall.rems().into())),
 8253                )
 8254            })
 8255            .into_any()
 8256            .into()
 8257    }
 8258
 8259    fn render_edit_prediction_line_popover(
 8260        &self,
 8261        label: impl Into<SharedString>,
 8262        icon: Option<IconName>,
 8263        window: &mut Window,
 8264        cx: &App,
 8265    ) -> Option<Stateful<Div>> {
 8266        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8267
 8268        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8269        let has_keybind = keybind.is_some();
 8270
 8271        let result = h_flex()
 8272            .id("ep-line-popover")
 8273            .py_0p5()
 8274            .pl_1()
 8275            .pr(padding_right)
 8276            .gap_1()
 8277            .rounded_md()
 8278            .border_1()
 8279            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8280            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8281            .shadow_sm()
 8282            .when(!has_keybind, |el| {
 8283                let status_colors = cx.theme().status();
 8284
 8285                el.bg(status_colors.error_background)
 8286                    .border_color(status_colors.error.opacity(0.6))
 8287                    .pl_2()
 8288                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8289                    .cursor_default()
 8290                    .hoverable_tooltip(move |_window, cx| {
 8291                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8292                    })
 8293            })
 8294            .children(keybind)
 8295            .child(
 8296                Label::new(label)
 8297                    .size(LabelSize::Small)
 8298                    .when(!has_keybind, |el| {
 8299                        el.color(cx.theme().status().error.into()).strikethrough()
 8300                    }),
 8301            )
 8302            .when(!has_keybind, |el| {
 8303                el.child(
 8304                    h_flex().ml_1().child(
 8305                        Icon::new(IconName::Info)
 8306                            .size(IconSize::Small)
 8307                            .color(cx.theme().status().error.into()),
 8308                    ),
 8309                )
 8310            })
 8311            .when_some(icon, |element, icon| {
 8312                element.child(
 8313                    div()
 8314                        .mt(px(1.5))
 8315                        .child(Icon::new(icon).size(IconSize::Small)),
 8316                )
 8317            });
 8318
 8319        Some(result)
 8320    }
 8321
 8322    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8323        let accent_color = cx.theme().colors().text_accent;
 8324        let editor_bg_color = cx.theme().colors().editor_background;
 8325        editor_bg_color.blend(accent_color.opacity(0.1))
 8326    }
 8327
 8328    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8329        let accent_color = cx.theme().colors().text_accent;
 8330        let editor_bg_color = cx.theme().colors().editor_background;
 8331        editor_bg_color.blend(accent_color.opacity(0.6))
 8332    }
 8333
 8334    fn render_edit_prediction_cursor_popover(
 8335        &self,
 8336        min_width: Pixels,
 8337        max_width: Pixels,
 8338        cursor_point: Point,
 8339        style: &EditorStyle,
 8340        accept_keystroke: Option<&gpui::Keystroke>,
 8341        _window: &Window,
 8342        cx: &mut Context<Editor>,
 8343    ) -> Option<AnyElement> {
 8344        let provider = self.edit_prediction_provider.as_ref()?;
 8345
 8346        if provider.provider.needs_terms_acceptance(cx) {
 8347            return Some(
 8348                h_flex()
 8349                    .min_w(min_width)
 8350                    .flex_1()
 8351                    .px_2()
 8352                    .py_1()
 8353                    .gap_3()
 8354                    .elevation_2(cx)
 8355                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8356                    .id("accept-terms")
 8357                    .cursor_pointer()
 8358                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8359                    .on_click(cx.listener(|this, _event, window, cx| {
 8360                        cx.stop_propagation();
 8361                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8362                        window.dispatch_action(
 8363                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8364                            cx,
 8365                        );
 8366                    }))
 8367                    .child(
 8368                        h_flex()
 8369                            .flex_1()
 8370                            .gap_2()
 8371                            .child(Icon::new(IconName::ZedPredict))
 8372                            .child(Label::new("Accept Terms of Service"))
 8373                            .child(div().w_full())
 8374                            .child(
 8375                                Icon::new(IconName::ArrowUpRight)
 8376                                    .color(Color::Muted)
 8377                                    .size(IconSize::Small),
 8378                            )
 8379                            .into_any_element(),
 8380                    )
 8381                    .into_any(),
 8382            );
 8383        }
 8384
 8385        let is_refreshing = provider.provider.is_refreshing(cx);
 8386
 8387        fn pending_completion_container() -> Div {
 8388            h_flex()
 8389                .h_full()
 8390                .flex_1()
 8391                .gap_2()
 8392                .child(Icon::new(IconName::ZedPredict))
 8393        }
 8394
 8395        let completion = match &self.active_inline_completion {
 8396            Some(prediction) => {
 8397                if !self.has_visible_completions_menu() {
 8398                    const RADIUS: Pixels = px(6.);
 8399                    const BORDER_WIDTH: Pixels = px(1.);
 8400
 8401                    return Some(
 8402                        h_flex()
 8403                            .elevation_2(cx)
 8404                            .border(BORDER_WIDTH)
 8405                            .border_color(cx.theme().colors().border)
 8406                            .when(accept_keystroke.is_none(), |el| {
 8407                                el.border_color(cx.theme().status().error)
 8408                            })
 8409                            .rounded(RADIUS)
 8410                            .rounded_tl(px(0.))
 8411                            .overflow_hidden()
 8412                            .child(div().px_1p5().child(match &prediction.completion {
 8413                                InlineCompletion::Move { target, snapshot } => {
 8414                                    use text::ToPoint as _;
 8415                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8416                                    {
 8417                                        Icon::new(IconName::ZedPredictDown)
 8418                                    } else {
 8419                                        Icon::new(IconName::ZedPredictUp)
 8420                                    }
 8421                                }
 8422                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8423                            }))
 8424                            .child(
 8425                                h_flex()
 8426                                    .gap_1()
 8427                                    .py_1()
 8428                                    .px_2()
 8429                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8430                                    .border_l_1()
 8431                                    .border_color(cx.theme().colors().border)
 8432                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8433                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8434                                        el.child(
 8435                                            Label::new("Hold")
 8436                                                .size(LabelSize::Small)
 8437                                                .when(accept_keystroke.is_none(), |el| {
 8438                                                    el.strikethrough()
 8439                                                })
 8440                                                .line_height_style(LineHeightStyle::UiLabel),
 8441                                        )
 8442                                    })
 8443                                    .id("edit_prediction_cursor_popover_keybind")
 8444                                    .when(accept_keystroke.is_none(), |el| {
 8445                                        let status_colors = cx.theme().status();
 8446
 8447                                        el.bg(status_colors.error_background)
 8448                                            .border_color(status_colors.error.opacity(0.6))
 8449                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8450                                            .cursor_default()
 8451                                            .hoverable_tooltip(move |_window, cx| {
 8452                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8453                                                    .into()
 8454                                            })
 8455                                    })
 8456                                    .when_some(
 8457                                        accept_keystroke.as_ref(),
 8458                                        |el, accept_keystroke| {
 8459                                            el.child(h_flex().children(ui::render_modifiers(
 8460                                                &accept_keystroke.modifiers,
 8461                                                PlatformStyle::platform(),
 8462                                                Some(Color::Default),
 8463                                                Some(IconSize::XSmall.rems().into()),
 8464                                                false,
 8465                                            )))
 8466                                        },
 8467                                    ),
 8468                            )
 8469                            .into_any(),
 8470                    );
 8471                }
 8472
 8473                self.render_edit_prediction_cursor_popover_preview(
 8474                    prediction,
 8475                    cursor_point,
 8476                    style,
 8477                    cx,
 8478                )?
 8479            }
 8480
 8481            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8482                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8483                    stale_completion,
 8484                    cursor_point,
 8485                    style,
 8486                    cx,
 8487                )?,
 8488
 8489                None => {
 8490                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8491                }
 8492            },
 8493
 8494            None => pending_completion_container().child(Label::new("No Prediction")),
 8495        };
 8496
 8497        let completion = if is_refreshing {
 8498            completion
 8499                .with_animation(
 8500                    "loading-completion",
 8501                    Animation::new(Duration::from_secs(2))
 8502                        .repeat()
 8503                        .with_easing(pulsating_between(0.4, 0.8)),
 8504                    |label, delta| label.opacity(delta),
 8505                )
 8506                .into_any_element()
 8507        } else {
 8508            completion.into_any_element()
 8509        };
 8510
 8511        let has_completion = self.active_inline_completion.is_some();
 8512
 8513        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8514        Some(
 8515            h_flex()
 8516                .min_w(min_width)
 8517                .max_w(max_width)
 8518                .flex_1()
 8519                .elevation_2(cx)
 8520                .border_color(cx.theme().colors().border)
 8521                .child(
 8522                    div()
 8523                        .flex_1()
 8524                        .py_1()
 8525                        .px_2()
 8526                        .overflow_hidden()
 8527                        .child(completion),
 8528                )
 8529                .when_some(accept_keystroke, |el, accept_keystroke| {
 8530                    if !accept_keystroke.modifiers.modified() {
 8531                        return el;
 8532                    }
 8533
 8534                    el.child(
 8535                        h_flex()
 8536                            .h_full()
 8537                            .border_l_1()
 8538                            .rounded_r_lg()
 8539                            .border_color(cx.theme().colors().border)
 8540                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8541                            .gap_1()
 8542                            .py_1()
 8543                            .px_2()
 8544                            .child(
 8545                                h_flex()
 8546                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8547                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8548                                    .child(h_flex().children(ui::render_modifiers(
 8549                                        &accept_keystroke.modifiers,
 8550                                        PlatformStyle::platform(),
 8551                                        Some(if !has_completion {
 8552                                            Color::Muted
 8553                                        } else {
 8554                                            Color::Default
 8555                                        }),
 8556                                        None,
 8557                                        false,
 8558                                    ))),
 8559                            )
 8560                            .child(Label::new("Preview").into_any_element())
 8561                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8562                    )
 8563                })
 8564                .into_any(),
 8565        )
 8566    }
 8567
 8568    fn render_edit_prediction_cursor_popover_preview(
 8569        &self,
 8570        completion: &InlineCompletionState,
 8571        cursor_point: Point,
 8572        style: &EditorStyle,
 8573        cx: &mut Context<Editor>,
 8574    ) -> Option<Div> {
 8575        use text::ToPoint as _;
 8576
 8577        fn render_relative_row_jump(
 8578            prefix: impl Into<String>,
 8579            current_row: u32,
 8580            target_row: u32,
 8581        ) -> Div {
 8582            let (row_diff, arrow) = if target_row < current_row {
 8583                (current_row - target_row, IconName::ArrowUp)
 8584            } else {
 8585                (target_row - current_row, IconName::ArrowDown)
 8586            };
 8587
 8588            h_flex()
 8589                .child(
 8590                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8591                        .color(Color::Muted)
 8592                        .size(LabelSize::Small),
 8593                )
 8594                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8595        }
 8596
 8597        match &completion.completion {
 8598            InlineCompletion::Move {
 8599                target, snapshot, ..
 8600            } => Some(
 8601                h_flex()
 8602                    .px_2()
 8603                    .gap_2()
 8604                    .flex_1()
 8605                    .child(
 8606                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8607                            Icon::new(IconName::ZedPredictDown)
 8608                        } else {
 8609                            Icon::new(IconName::ZedPredictUp)
 8610                        },
 8611                    )
 8612                    .child(Label::new("Jump to Edit")),
 8613            ),
 8614
 8615            InlineCompletion::Edit {
 8616                edits,
 8617                edit_preview,
 8618                snapshot,
 8619                display_mode: _,
 8620            } => {
 8621                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8622
 8623                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8624                    &snapshot,
 8625                    &edits,
 8626                    edit_preview.as_ref()?,
 8627                    true,
 8628                    cx,
 8629                )
 8630                .first_line_preview();
 8631
 8632                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8633                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8634
 8635                let preview = h_flex()
 8636                    .gap_1()
 8637                    .min_w_16()
 8638                    .child(styled_text)
 8639                    .when(has_more_lines, |parent| parent.child(""));
 8640
 8641                let left = if first_edit_row != cursor_point.row {
 8642                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8643                        .into_any_element()
 8644                } else {
 8645                    Icon::new(IconName::ZedPredict).into_any_element()
 8646                };
 8647
 8648                Some(
 8649                    h_flex()
 8650                        .h_full()
 8651                        .flex_1()
 8652                        .gap_2()
 8653                        .pr_1()
 8654                        .overflow_x_hidden()
 8655                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8656                        .child(left)
 8657                        .child(preview),
 8658                )
 8659            }
 8660        }
 8661    }
 8662
 8663    pub fn render_context_menu(
 8664        &self,
 8665        style: &EditorStyle,
 8666        max_height_in_lines: u32,
 8667        window: &mut Window,
 8668        cx: &mut Context<Editor>,
 8669    ) -> Option<AnyElement> {
 8670        let menu = self.context_menu.borrow();
 8671        let menu = menu.as_ref()?;
 8672        if !menu.visible() {
 8673            return None;
 8674        };
 8675        Some(menu.render(style, max_height_in_lines, window, cx))
 8676    }
 8677
 8678    fn render_context_menu_aside(
 8679        &mut self,
 8680        max_size: Size<Pixels>,
 8681        window: &mut Window,
 8682        cx: &mut Context<Editor>,
 8683    ) -> Option<AnyElement> {
 8684        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8685            if menu.visible() {
 8686                menu.render_aside(self, max_size, window, cx)
 8687            } else {
 8688                None
 8689            }
 8690        })
 8691    }
 8692
 8693    fn hide_context_menu(
 8694        &mut self,
 8695        window: &mut Window,
 8696        cx: &mut Context<Self>,
 8697    ) -> Option<CodeContextMenu> {
 8698        cx.notify();
 8699        self.completion_tasks.clear();
 8700        let context_menu = self.context_menu.borrow_mut().take();
 8701        self.stale_inline_completion_in_menu.take();
 8702        self.update_visible_inline_completion(window, cx);
 8703        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8704            if let Some(completion_provider) = &self.completion_provider {
 8705                completion_provider.selection_changed(None, window, cx);
 8706            }
 8707        }
 8708        context_menu
 8709    }
 8710
 8711    fn show_snippet_choices(
 8712        &mut self,
 8713        choices: &Vec<String>,
 8714        selection: Range<Anchor>,
 8715        cx: &mut Context<Self>,
 8716    ) {
 8717        if selection.start.buffer_id.is_none() {
 8718            return;
 8719        }
 8720        let buffer_id = selection.start.buffer_id.unwrap();
 8721        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8722        let id = post_inc(&mut self.next_completion_id);
 8723        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8724
 8725        if let Some(buffer) = buffer {
 8726            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8727                CompletionsMenu::new_snippet_choices(
 8728                    id,
 8729                    true,
 8730                    choices,
 8731                    selection,
 8732                    buffer,
 8733                    snippet_sort_order,
 8734                ),
 8735            ));
 8736        }
 8737    }
 8738
 8739    pub fn insert_snippet(
 8740        &mut self,
 8741        insertion_ranges: &[Range<usize>],
 8742        snippet: Snippet,
 8743        window: &mut Window,
 8744        cx: &mut Context<Self>,
 8745    ) -> Result<()> {
 8746        struct Tabstop<T> {
 8747            is_end_tabstop: bool,
 8748            ranges: Vec<Range<T>>,
 8749            choices: Option<Vec<String>>,
 8750        }
 8751
 8752        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8753            let snippet_text: Arc<str> = snippet.text.clone().into();
 8754            let edits = insertion_ranges
 8755                .iter()
 8756                .cloned()
 8757                .map(|range| (range, snippet_text.clone()));
 8758            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8759
 8760            let snapshot = &*buffer.read(cx);
 8761            let snippet = &snippet;
 8762            snippet
 8763                .tabstops
 8764                .iter()
 8765                .map(|tabstop| {
 8766                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8767                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8768                    });
 8769                    let mut tabstop_ranges = tabstop
 8770                        .ranges
 8771                        .iter()
 8772                        .flat_map(|tabstop_range| {
 8773                            let mut delta = 0_isize;
 8774                            insertion_ranges.iter().map(move |insertion_range| {
 8775                                let insertion_start = insertion_range.start as isize + delta;
 8776                                delta +=
 8777                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8778
 8779                                let start = ((insertion_start + tabstop_range.start) as usize)
 8780                                    .min(snapshot.len());
 8781                                let end = ((insertion_start + tabstop_range.end) as usize)
 8782                                    .min(snapshot.len());
 8783                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8784                            })
 8785                        })
 8786                        .collect::<Vec<_>>();
 8787                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8788
 8789                    Tabstop {
 8790                        is_end_tabstop,
 8791                        ranges: tabstop_ranges,
 8792                        choices: tabstop.choices.clone(),
 8793                    }
 8794                })
 8795                .collect::<Vec<_>>()
 8796        });
 8797        if let Some(tabstop) = tabstops.first() {
 8798            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8799                s.select_ranges(tabstop.ranges.iter().cloned());
 8800            });
 8801
 8802            if let Some(choices) = &tabstop.choices {
 8803                if let Some(selection) = tabstop.ranges.first() {
 8804                    self.show_snippet_choices(choices, selection.clone(), cx)
 8805                }
 8806            }
 8807
 8808            // If we're already at the last tabstop and it's at the end of the snippet,
 8809            // we're done, we don't need to keep the state around.
 8810            if !tabstop.is_end_tabstop {
 8811                let choices = tabstops
 8812                    .iter()
 8813                    .map(|tabstop| tabstop.choices.clone())
 8814                    .collect();
 8815
 8816                let ranges = tabstops
 8817                    .into_iter()
 8818                    .map(|tabstop| tabstop.ranges)
 8819                    .collect::<Vec<_>>();
 8820
 8821                self.snippet_stack.push(SnippetState {
 8822                    active_index: 0,
 8823                    ranges,
 8824                    choices,
 8825                });
 8826            }
 8827
 8828            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8829            if self.autoclose_regions.is_empty() {
 8830                let snapshot = self.buffer.read(cx).snapshot(cx);
 8831                for selection in &mut self.selections.all::<Point>(cx) {
 8832                    let selection_head = selection.head();
 8833                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8834                        continue;
 8835                    };
 8836
 8837                    let mut bracket_pair = None;
 8838                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8839                    let prev_chars = snapshot
 8840                        .reversed_chars_at(selection_head)
 8841                        .collect::<String>();
 8842                    for (pair, enabled) in scope.brackets() {
 8843                        if enabled
 8844                            && pair.close
 8845                            && prev_chars.starts_with(pair.start.as_str())
 8846                            && next_chars.starts_with(pair.end.as_str())
 8847                        {
 8848                            bracket_pair = Some(pair.clone());
 8849                            break;
 8850                        }
 8851                    }
 8852                    if let Some(pair) = bracket_pair {
 8853                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8854                        let autoclose_enabled =
 8855                            self.use_autoclose && snapshot_settings.use_autoclose;
 8856                        if autoclose_enabled {
 8857                            let start = snapshot.anchor_after(selection_head);
 8858                            let end = snapshot.anchor_after(selection_head);
 8859                            self.autoclose_regions.push(AutocloseRegion {
 8860                                selection_id: selection.id,
 8861                                range: start..end,
 8862                                pair,
 8863                            });
 8864                        }
 8865                    }
 8866                }
 8867            }
 8868        }
 8869        Ok(())
 8870    }
 8871
 8872    pub fn move_to_next_snippet_tabstop(
 8873        &mut self,
 8874        window: &mut Window,
 8875        cx: &mut Context<Self>,
 8876    ) -> bool {
 8877        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8878    }
 8879
 8880    pub fn move_to_prev_snippet_tabstop(
 8881        &mut self,
 8882        window: &mut Window,
 8883        cx: &mut Context<Self>,
 8884    ) -> bool {
 8885        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8886    }
 8887
 8888    pub fn move_to_snippet_tabstop(
 8889        &mut self,
 8890        bias: Bias,
 8891        window: &mut Window,
 8892        cx: &mut Context<Self>,
 8893    ) -> bool {
 8894        if let Some(mut snippet) = self.snippet_stack.pop() {
 8895            match bias {
 8896                Bias::Left => {
 8897                    if snippet.active_index > 0 {
 8898                        snippet.active_index -= 1;
 8899                    } else {
 8900                        self.snippet_stack.push(snippet);
 8901                        return false;
 8902                    }
 8903                }
 8904                Bias::Right => {
 8905                    if snippet.active_index + 1 < snippet.ranges.len() {
 8906                        snippet.active_index += 1;
 8907                    } else {
 8908                        self.snippet_stack.push(snippet);
 8909                        return false;
 8910                    }
 8911                }
 8912            }
 8913            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8914                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8915                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8916                });
 8917
 8918                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8919                    if let Some(selection) = current_ranges.first() {
 8920                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8921                    }
 8922                }
 8923
 8924                // If snippet state is not at the last tabstop, push it back on the stack
 8925                if snippet.active_index + 1 < snippet.ranges.len() {
 8926                    self.snippet_stack.push(snippet);
 8927                }
 8928                return true;
 8929            }
 8930        }
 8931
 8932        false
 8933    }
 8934
 8935    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8936        self.transact(window, cx, |this, window, cx| {
 8937            this.select_all(&SelectAll, window, cx);
 8938            this.insert("", window, cx);
 8939        });
 8940    }
 8941
 8942    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8943        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8944        self.transact(window, cx, |this, window, cx| {
 8945            this.select_autoclose_pair(window, cx);
 8946            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8947            if !this.linked_edit_ranges.is_empty() {
 8948                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8949                let snapshot = this.buffer.read(cx).snapshot(cx);
 8950
 8951                for selection in selections.iter() {
 8952                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8953                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8954                    if selection_start.buffer_id != selection_end.buffer_id {
 8955                        continue;
 8956                    }
 8957                    if let Some(ranges) =
 8958                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8959                    {
 8960                        for (buffer, entries) in ranges {
 8961                            linked_ranges.entry(buffer).or_default().extend(entries);
 8962                        }
 8963                    }
 8964                }
 8965            }
 8966
 8967            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8968            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8969            for selection in &mut selections {
 8970                if selection.is_empty() {
 8971                    let old_head = selection.head();
 8972                    let mut new_head =
 8973                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8974                            .to_point(&display_map);
 8975                    if let Some((buffer, line_buffer_range)) = display_map
 8976                        .buffer_snapshot
 8977                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8978                    {
 8979                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8980                        let indent_len = match indent_size.kind {
 8981                            IndentKind::Space => {
 8982                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8983                            }
 8984                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8985                        };
 8986                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8987                            let indent_len = indent_len.get();
 8988                            new_head = cmp::min(
 8989                                new_head,
 8990                                MultiBufferPoint::new(
 8991                                    old_head.row,
 8992                                    ((old_head.column - 1) / indent_len) * indent_len,
 8993                                ),
 8994                            );
 8995                        }
 8996                    }
 8997
 8998                    selection.set_head(new_head, SelectionGoal::None);
 8999                }
 9000            }
 9001
 9002            this.signature_help_state.set_backspace_pressed(true);
 9003            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9004                s.select(selections)
 9005            });
 9006            this.insert("", window, cx);
 9007            let empty_str: Arc<str> = Arc::from("");
 9008            for (buffer, edits) in linked_ranges {
 9009                let snapshot = buffer.read(cx).snapshot();
 9010                use text::ToPoint as TP;
 9011
 9012                let edits = edits
 9013                    .into_iter()
 9014                    .map(|range| {
 9015                        let end_point = TP::to_point(&range.end, &snapshot);
 9016                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9017
 9018                        if end_point == start_point {
 9019                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9020                                .saturating_sub(1);
 9021                            start_point =
 9022                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9023                        };
 9024
 9025                        (start_point..end_point, empty_str.clone())
 9026                    })
 9027                    .sorted_by_key(|(range, _)| range.start)
 9028                    .collect::<Vec<_>>();
 9029                buffer.update(cx, |this, cx| {
 9030                    this.edit(edits, None, cx);
 9031                })
 9032            }
 9033            this.refresh_inline_completion(true, false, window, cx);
 9034            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9035        });
 9036    }
 9037
 9038    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9039        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9040        self.transact(window, cx, |this, window, cx| {
 9041            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9042                s.move_with(|map, selection| {
 9043                    if selection.is_empty() {
 9044                        let cursor = movement::right(map, selection.head());
 9045                        selection.end = cursor;
 9046                        selection.reversed = true;
 9047                        selection.goal = SelectionGoal::None;
 9048                    }
 9049                })
 9050            });
 9051            this.insert("", window, cx);
 9052            this.refresh_inline_completion(true, false, window, cx);
 9053        });
 9054    }
 9055
 9056    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9057        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9058        if self.move_to_prev_snippet_tabstop(window, cx) {
 9059            return;
 9060        }
 9061        self.outdent(&Outdent, window, cx);
 9062    }
 9063
 9064    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9065        if self.move_to_next_snippet_tabstop(window, cx) {
 9066            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9067            return;
 9068        }
 9069        if self.read_only(cx) {
 9070            return;
 9071        }
 9072        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9073        let mut selections = self.selections.all_adjusted(cx);
 9074        let buffer = self.buffer.read(cx);
 9075        let snapshot = buffer.snapshot(cx);
 9076        let rows_iter = selections.iter().map(|s| s.head().row);
 9077        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9078
 9079        let has_some_cursor_in_whitespace = selections
 9080            .iter()
 9081            .filter(|selection| selection.is_empty())
 9082            .any(|selection| {
 9083                let cursor = selection.head();
 9084                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9085                cursor.column < current_indent.len
 9086            });
 9087
 9088        let mut edits = Vec::new();
 9089        let mut prev_edited_row = 0;
 9090        let mut row_delta = 0;
 9091        for selection in &mut selections {
 9092            if selection.start.row != prev_edited_row {
 9093                row_delta = 0;
 9094            }
 9095            prev_edited_row = selection.end.row;
 9096
 9097            // If the selection is non-empty, then increase the indentation of the selected lines.
 9098            if !selection.is_empty() {
 9099                row_delta =
 9100                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9101                continue;
 9102            }
 9103
 9104            let cursor = selection.head();
 9105            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9106            if let Some(suggested_indent) =
 9107                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9108            {
 9109                // Don't do anything if already at suggested indent
 9110                // and there is any other cursor which is not
 9111                if has_some_cursor_in_whitespace
 9112                    && cursor.column == current_indent.len
 9113                    && current_indent.len == suggested_indent.len
 9114                {
 9115                    continue;
 9116                }
 9117
 9118                // Adjust line and move cursor to suggested indent
 9119                // if cursor is not at suggested indent
 9120                if cursor.column < suggested_indent.len
 9121                    && cursor.column <= current_indent.len
 9122                    && current_indent.len <= suggested_indent.len
 9123                {
 9124                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9125                    selection.end = selection.start;
 9126                    if row_delta == 0 {
 9127                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9128                            cursor.row,
 9129                            current_indent,
 9130                            suggested_indent,
 9131                        ));
 9132                        row_delta = suggested_indent.len - current_indent.len;
 9133                    }
 9134                    continue;
 9135                }
 9136
 9137                // If current indent is more than suggested indent
 9138                // only move cursor to current indent and skip indent
 9139                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9140                    selection.start = Point::new(cursor.row, current_indent.len);
 9141                    selection.end = selection.start;
 9142                    continue;
 9143                }
 9144            }
 9145
 9146            // Otherwise, insert a hard or soft tab.
 9147            let settings = buffer.language_settings_at(cursor, cx);
 9148            let tab_size = if settings.hard_tabs {
 9149                IndentSize::tab()
 9150            } else {
 9151                let tab_size = settings.tab_size.get();
 9152                let indent_remainder = snapshot
 9153                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9154                    .flat_map(str::chars)
 9155                    .fold(row_delta % tab_size, |counter: u32, c| {
 9156                        if c == '\t' {
 9157                            0
 9158                        } else {
 9159                            (counter + 1) % tab_size
 9160                        }
 9161                    });
 9162
 9163                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9164                IndentSize::spaces(chars_to_next_tab_stop)
 9165            };
 9166            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9167            selection.end = selection.start;
 9168            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9169            row_delta += tab_size.len;
 9170        }
 9171
 9172        self.transact(window, cx, |this, window, cx| {
 9173            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9174            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9175                s.select(selections)
 9176            });
 9177            this.refresh_inline_completion(true, false, window, cx);
 9178        });
 9179    }
 9180
 9181    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9182        if self.read_only(cx) {
 9183            return;
 9184        }
 9185        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9186        let mut selections = self.selections.all::<Point>(cx);
 9187        let mut prev_edited_row = 0;
 9188        let mut row_delta = 0;
 9189        let mut edits = Vec::new();
 9190        let buffer = self.buffer.read(cx);
 9191        let snapshot = buffer.snapshot(cx);
 9192        for selection in &mut selections {
 9193            if selection.start.row != prev_edited_row {
 9194                row_delta = 0;
 9195            }
 9196            prev_edited_row = selection.end.row;
 9197
 9198            row_delta =
 9199                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9200        }
 9201
 9202        self.transact(window, cx, |this, window, cx| {
 9203            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9204            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9205                s.select(selections)
 9206            });
 9207        });
 9208    }
 9209
 9210    fn indent_selection(
 9211        buffer: &MultiBuffer,
 9212        snapshot: &MultiBufferSnapshot,
 9213        selection: &mut Selection<Point>,
 9214        edits: &mut Vec<(Range<Point>, String)>,
 9215        delta_for_start_row: u32,
 9216        cx: &App,
 9217    ) -> u32 {
 9218        let settings = buffer.language_settings_at(selection.start, cx);
 9219        let tab_size = settings.tab_size.get();
 9220        let indent_kind = if settings.hard_tabs {
 9221            IndentKind::Tab
 9222        } else {
 9223            IndentKind::Space
 9224        };
 9225        let mut start_row = selection.start.row;
 9226        let mut end_row = selection.end.row + 1;
 9227
 9228        // If a selection ends at the beginning of a line, don't indent
 9229        // that last line.
 9230        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9231            end_row -= 1;
 9232        }
 9233
 9234        // Avoid re-indenting a row that has already been indented by a
 9235        // previous selection, but still update this selection's column
 9236        // to reflect that indentation.
 9237        if delta_for_start_row > 0 {
 9238            start_row += 1;
 9239            selection.start.column += delta_for_start_row;
 9240            if selection.end.row == selection.start.row {
 9241                selection.end.column += delta_for_start_row;
 9242            }
 9243        }
 9244
 9245        let mut delta_for_end_row = 0;
 9246        let has_multiple_rows = start_row + 1 != end_row;
 9247        for row in start_row..end_row {
 9248            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9249            let indent_delta = match (current_indent.kind, indent_kind) {
 9250                (IndentKind::Space, IndentKind::Space) => {
 9251                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9252                    IndentSize::spaces(columns_to_next_tab_stop)
 9253                }
 9254                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9255                (_, IndentKind::Tab) => IndentSize::tab(),
 9256            };
 9257
 9258            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9259                0
 9260            } else {
 9261                selection.start.column
 9262            };
 9263            let row_start = Point::new(row, start);
 9264            edits.push((
 9265                row_start..row_start,
 9266                indent_delta.chars().collect::<String>(),
 9267            ));
 9268
 9269            // Update this selection's endpoints to reflect the indentation.
 9270            if row == selection.start.row {
 9271                selection.start.column += indent_delta.len;
 9272            }
 9273            if row == selection.end.row {
 9274                selection.end.column += indent_delta.len;
 9275                delta_for_end_row = indent_delta.len;
 9276            }
 9277        }
 9278
 9279        if selection.start.row == selection.end.row {
 9280            delta_for_start_row + delta_for_end_row
 9281        } else {
 9282            delta_for_end_row
 9283        }
 9284    }
 9285
 9286    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9287        if self.read_only(cx) {
 9288            return;
 9289        }
 9290        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9291        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9292        let selections = self.selections.all::<Point>(cx);
 9293        let mut deletion_ranges = Vec::new();
 9294        let mut last_outdent = None;
 9295        {
 9296            let buffer = self.buffer.read(cx);
 9297            let snapshot = buffer.snapshot(cx);
 9298            for selection in &selections {
 9299                let settings = buffer.language_settings_at(selection.start, cx);
 9300                let tab_size = settings.tab_size.get();
 9301                let mut rows = selection.spanned_rows(false, &display_map);
 9302
 9303                // Avoid re-outdenting a row that has already been outdented by a
 9304                // previous selection.
 9305                if let Some(last_row) = last_outdent {
 9306                    if last_row == rows.start {
 9307                        rows.start = rows.start.next_row();
 9308                    }
 9309                }
 9310                let has_multiple_rows = rows.len() > 1;
 9311                for row in rows.iter_rows() {
 9312                    let indent_size = snapshot.indent_size_for_line(row);
 9313                    if indent_size.len > 0 {
 9314                        let deletion_len = match indent_size.kind {
 9315                            IndentKind::Space => {
 9316                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9317                                if columns_to_prev_tab_stop == 0 {
 9318                                    tab_size
 9319                                } else {
 9320                                    columns_to_prev_tab_stop
 9321                                }
 9322                            }
 9323                            IndentKind::Tab => 1,
 9324                        };
 9325                        let start = if has_multiple_rows
 9326                            || deletion_len > selection.start.column
 9327                            || indent_size.len < selection.start.column
 9328                        {
 9329                            0
 9330                        } else {
 9331                            selection.start.column - deletion_len
 9332                        };
 9333                        deletion_ranges.push(
 9334                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9335                        );
 9336                        last_outdent = Some(row);
 9337                    }
 9338                }
 9339            }
 9340        }
 9341
 9342        self.transact(window, cx, |this, window, cx| {
 9343            this.buffer.update(cx, |buffer, cx| {
 9344                let empty_str: Arc<str> = Arc::default();
 9345                buffer.edit(
 9346                    deletion_ranges
 9347                        .into_iter()
 9348                        .map(|range| (range, empty_str.clone())),
 9349                    None,
 9350                    cx,
 9351                );
 9352            });
 9353            let selections = this.selections.all::<usize>(cx);
 9354            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9355                s.select(selections)
 9356            });
 9357        });
 9358    }
 9359
 9360    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9361        if self.read_only(cx) {
 9362            return;
 9363        }
 9364        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9365        let selections = self
 9366            .selections
 9367            .all::<usize>(cx)
 9368            .into_iter()
 9369            .map(|s| s.range());
 9370
 9371        self.transact(window, cx, |this, window, cx| {
 9372            this.buffer.update(cx, |buffer, cx| {
 9373                buffer.autoindent_ranges(selections, cx);
 9374            });
 9375            let selections = this.selections.all::<usize>(cx);
 9376            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9377                s.select(selections)
 9378            });
 9379        });
 9380    }
 9381
 9382    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9383        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9384        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9385        let selections = self.selections.all::<Point>(cx);
 9386
 9387        let mut new_cursors = Vec::new();
 9388        let mut edit_ranges = Vec::new();
 9389        let mut selections = selections.iter().peekable();
 9390        while let Some(selection) = selections.next() {
 9391            let mut rows = selection.spanned_rows(false, &display_map);
 9392            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9393
 9394            // Accumulate contiguous regions of rows that we want to delete.
 9395            while let Some(next_selection) = selections.peek() {
 9396                let next_rows = next_selection.spanned_rows(false, &display_map);
 9397                if next_rows.start <= rows.end {
 9398                    rows.end = next_rows.end;
 9399                    selections.next().unwrap();
 9400                } else {
 9401                    break;
 9402                }
 9403            }
 9404
 9405            let buffer = &display_map.buffer_snapshot;
 9406            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9407            let edit_end;
 9408            let cursor_buffer_row;
 9409            if buffer.max_point().row >= rows.end.0 {
 9410                // If there's a line after the range, delete the \n from the end of the row range
 9411                // and position the cursor on the next line.
 9412                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9413                cursor_buffer_row = rows.end;
 9414            } else {
 9415                // If there isn't a line after the range, delete the \n from the line before the
 9416                // start of the row range and position the cursor there.
 9417                edit_start = edit_start.saturating_sub(1);
 9418                edit_end = buffer.len();
 9419                cursor_buffer_row = rows.start.previous_row();
 9420            }
 9421
 9422            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9423            *cursor.column_mut() =
 9424                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9425
 9426            new_cursors.push((
 9427                selection.id,
 9428                buffer.anchor_after(cursor.to_point(&display_map)),
 9429            ));
 9430            edit_ranges.push(edit_start..edit_end);
 9431        }
 9432
 9433        self.transact(window, cx, |this, window, cx| {
 9434            let buffer = this.buffer.update(cx, |buffer, cx| {
 9435                let empty_str: Arc<str> = Arc::default();
 9436                buffer.edit(
 9437                    edit_ranges
 9438                        .into_iter()
 9439                        .map(|range| (range, empty_str.clone())),
 9440                    None,
 9441                    cx,
 9442                );
 9443                buffer.snapshot(cx)
 9444            });
 9445            let new_selections = new_cursors
 9446                .into_iter()
 9447                .map(|(id, cursor)| {
 9448                    let cursor = cursor.to_point(&buffer);
 9449                    Selection {
 9450                        id,
 9451                        start: cursor,
 9452                        end: cursor,
 9453                        reversed: false,
 9454                        goal: SelectionGoal::None,
 9455                    }
 9456                })
 9457                .collect();
 9458
 9459            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9460                s.select(new_selections);
 9461            });
 9462        });
 9463    }
 9464
 9465    pub fn join_lines_impl(
 9466        &mut self,
 9467        insert_whitespace: bool,
 9468        window: &mut Window,
 9469        cx: &mut Context<Self>,
 9470    ) {
 9471        if self.read_only(cx) {
 9472            return;
 9473        }
 9474        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9475        for selection in self.selections.all::<Point>(cx) {
 9476            let start = MultiBufferRow(selection.start.row);
 9477            // Treat single line selections as if they include the next line. Otherwise this action
 9478            // would do nothing for single line selections individual cursors.
 9479            let end = if selection.start.row == selection.end.row {
 9480                MultiBufferRow(selection.start.row + 1)
 9481            } else {
 9482                MultiBufferRow(selection.end.row)
 9483            };
 9484
 9485            if let Some(last_row_range) = row_ranges.last_mut() {
 9486                if start <= last_row_range.end {
 9487                    last_row_range.end = end;
 9488                    continue;
 9489                }
 9490            }
 9491            row_ranges.push(start..end);
 9492        }
 9493
 9494        let snapshot = self.buffer.read(cx).snapshot(cx);
 9495        let mut cursor_positions = Vec::new();
 9496        for row_range in &row_ranges {
 9497            let anchor = snapshot.anchor_before(Point::new(
 9498                row_range.end.previous_row().0,
 9499                snapshot.line_len(row_range.end.previous_row()),
 9500            ));
 9501            cursor_positions.push(anchor..anchor);
 9502        }
 9503
 9504        self.transact(window, cx, |this, window, cx| {
 9505            for row_range in row_ranges.into_iter().rev() {
 9506                for row in row_range.iter_rows().rev() {
 9507                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9508                    let next_line_row = row.next_row();
 9509                    let indent = snapshot.indent_size_for_line(next_line_row);
 9510                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9511
 9512                    let replace =
 9513                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9514                            " "
 9515                        } else {
 9516                            ""
 9517                        };
 9518
 9519                    this.buffer.update(cx, |buffer, cx| {
 9520                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9521                    });
 9522                }
 9523            }
 9524
 9525            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9526                s.select_anchor_ranges(cursor_positions)
 9527            });
 9528        });
 9529    }
 9530
 9531    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9532        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9533        self.join_lines_impl(true, window, cx);
 9534    }
 9535
 9536    pub fn sort_lines_case_sensitive(
 9537        &mut self,
 9538        _: &SortLinesCaseSensitive,
 9539        window: &mut Window,
 9540        cx: &mut Context<Self>,
 9541    ) {
 9542        self.manipulate_lines(window, cx, |lines| lines.sort())
 9543    }
 9544
 9545    pub fn sort_lines_case_insensitive(
 9546        &mut self,
 9547        _: &SortLinesCaseInsensitive,
 9548        window: &mut Window,
 9549        cx: &mut Context<Self>,
 9550    ) {
 9551        self.manipulate_lines(window, cx, |lines| {
 9552            lines.sort_by_key(|line| line.to_lowercase())
 9553        })
 9554    }
 9555
 9556    pub fn unique_lines_case_insensitive(
 9557        &mut self,
 9558        _: &UniqueLinesCaseInsensitive,
 9559        window: &mut Window,
 9560        cx: &mut Context<Self>,
 9561    ) {
 9562        self.manipulate_lines(window, cx, |lines| {
 9563            let mut seen = HashSet::default();
 9564            lines.retain(|line| seen.insert(line.to_lowercase()));
 9565        })
 9566    }
 9567
 9568    pub fn unique_lines_case_sensitive(
 9569        &mut self,
 9570        _: &UniqueLinesCaseSensitive,
 9571        window: &mut Window,
 9572        cx: &mut Context<Self>,
 9573    ) {
 9574        self.manipulate_lines(window, cx, |lines| {
 9575            let mut seen = HashSet::default();
 9576            lines.retain(|line| seen.insert(*line));
 9577        })
 9578    }
 9579
 9580    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9581        let Some(project) = self.project.clone() else {
 9582            return;
 9583        };
 9584        self.reload(project, window, cx)
 9585            .detach_and_notify_err(window, cx);
 9586    }
 9587
 9588    pub fn restore_file(
 9589        &mut self,
 9590        _: &::git::RestoreFile,
 9591        window: &mut Window,
 9592        cx: &mut Context<Self>,
 9593    ) {
 9594        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9595        let mut buffer_ids = HashSet::default();
 9596        let snapshot = self.buffer().read(cx).snapshot(cx);
 9597        for selection in self.selections.all::<usize>(cx) {
 9598            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9599        }
 9600
 9601        let buffer = self.buffer().read(cx);
 9602        let ranges = buffer_ids
 9603            .into_iter()
 9604            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9605            .collect::<Vec<_>>();
 9606
 9607        self.restore_hunks_in_ranges(ranges, window, cx);
 9608    }
 9609
 9610    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9611        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9612        let selections = self
 9613            .selections
 9614            .all(cx)
 9615            .into_iter()
 9616            .map(|s| s.range())
 9617            .collect();
 9618        self.restore_hunks_in_ranges(selections, window, cx);
 9619    }
 9620
 9621    pub fn restore_hunks_in_ranges(
 9622        &mut self,
 9623        ranges: Vec<Range<Point>>,
 9624        window: &mut Window,
 9625        cx: &mut Context<Editor>,
 9626    ) {
 9627        let mut revert_changes = HashMap::default();
 9628        let chunk_by = self
 9629            .snapshot(window, cx)
 9630            .hunks_for_ranges(ranges)
 9631            .into_iter()
 9632            .chunk_by(|hunk| hunk.buffer_id);
 9633        for (buffer_id, hunks) in &chunk_by {
 9634            let hunks = hunks.collect::<Vec<_>>();
 9635            for hunk in &hunks {
 9636                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9637            }
 9638            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9639        }
 9640        drop(chunk_by);
 9641        if !revert_changes.is_empty() {
 9642            self.transact(window, cx, |editor, window, cx| {
 9643                editor.restore(revert_changes, window, cx);
 9644            });
 9645        }
 9646    }
 9647
 9648    pub fn open_active_item_in_terminal(
 9649        &mut self,
 9650        _: &OpenInTerminal,
 9651        window: &mut Window,
 9652        cx: &mut Context<Self>,
 9653    ) {
 9654        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9655            let project_path = buffer.read(cx).project_path(cx)?;
 9656            let project = self.project.as_ref()?.read(cx);
 9657            let entry = project.entry_for_path(&project_path, cx)?;
 9658            let parent = match &entry.canonical_path {
 9659                Some(canonical_path) => canonical_path.to_path_buf(),
 9660                None => project.absolute_path(&project_path, cx)?,
 9661            }
 9662            .parent()?
 9663            .to_path_buf();
 9664            Some(parent)
 9665        }) {
 9666            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9667        }
 9668    }
 9669
 9670    fn set_breakpoint_context_menu(
 9671        &mut self,
 9672        display_row: DisplayRow,
 9673        position: Option<Anchor>,
 9674        clicked_point: gpui::Point<Pixels>,
 9675        window: &mut Window,
 9676        cx: &mut Context<Self>,
 9677    ) {
 9678        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9679            return;
 9680        }
 9681        let source = self
 9682            .buffer
 9683            .read(cx)
 9684            .snapshot(cx)
 9685            .anchor_before(Point::new(display_row.0, 0u32));
 9686
 9687        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9688
 9689        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9690            self,
 9691            source,
 9692            clicked_point,
 9693            context_menu,
 9694            window,
 9695            cx,
 9696        );
 9697    }
 9698
 9699    fn add_edit_breakpoint_block(
 9700        &mut self,
 9701        anchor: Anchor,
 9702        breakpoint: &Breakpoint,
 9703        edit_action: BreakpointPromptEditAction,
 9704        window: &mut Window,
 9705        cx: &mut Context<Self>,
 9706    ) {
 9707        let weak_editor = cx.weak_entity();
 9708        let bp_prompt = cx.new(|cx| {
 9709            BreakpointPromptEditor::new(
 9710                weak_editor,
 9711                anchor,
 9712                breakpoint.clone(),
 9713                edit_action,
 9714                window,
 9715                cx,
 9716            )
 9717        });
 9718
 9719        let height = bp_prompt.update(cx, |this, cx| {
 9720            this.prompt
 9721                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9722        });
 9723        let cloned_prompt = bp_prompt.clone();
 9724        let blocks = vec![BlockProperties {
 9725            style: BlockStyle::Sticky,
 9726            placement: BlockPlacement::Above(anchor),
 9727            height: Some(height),
 9728            render: Arc::new(move |cx| {
 9729                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9730                cloned_prompt.clone().into_any_element()
 9731            }),
 9732            priority: 0,
 9733            render_in_minimap: true,
 9734        }];
 9735
 9736        let focus_handle = bp_prompt.focus_handle(cx);
 9737        window.focus(&focus_handle);
 9738
 9739        let block_ids = self.insert_blocks(blocks, None, cx);
 9740        bp_prompt.update(cx, |prompt, _| {
 9741            prompt.add_block_ids(block_ids);
 9742        });
 9743    }
 9744
 9745    pub(crate) fn breakpoint_at_row(
 9746        &self,
 9747        row: u32,
 9748        window: &mut Window,
 9749        cx: &mut Context<Self>,
 9750    ) -> Option<(Anchor, Breakpoint)> {
 9751        let snapshot = self.snapshot(window, cx);
 9752        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9753
 9754        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9755    }
 9756
 9757    pub(crate) fn breakpoint_at_anchor(
 9758        &self,
 9759        breakpoint_position: Anchor,
 9760        snapshot: &EditorSnapshot,
 9761        cx: &mut Context<Self>,
 9762    ) -> Option<(Anchor, Breakpoint)> {
 9763        let project = self.project.clone()?;
 9764
 9765        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9766            snapshot
 9767                .buffer_snapshot
 9768                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9769        })?;
 9770
 9771        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9772        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9773        let buffer_snapshot = buffer.read(cx).snapshot();
 9774
 9775        let row = buffer_snapshot
 9776            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9777            .row;
 9778
 9779        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9780        let anchor_end = snapshot
 9781            .buffer_snapshot
 9782            .anchor_after(Point::new(row, line_len));
 9783
 9784        let bp = self
 9785            .breakpoint_store
 9786            .as_ref()?
 9787            .read_with(cx, |breakpoint_store, cx| {
 9788                breakpoint_store
 9789                    .breakpoints(
 9790                        &buffer,
 9791                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9792                        &buffer_snapshot,
 9793                        cx,
 9794                    )
 9795                    .next()
 9796                    .and_then(|(bp, _)| {
 9797                        let breakpoint_row = buffer_snapshot
 9798                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9799                            .row;
 9800
 9801                        if breakpoint_row == row {
 9802                            snapshot
 9803                                .buffer_snapshot
 9804                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9805                                .map(|position| (position, bp.bp.clone()))
 9806                        } else {
 9807                            None
 9808                        }
 9809                    })
 9810            });
 9811        bp
 9812    }
 9813
 9814    pub fn edit_log_breakpoint(
 9815        &mut self,
 9816        _: &EditLogBreakpoint,
 9817        window: &mut Window,
 9818        cx: &mut Context<Self>,
 9819    ) {
 9820        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9821            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9822                message: None,
 9823                state: BreakpointState::Enabled,
 9824                condition: None,
 9825                hit_condition: None,
 9826            });
 9827
 9828            self.add_edit_breakpoint_block(
 9829                anchor,
 9830                &breakpoint,
 9831                BreakpointPromptEditAction::Log,
 9832                window,
 9833                cx,
 9834            );
 9835        }
 9836    }
 9837
 9838    fn breakpoints_at_cursors(
 9839        &self,
 9840        window: &mut Window,
 9841        cx: &mut Context<Self>,
 9842    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9843        let snapshot = self.snapshot(window, cx);
 9844        let cursors = self
 9845            .selections
 9846            .disjoint_anchors()
 9847            .into_iter()
 9848            .map(|selection| {
 9849                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9850
 9851                let breakpoint_position = self
 9852                    .breakpoint_at_row(cursor_position.row, window, cx)
 9853                    .map(|bp| bp.0)
 9854                    .unwrap_or_else(|| {
 9855                        snapshot
 9856                            .display_snapshot
 9857                            .buffer_snapshot
 9858                            .anchor_after(Point::new(cursor_position.row, 0))
 9859                    });
 9860
 9861                let breakpoint = self
 9862                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9863                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9864
 9865                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9866            })
 9867            // 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.
 9868            .collect::<HashMap<Anchor, _>>();
 9869
 9870        cursors.into_iter().collect()
 9871    }
 9872
 9873    pub fn enable_breakpoint(
 9874        &mut self,
 9875        _: &crate::actions::EnableBreakpoint,
 9876        window: &mut Window,
 9877        cx: &mut Context<Self>,
 9878    ) {
 9879        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9880            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9881                continue;
 9882            };
 9883            self.edit_breakpoint_at_anchor(
 9884                anchor,
 9885                breakpoint,
 9886                BreakpointEditAction::InvertState,
 9887                cx,
 9888            );
 9889        }
 9890    }
 9891
 9892    pub fn disable_breakpoint(
 9893        &mut self,
 9894        _: &crate::actions::DisableBreakpoint,
 9895        window: &mut Window,
 9896        cx: &mut Context<Self>,
 9897    ) {
 9898        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9899            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9900                continue;
 9901            };
 9902            self.edit_breakpoint_at_anchor(
 9903                anchor,
 9904                breakpoint,
 9905                BreakpointEditAction::InvertState,
 9906                cx,
 9907            );
 9908        }
 9909    }
 9910
 9911    pub fn toggle_breakpoint(
 9912        &mut self,
 9913        _: &crate::actions::ToggleBreakpoint,
 9914        window: &mut Window,
 9915        cx: &mut Context<Self>,
 9916    ) {
 9917        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9918            if let Some(breakpoint) = breakpoint {
 9919                self.edit_breakpoint_at_anchor(
 9920                    anchor,
 9921                    breakpoint,
 9922                    BreakpointEditAction::Toggle,
 9923                    cx,
 9924                );
 9925            } else {
 9926                self.edit_breakpoint_at_anchor(
 9927                    anchor,
 9928                    Breakpoint::new_standard(),
 9929                    BreakpointEditAction::Toggle,
 9930                    cx,
 9931                );
 9932            }
 9933        }
 9934    }
 9935
 9936    pub fn edit_breakpoint_at_anchor(
 9937        &mut self,
 9938        breakpoint_position: Anchor,
 9939        breakpoint: Breakpoint,
 9940        edit_action: BreakpointEditAction,
 9941        cx: &mut Context<Self>,
 9942    ) {
 9943        let Some(breakpoint_store) = &self.breakpoint_store else {
 9944            return;
 9945        };
 9946
 9947        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9948            if breakpoint_position == Anchor::min() {
 9949                self.buffer()
 9950                    .read(cx)
 9951                    .excerpt_buffer_ids()
 9952                    .into_iter()
 9953                    .next()
 9954            } else {
 9955                None
 9956            }
 9957        }) else {
 9958            return;
 9959        };
 9960
 9961        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9962            return;
 9963        };
 9964
 9965        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9966            breakpoint_store.toggle_breakpoint(
 9967                buffer,
 9968                BreakpointWithPosition {
 9969                    position: breakpoint_position.text_anchor,
 9970                    bp: breakpoint,
 9971                },
 9972                edit_action,
 9973                cx,
 9974            );
 9975        });
 9976
 9977        cx.notify();
 9978    }
 9979
 9980    #[cfg(any(test, feature = "test-support"))]
 9981    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9982        self.breakpoint_store.clone()
 9983    }
 9984
 9985    pub fn prepare_restore_change(
 9986        &self,
 9987        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9988        hunk: &MultiBufferDiffHunk,
 9989        cx: &mut App,
 9990    ) -> Option<()> {
 9991        if hunk.is_created_file() {
 9992            return None;
 9993        }
 9994        let buffer = self.buffer.read(cx);
 9995        let diff = buffer.diff_for(hunk.buffer_id)?;
 9996        let buffer = buffer.buffer(hunk.buffer_id)?;
 9997        let buffer = buffer.read(cx);
 9998        let original_text = diff
 9999            .read(cx)
10000            .base_text()
10001            .as_rope()
10002            .slice(hunk.diff_base_byte_range.clone());
10003        let buffer_snapshot = buffer.snapshot();
10004        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10005        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10006            probe
10007                .0
10008                .start
10009                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10010                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10011        }) {
10012            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10013            Some(())
10014        } else {
10015            None
10016        }
10017    }
10018
10019    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10020        self.manipulate_lines(window, cx, |lines| lines.reverse())
10021    }
10022
10023    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10024        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10025    }
10026
10027    fn manipulate_lines<Fn>(
10028        &mut self,
10029        window: &mut Window,
10030        cx: &mut Context<Self>,
10031        mut callback: Fn,
10032    ) where
10033        Fn: FnMut(&mut Vec<&str>),
10034    {
10035        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10036
10037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10038        let buffer = self.buffer.read(cx).snapshot(cx);
10039
10040        let mut edits = Vec::new();
10041
10042        let selections = self.selections.all::<Point>(cx);
10043        let mut selections = selections.iter().peekable();
10044        let mut contiguous_row_selections = Vec::new();
10045        let mut new_selections = Vec::new();
10046        let mut added_lines = 0;
10047        let mut removed_lines = 0;
10048
10049        while let Some(selection) = selections.next() {
10050            let (start_row, end_row) = consume_contiguous_rows(
10051                &mut contiguous_row_selections,
10052                selection,
10053                &display_map,
10054                &mut selections,
10055            );
10056
10057            let start_point = Point::new(start_row.0, 0);
10058            let end_point = Point::new(
10059                end_row.previous_row().0,
10060                buffer.line_len(end_row.previous_row()),
10061            );
10062            let text = buffer
10063                .text_for_range(start_point..end_point)
10064                .collect::<String>();
10065
10066            let mut lines = text.split('\n').collect_vec();
10067
10068            let lines_before = lines.len();
10069            callback(&mut lines);
10070            let lines_after = lines.len();
10071
10072            edits.push((start_point..end_point, lines.join("\n")));
10073
10074            // Selections must change based on added and removed line count
10075            let start_row =
10076                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10077            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10078            new_selections.push(Selection {
10079                id: selection.id,
10080                start: start_row,
10081                end: end_row,
10082                goal: SelectionGoal::None,
10083                reversed: selection.reversed,
10084            });
10085
10086            if lines_after > lines_before {
10087                added_lines += lines_after - lines_before;
10088            } else if lines_before > lines_after {
10089                removed_lines += lines_before - lines_after;
10090            }
10091        }
10092
10093        self.transact(window, cx, |this, window, cx| {
10094            let buffer = this.buffer.update(cx, |buffer, cx| {
10095                buffer.edit(edits, None, cx);
10096                buffer.snapshot(cx)
10097            });
10098
10099            // Recalculate offsets on newly edited buffer
10100            let new_selections = new_selections
10101                .iter()
10102                .map(|s| {
10103                    let start_point = Point::new(s.start.0, 0);
10104                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10105                    Selection {
10106                        id: s.id,
10107                        start: buffer.point_to_offset(start_point),
10108                        end: buffer.point_to_offset(end_point),
10109                        goal: s.goal,
10110                        reversed: s.reversed,
10111                    }
10112                })
10113                .collect();
10114
10115            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10116                s.select(new_selections);
10117            });
10118
10119            this.request_autoscroll(Autoscroll::fit(), cx);
10120        });
10121    }
10122
10123    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10124        self.manipulate_text(window, cx, |text| {
10125            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10126            if has_upper_case_characters {
10127                text.to_lowercase()
10128            } else {
10129                text.to_uppercase()
10130            }
10131        })
10132    }
10133
10134    pub fn convert_to_upper_case(
10135        &mut self,
10136        _: &ConvertToUpperCase,
10137        window: &mut Window,
10138        cx: &mut Context<Self>,
10139    ) {
10140        self.manipulate_text(window, cx, |text| text.to_uppercase())
10141    }
10142
10143    pub fn convert_to_lower_case(
10144        &mut self,
10145        _: &ConvertToLowerCase,
10146        window: &mut Window,
10147        cx: &mut Context<Self>,
10148    ) {
10149        self.manipulate_text(window, cx, |text| text.to_lowercase())
10150    }
10151
10152    pub fn convert_to_title_case(
10153        &mut self,
10154        _: &ConvertToTitleCase,
10155        window: &mut Window,
10156        cx: &mut Context<Self>,
10157    ) {
10158        self.manipulate_text(window, cx, |text| {
10159            text.split('\n')
10160                .map(|line| line.to_case(Case::Title))
10161                .join("\n")
10162        })
10163    }
10164
10165    pub fn convert_to_snake_case(
10166        &mut self,
10167        _: &ConvertToSnakeCase,
10168        window: &mut Window,
10169        cx: &mut Context<Self>,
10170    ) {
10171        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10172    }
10173
10174    pub fn convert_to_kebab_case(
10175        &mut self,
10176        _: &ConvertToKebabCase,
10177        window: &mut Window,
10178        cx: &mut Context<Self>,
10179    ) {
10180        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10181    }
10182
10183    pub fn convert_to_upper_camel_case(
10184        &mut self,
10185        _: &ConvertToUpperCamelCase,
10186        window: &mut Window,
10187        cx: &mut Context<Self>,
10188    ) {
10189        self.manipulate_text(window, cx, |text| {
10190            text.split('\n')
10191                .map(|line| line.to_case(Case::UpperCamel))
10192                .join("\n")
10193        })
10194    }
10195
10196    pub fn convert_to_lower_camel_case(
10197        &mut self,
10198        _: &ConvertToLowerCamelCase,
10199        window: &mut Window,
10200        cx: &mut Context<Self>,
10201    ) {
10202        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10203    }
10204
10205    pub fn convert_to_opposite_case(
10206        &mut self,
10207        _: &ConvertToOppositeCase,
10208        window: &mut Window,
10209        cx: &mut Context<Self>,
10210    ) {
10211        self.manipulate_text(window, cx, |text| {
10212            text.chars()
10213                .fold(String::with_capacity(text.len()), |mut t, c| {
10214                    if c.is_uppercase() {
10215                        t.extend(c.to_lowercase());
10216                    } else {
10217                        t.extend(c.to_uppercase());
10218                    }
10219                    t
10220                })
10221        })
10222    }
10223
10224    pub fn convert_to_rot13(
10225        &mut self,
10226        _: &ConvertToRot13,
10227        window: &mut Window,
10228        cx: &mut Context<Self>,
10229    ) {
10230        self.manipulate_text(window, cx, |text| {
10231            text.chars()
10232                .map(|c| match c {
10233                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10234                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10235                    _ => c,
10236                })
10237                .collect()
10238        })
10239    }
10240
10241    pub fn convert_to_rot47(
10242        &mut self,
10243        _: &ConvertToRot47,
10244        window: &mut Window,
10245        cx: &mut Context<Self>,
10246    ) {
10247        self.manipulate_text(window, cx, |text| {
10248            text.chars()
10249                .map(|c| {
10250                    let code_point = c as u32;
10251                    if code_point >= 33 && code_point <= 126 {
10252                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10253                    }
10254                    c
10255                })
10256                .collect()
10257        })
10258    }
10259
10260    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10261    where
10262        Fn: FnMut(&str) -> String,
10263    {
10264        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10265        let buffer = self.buffer.read(cx).snapshot(cx);
10266
10267        let mut new_selections = Vec::new();
10268        let mut edits = Vec::new();
10269        let mut selection_adjustment = 0i32;
10270
10271        for selection in self.selections.all::<usize>(cx) {
10272            let selection_is_empty = selection.is_empty();
10273
10274            let (start, end) = if selection_is_empty {
10275                let word_range = movement::surrounding_word(
10276                    &display_map,
10277                    selection.start.to_display_point(&display_map),
10278                );
10279                let start = word_range.start.to_offset(&display_map, Bias::Left);
10280                let end = word_range.end.to_offset(&display_map, Bias::Left);
10281                (start, end)
10282            } else {
10283                (selection.start, selection.end)
10284            };
10285
10286            let text = buffer.text_for_range(start..end).collect::<String>();
10287            let old_length = text.len() as i32;
10288            let text = callback(&text);
10289
10290            new_selections.push(Selection {
10291                start: (start as i32 - selection_adjustment) as usize,
10292                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10293                goal: SelectionGoal::None,
10294                ..selection
10295            });
10296
10297            selection_adjustment += old_length - text.len() as i32;
10298
10299            edits.push((start..end, text));
10300        }
10301
10302        self.transact(window, cx, |this, window, cx| {
10303            this.buffer.update(cx, |buffer, cx| {
10304                buffer.edit(edits, None, cx);
10305            });
10306
10307            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10308                s.select(new_selections);
10309            });
10310
10311            this.request_autoscroll(Autoscroll::fit(), cx);
10312        });
10313    }
10314
10315    pub fn duplicate(
10316        &mut self,
10317        upwards: bool,
10318        whole_lines: bool,
10319        window: &mut Window,
10320        cx: &mut Context<Self>,
10321    ) {
10322        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10323
10324        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10325        let buffer = &display_map.buffer_snapshot;
10326        let selections = self.selections.all::<Point>(cx);
10327
10328        let mut edits = Vec::new();
10329        let mut selections_iter = selections.iter().peekable();
10330        while let Some(selection) = selections_iter.next() {
10331            let mut rows = selection.spanned_rows(false, &display_map);
10332            // duplicate line-wise
10333            if whole_lines || selection.start == selection.end {
10334                // Avoid duplicating the same lines twice.
10335                while let Some(next_selection) = selections_iter.peek() {
10336                    let next_rows = next_selection.spanned_rows(false, &display_map);
10337                    if next_rows.start < rows.end {
10338                        rows.end = next_rows.end;
10339                        selections_iter.next().unwrap();
10340                    } else {
10341                        break;
10342                    }
10343                }
10344
10345                // Copy the text from the selected row region and splice it either at the start
10346                // or end of the region.
10347                let start = Point::new(rows.start.0, 0);
10348                let end = Point::new(
10349                    rows.end.previous_row().0,
10350                    buffer.line_len(rows.end.previous_row()),
10351                );
10352                let text = buffer
10353                    .text_for_range(start..end)
10354                    .chain(Some("\n"))
10355                    .collect::<String>();
10356                let insert_location = if upwards {
10357                    Point::new(rows.end.0, 0)
10358                } else {
10359                    start
10360                };
10361                edits.push((insert_location..insert_location, text));
10362            } else {
10363                // duplicate character-wise
10364                let start = selection.start;
10365                let end = selection.end;
10366                let text = buffer.text_for_range(start..end).collect::<String>();
10367                edits.push((selection.end..selection.end, text));
10368            }
10369        }
10370
10371        self.transact(window, cx, |this, _, cx| {
10372            this.buffer.update(cx, |buffer, cx| {
10373                buffer.edit(edits, None, cx);
10374            });
10375
10376            this.request_autoscroll(Autoscroll::fit(), cx);
10377        });
10378    }
10379
10380    pub fn duplicate_line_up(
10381        &mut self,
10382        _: &DuplicateLineUp,
10383        window: &mut Window,
10384        cx: &mut Context<Self>,
10385    ) {
10386        self.duplicate(true, true, window, cx);
10387    }
10388
10389    pub fn duplicate_line_down(
10390        &mut self,
10391        _: &DuplicateLineDown,
10392        window: &mut Window,
10393        cx: &mut Context<Self>,
10394    ) {
10395        self.duplicate(false, true, window, cx);
10396    }
10397
10398    pub fn duplicate_selection(
10399        &mut self,
10400        _: &DuplicateSelection,
10401        window: &mut Window,
10402        cx: &mut Context<Self>,
10403    ) {
10404        self.duplicate(false, false, window, cx);
10405    }
10406
10407    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10408        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10409
10410        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10411        let buffer = self.buffer.read(cx).snapshot(cx);
10412
10413        let mut edits = Vec::new();
10414        let mut unfold_ranges = Vec::new();
10415        let mut refold_creases = Vec::new();
10416
10417        let selections = self.selections.all::<Point>(cx);
10418        let mut selections = selections.iter().peekable();
10419        let mut contiguous_row_selections = Vec::new();
10420        let mut new_selections = Vec::new();
10421
10422        while let Some(selection) = selections.next() {
10423            // Find all the selections that span a contiguous row range
10424            let (start_row, end_row) = consume_contiguous_rows(
10425                &mut contiguous_row_selections,
10426                selection,
10427                &display_map,
10428                &mut selections,
10429            );
10430
10431            // Move the text spanned by the row range to be before the line preceding the row range
10432            if start_row.0 > 0 {
10433                let range_to_move = Point::new(
10434                    start_row.previous_row().0,
10435                    buffer.line_len(start_row.previous_row()),
10436                )
10437                    ..Point::new(
10438                        end_row.previous_row().0,
10439                        buffer.line_len(end_row.previous_row()),
10440                    );
10441                let insertion_point = display_map
10442                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10443                    .0;
10444
10445                // Don't move lines across excerpts
10446                if buffer
10447                    .excerpt_containing(insertion_point..range_to_move.end)
10448                    .is_some()
10449                {
10450                    let text = buffer
10451                        .text_for_range(range_to_move.clone())
10452                        .flat_map(|s| s.chars())
10453                        .skip(1)
10454                        .chain(['\n'])
10455                        .collect::<String>();
10456
10457                    edits.push((
10458                        buffer.anchor_after(range_to_move.start)
10459                            ..buffer.anchor_before(range_to_move.end),
10460                        String::new(),
10461                    ));
10462                    let insertion_anchor = buffer.anchor_after(insertion_point);
10463                    edits.push((insertion_anchor..insertion_anchor, text));
10464
10465                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10466
10467                    // Move selections up
10468                    new_selections.extend(contiguous_row_selections.drain(..).map(
10469                        |mut selection| {
10470                            selection.start.row -= row_delta;
10471                            selection.end.row -= row_delta;
10472                            selection
10473                        },
10474                    ));
10475
10476                    // Move folds up
10477                    unfold_ranges.push(range_to_move.clone());
10478                    for fold in display_map.folds_in_range(
10479                        buffer.anchor_before(range_to_move.start)
10480                            ..buffer.anchor_after(range_to_move.end),
10481                    ) {
10482                        let mut start = fold.range.start.to_point(&buffer);
10483                        let mut end = fold.range.end.to_point(&buffer);
10484                        start.row -= row_delta;
10485                        end.row -= row_delta;
10486                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10487                    }
10488                }
10489            }
10490
10491            // If we didn't move line(s), preserve the existing selections
10492            new_selections.append(&mut contiguous_row_selections);
10493        }
10494
10495        self.transact(window, cx, |this, window, cx| {
10496            this.unfold_ranges(&unfold_ranges, true, true, cx);
10497            this.buffer.update(cx, |buffer, cx| {
10498                for (range, text) in edits {
10499                    buffer.edit([(range, text)], None, cx);
10500                }
10501            });
10502            this.fold_creases(refold_creases, true, window, cx);
10503            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10504                s.select(new_selections);
10505            })
10506        });
10507    }
10508
10509    pub fn move_line_down(
10510        &mut self,
10511        _: &MoveLineDown,
10512        window: &mut Window,
10513        cx: &mut Context<Self>,
10514    ) {
10515        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10516
10517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10518        let buffer = self.buffer.read(cx).snapshot(cx);
10519
10520        let mut edits = Vec::new();
10521        let mut unfold_ranges = Vec::new();
10522        let mut refold_creases = Vec::new();
10523
10524        let selections = self.selections.all::<Point>(cx);
10525        let mut selections = selections.iter().peekable();
10526        let mut contiguous_row_selections = Vec::new();
10527        let mut new_selections = Vec::new();
10528
10529        while let Some(selection) = selections.next() {
10530            // Find all the selections that span a contiguous row range
10531            let (start_row, end_row) = consume_contiguous_rows(
10532                &mut contiguous_row_selections,
10533                selection,
10534                &display_map,
10535                &mut selections,
10536            );
10537
10538            // Move the text spanned by the row range to be after the last line of the row range
10539            if end_row.0 <= buffer.max_point().row {
10540                let range_to_move =
10541                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10542                let insertion_point = display_map
10543                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10544                    .0;
10545
10546                // Don't move lines across excerpt boundaries
10547                if buffer
10548                    .excerpt_containing(range_to_move.start..insertion_point)
10549                    .is_some()
10550                {
10551                    let mut text = String::from("\n");
10552                    text.extend(buffer.text_for_range(range_to_move.clone()));
10553                    text.pop(); // Drop trailing newline
10554                    edits.push((
10555                        buffer.anchor_after(range_to_move.start)
10556                            ..buffer.anchor_before(range_to_move.end),
10557                        String::new(),
10558                    ));
10559                    let insertion_anchor = buffer.anchor_after(insertion_point);
10560                    edits.push((insertion_anchor..insertion_anchor, text));
10561
10562                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10563
10564                    // Move selections down
10565                    new_selections.extend(contiguous_row_selections.drain(..).map(
10566                        |mut selection| {
10567                            selection.start.row += row_delta;
10568                            selection.end.row += row_delta;
10569                            selection
10570                        },
10571                    ));
10572
10573                    // Move folds down
10574                    unfold_ranges.push(range_to_move.clone());
10575                    for fold in display_map.folds_in_range(
10576                        buffer.anchor_before(range_to_move.start)
10577                            ..buffer.anchor_after(range_to_move.end),
10578                    ) {
10579                        let mut start = fold.range.start.to_point(&buffer);
10580                        let mut end = fold.range.end.to_point(&buffer);
10581                        start.row += row_delta;
10582                        end.row += row_delta;
10583                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10584                    }
10585                }
10586            }
10587
10588            // If we didn't move line(s), preserve the existing selections
10589            new_selections.append(&mut contiguous_row_selections);
10590        }
10591
10592        self.transact(window, cx, |this, window, cx| {
10593            this.unfold_ranges(&unfold_ranges, true, true, cx);
10594            this.buffer.update(cx, |buffer, cx| {
10595                for (range, text) in edits {
10596                    buffer.edit([(range, text)], None, cx);
10597                }
10598            });
10599            this.fold_creases(refold_creases, true, window, cx);
10600            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10601                s.select(new_selections)
10602            });
10603        });
10604    }
10605
10606    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10607        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10608        let text_layout_details = &self.text_layout_details(window);
10609        self.transact(window, cx, |this, window, cx| {
10610            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10611                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10612                s.move_with(|display_map, selection| {
10613                    if !selection.is_empty() {
10614                        return;
10615                    }
10616
10617                    let mut head = selection.head();
10618                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10619                    if head.column() == display_map.line_len(head.row()) {
10620                        transpose_offset = display_map
10621                            .buffer_snapshot
10622                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10623                    }
10624
10625                    if transpose_offset == 0 {
10626                        return;
10627                    }
10628
10629                    *head.column_mut() += 1;
10630                    head = display_map.clip_point(head, Bias::Right);
10631                    let goal = SelectionGoal::HorizontalPosition(
10632                        display_map
10633                            .x_for_display_point(head, text_layout_details)
10634                            .into(),
10635                    );
10636                    selection.collapse_to(head, goal);
10637
10638                    let transpose_start = display_map
10639                        .buffer_snapshot
10640                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10641                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10642                        let transpose_end = display_map
10643                            .buffer_snapshot
10644                            .clip_offset(transpose_offset + 1, Bias::Right);
10645                        if let Some(ch) =
10646                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10647                        {
10648                            edits.push((transpose_start..transpose_offset, String::new()));
10649                            edits.push((transpose_end..transpose_end, ch.to_string()));
10650                        }
10651                    }
10652                });
10653                edits
10654            });
10655            this.buffer
10656                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10657            let selections = this.selections.all::<usize>(cx);
10658            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10659                s.select(selections);
10660            });
10661        });
10662    }
10663
10664    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10665        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10666        self.rewrap_impl(RewrapOptions::default(), cx)
10667    }
10668
10669    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10670        let buffer = self.buffer.read(cx).snapshot(cx);
10671        let selections = self.selections.all::<Point>(cx);
10672        let mut selections = selections.iter().peekable();
10673
10674        let mut edits = Vec::new();
10675        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10676
10677        while let Some(selection) = selections.next() {
10678            let mut start_row = selection.start.row;
10679            let mut end_row = selection.end.row;
10680
10681            // Skip selections that overlap with a range that has already been rewrapped.
10682            let selection_range = start_row..end_row;
10683            if rewrapped_row_ranges
10684                .iter()
10685                .any(|range| range.overlaps(&selection_range))
10686            {
10687                continue;
10688            }
10689
10690            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10691
10692            // Since not all lines in the selection may be at the same indent
10693            // level, choose the indent size that is the most common between all
10694            // of the lines.
10695            //
10696            // If there is a tie, we use the deepest indent.
10697            let (indent_size, indent_end) = {
10698                let mut indent_size_occurrences = HashMap::default();
10699                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10700
10701                for row in start_row..=end_row {
10702                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10703                    rows_by_indent_size.entry(indent).or_default().push(row);
10704                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10705                }
10706
10707                let indent_size = indent_size_occurrences
10708                    .into_iter()
10709                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10710                    .map(|(indent, _)| indent)
10711                    .unwrap_or_default();
10712                let row = rows_by_indent_size[&indent_size][0];
10713                let indent_end = Point::new(row, indent_size.len);
10714
10715                (indent_size, indent_end)
10716            };
10717
10718            let mut line_prefix = indent_size.chars().collect::<String>();
10719
10720            let mut inside_comment = false;
10721            if let Some(comment_prefix) =
10722                buffer
10723                    .language_scope_at(selection.head())
10724                    .and_then(|language| {
10725                        language
10726                            .line_comment_prefixes()
10727                            .iter()
10728                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10729                            .cloned()
10730                    })
10731            {
10732                line_prefix.push_str(&comment_prefix);
10733                inside_comment = true;
10734            }
10735
10736            let language_settings = buffer.language_settings_at(selection.head(), cx);
10737            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10738                RewrapBehavior::InComments => inside_comment,
10739                RewrapBehavior::InSelections => !selection.is_empty(),
10740                RewrapBehavior::Anywhere => true,
10741            };
10742
10743            let should_rewrap = options.override_language_settings
10744                || allow_rewrap_based_on_language
10745                || self.hard_wrap.is_some();
10746            if !should_rewrap {
10747                continue;
10748            }
10749
10750            if selection.is_empty() {
10751                'expand_upwards: while start_row > 0 {
10752                    let prev_row = start_row - 1;
10753                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10754                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10755                    {
10756                        start_row = prev_row;
10757                    } else {
10758                        break 'expand_upwards;
10759                    }
10760                }
10761
10762                'expand_downwards: while end_row < buffer.max_point().row {
10763                    let next_row = end_row + 1;
10764                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10765                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10766                    {
10767                        end_row = next_row;
10768                    } else {
10769                        break 'expand_downwards;
10770                    }
10771                }
10772            }
10773
10774            let start = Point::new(start_row, 0);
10775            let start_offset = start.to_offset(&buffer);
10776            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10777            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10778            let Some(lines_without_prefixes) = selection_text
10779                .lines()
10780                .map(|line| {
10781                    line.strip_prefix(&line_prefix)
10782                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10783                        .with_context(|| {
10784                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10785                        })
10786                })
10787                .collect::<Result<Vec<_>, _>>()
10788                .log_err()
10789            else {
10790                continue;
10791            };
10792
10793            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10794                buffer
10795                    .language_settings_at(Point::new(start_row, 0), cx)
10796                    .preferred_line_length as usize
10797            });
10798            let wrapped_text = wrap_with_prefix(
10799                line_prefix,
10800                lines_without_prefixes.join("\n"),
10801                wrap_column,
10802                tab_size,
10803                options.preserve_existing_whitespace,
10804            );
10805
10806            // TODO: should always use char-based diff while still supporting cursor behavior that
10807            // matches vim.
10808            let mut diff_options = DiffOptions::default();
10809            if options.override_language_settings {
10810                diff_options.max_word_diff_len = 0;
10811                diff_options.max_word_diff_line_count = 0;
10812            } else {
10813                diff_options.max_word_diff_len = usize::MAX;
10814                diff_options.max_word_diff_line_count = usize::MAX;
10815            }
10816
10817            for (old_range, new_text) in
10818                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10819            {
10820                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10821                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10822                edits.push((edit_start..edit_end, new_text));
10823            }
10824
10825            rewrapped_row_ranges.push(start_row..=end_row);
10826        }
10827
10828        self.buffer
10829            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10830    }
10831
10832    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10833        let mut text = String::new();
10834        let buffer = self.buffer.read(cx).snapshot(cx);
10835        let mut selections = self.selections.all::<Point>(cx);
10836        let mut clipboard_selections = Vec::with_capacity(selections.len());
10837        {
10838            let max_point = buffer.max_point();
10839            let mut is_first = true;
10840            for selection in &mut selections {
10841                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10842                if is_entire_line {
10843                    selection.start = Point::new(selection.start.row, 0);
10844                    if !selection.is_empty() && selection.end.column == 0 {
10845                        selection.end = cmp::min(max_point, selection.end);
10846                    } else {
10847                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10848                    }
10849                    selection.goal = SelectionGoal::None;
10850                }
10851                if is_first {
10852                    is_first = false;
10853                } else {
10854                    text += "\n";
10855                }
10856                let mut len = 0;
10857                for chunk in buffer.text_for_range(selection.start..selection.end) {
10858                    text.push_str(chunk);
10859                    len += chunk.len();
10860                }
10861                clipboard_selections.push(ClipboardSelection {
10862                    len,
10863                    is_entire_line,
10864                    first_line_indent: buffer
10865                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10866                        .len,
10867                });
10868            }
10869        }
10870
10871        self.transact(window, cx, |this, window, cx| {
10872            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10873                s.select(selections);
10874            });
10875            this.insert("", window, cx);
10876        });
10877        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10878    }
10879
10880    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10881        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10882        let item = self.cut_common(window, cx);
10883        cx.write_to_clipboard(item);
10884    }
10885
10886    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10887        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10888        self.change_selections(None, window, cx, |s| {
10889            s.move_with(|snapshot, sel| {
10890                if sel.is_empty() {
10891                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10892                }
10893            });
10894        });
10895        let item = self.cut_common(window, cx);
10896        cx.set_global(KillRing(item))
10897    }
10898
10899    pub fn kill_ring_yank(
10900        &mut self,
10901        _: &KillRingYank,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10906        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10907            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10908                (kill_ring.text().to_string(), kill_ring.metadata_json())
10909            } else {
10910                return;
10911            }
10912        } else {
10913            return;
10914        };
10915        self.do_paste(&text, metadata, false, window, cx);
10916    }
10917
10918    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10919        self.do_copy(true, cx);
10920    }
10921
10922    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10923        self.do_copy(false, cx);
10924    }
10925
10926    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10927        let selections = self.selections.all::<Point>(cx);
10928        let buffer = self.buffer.read(cx).read(cx);
10929        let mut text = String::new();
10930
10931        let mut clipboard_selections = Vec::with_capacity(selections.len());
10932        {
10933            let max_point = buffer.max_point();
10934            let mut is_first = true;
10935            for selection in &selections {
10936                let mut start = selection.start;
10937                let mut end = selection.end;
10938                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10939                if is_entire_line {
10940                    start = Point::new(start.row, 0);
10941                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10942                }
10943
10944                let mut trimmed_selections = Vec::new();
10945                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10946                    let row = MultiBufferRow(start.row);
10947                    let first_indent = buffer.indent_size_for_line(row);
10948                    if first_indent.len == 0 || start.column > first_indent.len {
10949                        trimmed_selections.push(start..end);
10950                    } else {
10951                        trimmed_selections.push(
10952                            Point::new(row.0, first_indent.len)
10953                                ..Point::new(row.0, buffer.line_len(row)),
10954                        );
10955                        for row in start.row + 1..=end.row {
10956                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10957                            if row == end.row {
10958                                line_len = end.column;
10959                            }
10960                            if line_len == 0 {
10961                                trimmed_selections
10962                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10963                                continue;
10964                            }
10965                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10966                            if row_indent_size.len >= first_indent.len {
10967                                trimmed_selections.push(
10968                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10969                                );
10970                            } else {
10971                                trimmed_selections.clear();
10972                                trimmed_selections.push(start..end);
10973                                break;
10974                            }
10975                        }
10976                    }
10977                } else {
10978                    trimmed_selections.push(start..end);
10979                }
10980
10981                for trimmed_range in trimmed_selections {
10982                    if is_first {
10983                        is_first = false;
10984                    } else {
10985                        text += "\n";
10986                    }
10987                    let mut len = 0;
10988                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10989                        text.push_str(chunk);
10990                        len += chunk.len();
10991                    }
10992                    clipboard_selections.push(ClipboardSelection {
10993                        len,
10994                        is_entire_line,
10995                        first_line_indent: buffer
10996                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10997                            .len,
10998                    });
10999                }
11000            }
11001        }
11002
11003        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11004            text,
11005            clipboard_selections,
11006        ));
11007    }
11008
11009    pub fn do_paste(
11010        &mut self,
11011        text: &String,
11012        clipboard_selections: Option<Vec<ClipboardSelection>>,
11013        handle_entire_lines: bool,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        if self.read_only(cx) {
11018            return;
11019        }
11020
11021        let clipboard_text = Cow::Borrowed(text);
11022
11023        self.transact(window, cx, |this, window, cx| {
11024            if let Some(mut clipboard_selections) = clipboard_selections {
11025                let old_selections = this.selections.all::<usize>(cx);
11026                let all_selections_were_entire_line =
11027                    clipboard_selections.iter().all(|s| s.is_entire_line);
11028                let first_selection_indent_column =
11029                    clipboard_selections.first().map(|s| s.first_line_indent);
11030                if clipboard_selections.len() != old_selections.len() {
11031                    clipboard_selections.drain(..);
11032                }
11033                let cursor_offset = this.selections.last::<usize>(cx).head();
11034                let mut auto_indent_on_paste = true;
11035
11036                this.buffer.update(cx, |buffer, cx| {
11037                    let snapshot = buffer.read(cx);
11038                    auto_indent_on_paste = snapshot
11039                        .language_settings_at(cursor_offset, cx)
11040                        .auto_indent_on_paste;
11041
11042                    let mut start_offset = 0;
11043                    let mut edits = Vec::new();
11044                    let mut original_indent_columns = Vec::new();
11045                    for (ix, selection) in old_selections.iter().enumerate() {
11046                        let to_insert;
11047                        let entire_line;
11048                        let original_indent_column;
11049                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11050                            let end_offset = start_offset + clipboard_selection.len;
11051                            to_insert = &clipboard_text[start_offset..end_offset];
11052                            entire_line = clipboard_selection.is_entire_line;
11053                            start_offset = end_offset + 1;
11054                            original_indent_column = Some(clipboard_selection.first_line_indent);
11055                        } else {
11056                            to_insert = clipboard_text.as_str();
11057                            entire_line = all_selections_were_entire_line;
11058                            original_indent_column = first_selection_indent_column
11059                        }
11060
11061                        // If the corresponding selection was empty when this slice of the
11062                        // clipboard text was written, then the entire line containing the
11063                        // selection was copied. If this selection is also currently empty,
11064                        // then paste the line before the current line of the buffer.
11065                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11066                            let column = selection.start.to_point(&snapshot).column as usize;
11067                            let line_start = selection.start - column;
11068                            line_start..line_start
11069                        } else {
11070                            selection.range()
11071                        };
11072
11073                        edits.push((range, to_insert));
11074                        original_indent_columns.push(original_indent_column);
11075                    }
11076                    drop(snapshot);
11077
11078                    buffer.edit(
11079                        edits,
11080                        if auto_indent_on_paste {
11081                            Some(AutoindentMode::Block {
11082                                original_indent_columns,
11083                            })
11084                        } else {
11085                            None
11086                        },
11087                        cx,
11088                    );
11089                });
11090
11091                let selections = this.selections.all::<usize>(cx);
11092                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11093                    s.select(selections)
11094                });
11095            } else {
11096                this.insert(&clipboard_text, window, cx);
11097            }
11098        });
11099    }
11100
11101    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11102        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11103        if let Some(item) = cx.read_from_clipboard() {
11104            let entries = item.entries();
11105
11106            match entries.first() {
11107                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11108                // of all the pasted entries.
11109                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11110                    .do_paste(
11111                        clipboard_string.text(),
11112                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11113                        true,
11114                        window,
11115                        cx,
11116                    ),
11117                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11118            }
11119        }
11120    }
11121
11122    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11123        if self.read_only(cx) {
11124            return;
11125        }
11126
11127        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11128
11129        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11130            if let Some((selections, _)) =
11131                self.selection_history.transaction(transaction_id).cloned()
11132            {
11133                self.change_selections(None, window, cx, |s| {
11134                    s.select_anchors(selections.to_vec());
11135                });
11136            } else {
11137                log::error!(
11138                    "No entry in selection_history found for undo. \
11139                     This may correspond to a bug where undo does not update the selection. \
11140                     If this is occurring, please add details to \
11141                     https://github.com/zed-industries/zed/issues/22692"
11142                );
11143            }
11144            self.request_autoscroll(Autoscroll::fit(), cx);
11145            self.unmark_text(window, cx);
11146            self.refresh_inline_completion(true, false, window, cx);
11147            cx.emit(EditorEvent::Edited { transaction_id });
11148            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11149        }
11150    }
11151
11152    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11153        if self.read_only(cx) {
11154            return;
11155        }
11156
11157        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11158
11159        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11160            if let Some((_, Some(selections))) =
11161                self.selection_history.transaction(transaction_id).cloned()
11162            {
11163                self.change_selections(None, window, cx, |s| {
11164                    s.select_anchors(selections.to_vec());
11165                });
11166            } else {
11167                log::error!(
11168                    "No entry in selection_history found for redo. \
11169                     This may correspond to a bug where undo does not update the selection. \
11170                     If this is occurring, please add details to \
11171                     https://github.com/zed-industries/zed/issues/22692"
11172                );
11173            }
11174            self.request_autoscroll(Autoscroll::fit(), cx);
11175            self.unmark_text(window, cx);
11176            self.refresh_inline_completion(true, false, window, cx);
11177            cx.emit(EditorEvent::Edited { transaction_id });
11178        }
11179    }
11180
11181    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11182        self.buffer
11183            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11184    }
11185
11186    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11187        self.buffer
11188            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11189    }
11190
11191    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11192        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11193        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11194            s.move_with(|map, selection| {
11195                let cursor = if selection.is_empty() {
11196                    movement::left(map, selection.start)
11197                } else {
11198                    selection.start
11199                };
11200                selection.collapse_to(cursor, SelectionGoal::None);
11201            });
11202        })
11203    }
11204
11205    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11206        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11207        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11208            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11209        })
11210    }
11211
11212    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11213        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11214        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11215            s.move_with(|map, selection| {
11216                let cursor = if selection.is_empty() {
11217                    movement::right(map, selection.end)
11218                } else {
11219                    selection.end
11220                };
11221                selection.collapse_to(cursor, SelectionGoal::None)
11222            });
11223        })
11224    }
11225
11226    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11227        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11228        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11229            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11230        })
11231    }
11232
11233    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11234        if self.take_rename(true, window, cx).is_some() {
11235            return;
11236        }
11237
11238        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11239            cx.propagate();
11240            return;
11241        }
11242
11243        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11244
11245        let text_layout_details = &self.text_layout_details(window);
11246        let selection_count = self.selections.count();
11247        let first_selection = self.selections.first_anchor();
11248
11249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11250            s.move_with(|map, selection| {
11251                if !selection.is_empty() {
11252                    selection.goal = SelectionGoal::None;
11253                }
11254                let (cursor, goal) = movement::up(
11255                    map,
11256                    selection.start,
11257                    selection.goal,
11258                    false,
11259                    text_layout_details,
11260                );
11261                selection.collapse_to(cursor, goal);
11262            });
11263        });
11264
11265        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11266        {
11267            cx.propagate();
11268        }
11269    }
11270
11271    pub fn move_up_by_lines(
11272        &mut self,
11273        action: &MoveUpByLines,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276    ) {
11277        if self.take_rename(true, window, cx).is_some() {
11278            return;
11279        }
11280
11281        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11282            cx.propagate();
11283            return;
11284        }
11285
11286        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11287
11288        let text_layout_details = &self.text_layout_details(window);
11289
11290        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11291            s.move_with(|map, selection| {
11292                if !selection.is_empty() {
11293                    selection.goal = SelectionGoal::None;
11294                }
11295                let (cursor, goal) = movement::up_by_rows(
11296                    map,
11297                    selection.start,
11298                    action.lines,
11299                    selection.goal,
11300                    false,
11301                    text_layout_details,
11302                );
11303                selection.collapse_to(cursor, goal);
11304            });
11305        })
11306    }
11307
11308    pub fn move_down_by_lines(
11309        &mut self,
11310        action: &MoveDownByLines,
11311        window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        if self.take_rename(true, window, cx).is_some() {
11315            return;
11316        }
11317
11318        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11319            cx.propagate();
11320            return;
11321        }
11322
11323        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11324
11325        let text_layout_details = &self.text_layout_details(window);
11326
11327        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11328            s.move_with(|map, selection| {
11329                if !selection.is_empty() {
11330                    selection.goal = SelectionGoal::None;
11331                }
11332                let (cursor, goal) = movement::down_by_rows(
11333                    map,
11334                    selection.start,
11335                    action.lines,
11336                    selection.goal,
11337                    false,
11338                    text_layout_details,
11339                );
11340                selection.collapse_to(cursor, goal);
11341            });
11342        })
11343    }
11344
11345    pub fn select_down_by_lines(
11346        &mut self,
11347        action: &SelectDownByLines,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) {
11351        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11352        let text_layout_details = &self.text_layout_details(window);
11353        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11354            s.move_heads_with(|map, head, goal| {
11355                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11356            })
11357        })
11358    }
11359
11360    pub fn select_up_by_lines(
11361        &mut self,
11362        action: &SelectUpByLines,
11363        window: &mut Window,
11364        cx: &mut Context<Self>,
11365    ) {
11366        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11367        let text_layout_details = &self.text_layout_details(window);
11368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11369            s.move_heads_with(|map, head, goal| {
11370                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11371            })
11372        })
11373    }
11374
11375    pub fn select_page_up(
11376        &mut self,
11377        _: &SelectPageUp,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        let Some(row_count) = self.visible_row_count() else {
11382            return;
11383        };
11384
11385        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11386
11387        let text_layout_details = &self.text_layout_details(window);
11388
11389        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11390            s.move_heads_with(|map, head, goal| {
11391                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11392            })
11393        })
11394    }
11395
11396    pub fn move_page_up(
11397        &mut self,
11398        action: &MovePageUp,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        if self.take_rename(true, window, cx).is_some() {
11403            return;
11404        }
11405
11406        if self
11407            .context_menu
11408            .borrow_mut()
11409            .as_mut()
11410            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11411            .unwrap_or(false)
11412        {
11413            return;
11414        }
11415
11416        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11417            cx.propagate();
11418            return;
11419        }
11420
11421        let Some(row_count) = self.visible_row_count() else {
11422            return;
11423        };
11424
11425        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11426
11427        let autoscroll = if action.center_cursor {
11428            Autoscroll::center()
11429        } else {
11430            Autoscroll::fit()
11431        };
11432
11433        let text_layout_details = &self.text_layout_details(window);
11434
11435        self.change_selections(Some(autoscroll), window, cx, |s| {
11436            s.move_with(|map, selection| {
11437                if !selection.is_empty() {
11438                    selection.goal = SelectionGoal::None;
11439                }
11440                let (cursor, goal) = movement::up_by_rows(
11441                    map,
11442                    selection.end,
11443                    row_count,
11444                    selection.goal,
11445                    false,
11446                    text_layout_details,
11447                );
11448                selection.collapse_to(cursor, goal);
11449            });
11450        });
11451    }
11452
11453    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11454        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11455        let text_layout_details = &self.text_layout_details(window);
11456        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11457            s.move_heads_with(|map, head, goal| {
11458                movement::up(map, head, goal, false, text_layout_details)
11459            })
11460        })
11461    }
11462
11463    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11464        self.take_rename(true, window, cx);
11465
11466        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11467            cx.propagate();
11468            return;
11469        }
11470
11471        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11472
11473        let text_layout_details = &self.text_layout_details(window);
11474        let selection_count = self.selections.count();
11475        let first_selection = self.selections.first_anchor();
11476
11477        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11478            s.move_with(|map, selection| {
11479                if !selection.is_empty() {
11480                    selection.goal = SelectionGoal::None;
11481                }
11482                let (cursor, goal) = movement::down(
11483                    map,
11484                    selection.end,
11485                    selection.goal,
11486                    false,
11487                    text_layout_details,
11488                );
11489                selection.collapse_to(cursor, goal);
11490            });
11491        });
11492
11493        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11494        {
11495            cx.propagate();
11496        }
11497    }
11498
11499    pub fn select_page_down(
11500        &mut self,
11501        _: &SelectPageDown,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) {
11505        let Some(row_count) = self.visible_row_count() else {
11506            return;
11507        };
11508
11509        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11510
11511        let text_layout_details = &self.text_layout_details(window);
11512
11513        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11514            s.move_heads_with(|map, head, goal| {
11515                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11516            })
11517        })
11518    }
11519
11520    pub fn move_page_down(
11521        &mut self,
11522        action: &MovePageDown,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        if self.take_rename(true, window, cx).is_some() {
11527            return;
11528        }
11529
11530        if self
11531            .context_menu
11532            .borrow_mut()
11533            .as_mut()
11534            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11535            .unwrap_or(false)
11536        {
11537            return;
11538        }
11539
11540        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11541            cx.propagate();
11542            return;
11543        }
11544
11545        let Some(row_count) = self.visible_row_count() else {
11546            return;
11547        };
11548
11549        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11550
11551        let autoscroll = if action.center_cursor {
11552            Autoscroll::center()
11553        } else {
11554            Autoscroll::fit()
11555        };
11556
11557        let text_layout_details = &self.text_layout_details(window);
11558        self.change_selections(Some(autoscroll), window, cx, |s| {
11559            s.move_with(|map, selection| {
11560                if !selection.is_empty() {
11561                    selection.goal = SelectionGoal::None;
11562                }
11563                let (cursor, goal) = movement::down_by_rows(
11564                    map,
11565                    selection.end,
11566                    row_count,
11567                    selection.goal,
11568                    false,
11569                    text_layout_details,
11570                );
11571                selection.collapse_to(cursor, goal);
11572            });
11573        });
11574    }
11575
11576    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11577        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11578        let text_layout_details = &self.text_layout_details(window);
11579        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11580            s.move_heads_with(|map, head, goal| {
11581                movement::down(map, head, goal, false, text_layout_details)
11582            })
11583        });
11584    }
11585
11586    pub fn context_menu_first(
11587        &mut self,
11588        _: &ContextMenuFirst,
11589        window: &mut Window,
11590        cx: &mut Context<Self>,
11591    ) {
11592        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11593            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11594        }
11595    }
11596
11597    pub fn context_menu_prev(
11598        &mut self,
11599        _: &ContextMenuPrevious,
11600        window: &mut Window,
11601        cx: &mut Context<Self>,
11602    ) {
11603        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11604            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11605        }
11606    }
11607
11608    pub fn context_menu_next(
11609        &mut self,
11610        _: &ContextMenuNext,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11615            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11616        }
11617    }
11618
11619    pub fn context_menu_last(
11620        &mut self,
11621        _: &ContextMenuLast,
11622        window: &mut Window,
11623        cx: &mut Context<Self>,
11624    ) {
11625        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11626            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11627        }
11628    }
11629
11630    pub fn move_to_previous_word_start(
11631        &mut self,
11632        _: &MoveToPreviousWordStart,
11633        window: &mut Window,
11634        cx: &mut Context<Self>,
11635    ) {
11636        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11637        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11638            s.move_cursors_with(|map, head, _| {
11639                (
11640                    movement::previous_word_start(map, head),
11641                    SelectionGoal::None,
11642                )
11643            });
11644        })
11645    }
11646
11647    pub fn move_to_previous_subword_start(
11648        &mut self,
11649        _: &MoveToPreviousSubwordStart,
11650        window: &mut Window,
11651        cx: &mut Context<Self>,
11652    ) {
11653        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11654        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11655            s.move_cursors_with(|map, head, _| {
11656                (
11657                    movement::previous_subword_start(map, head),
11658                    SelectionGoal::None,
11659                )
11660            });
11661        })
11662    }
11663
11664    pub fn select_to_previous_word_start(
11665        &mut self,
11666        _: &SelectToPreviousWordStart,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11671        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11672            s.move_heads_with(|map, head, _| {
11673                (
11674                    movement::previous_word_start(map, head),
11675                    SelectionGoal::None,
11676                )
11677            });
11678        })
11679    }
11680
11681    pub fn select_to_previous_subword_start(
11682        &mut self,
11683        _: &SelectToPreviousSubwordStart,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11688        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11689            s.move_heads_with(|map, head, _| {
11690                (
11691                    movement::previous_subword_start(map, head),
11692                    SelectionGoal::None,
11693                )
11694            });
11695        })
11696    }
11697
11698    pub fn delete_to_previous_word_start(
11699        &mut self,
11700        action: &DeleteToPreviousWordStart,
11701        window: &mut Window,
11702        cx: &mut Context<Self>,
11703    ) {
11704        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11705        self.transact(window, cx, |this, window, cx| {
11706            this.select_autoclose_pair(window, cx);
11707            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11708                s.move_with(|map, selection| {
11709                    if selection.is_empty() {
11710                        let cursor = if action.ignore_newlines {
11711                            movement::previous_word_start(map, selection.head())
11712                        } else {
11713                            movement::previous_word_start_or_newline(map, selection.head())
11714                        };
11715                        selection.set_head(cursor, SelectionGoal::None);
11716                    }
11717                });
11718            });
11719            this.insert("", window, cx);
11720        });
11721    }
11722
11723    pub fn delete_to_previous_subword_start(
11724        &mut self,
11725        _: &DeleteToPreviousSubwordStart,
11726        window: &mut Window,
11727        cx: &mut Context<Self>,
11728    ) {
11729        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11730        self.transact(window, cx, |this, window, cx| {
11731            this.select_autoclose_pair(window, cx);
11732            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11733                s.move_with(|map, selection| {
11734                    if selection.is_empty() {
11735                        let cursor = movement::previous_subword_start(map, selection.head());
11736                        selection.set_head(cursor, SelectionGoal::None);
11737                    }
11738                });
11739            });
11740            this.insert("", window, cx);
11741        });
11742    }
11743
11744    pub fn move_to_next_word_end(
11745        &mut self,
11746        _: &MoveToNextWordEnd,
11747        window: &mut Window,
11748        cx: &mut Context<Self>,
11749    ) {
11750        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11751        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11752            s.move_cursors_with(|map, head, _| {
11753                (movement::next_word_end(map, head), SelectionGoal::None)
11754            });
11755        })
11756    }
11757
11758    pub fn move_to_next_subword_end(
11759        &mut self,
11760        _: &MoveToNextSubwordEnd,
11761        window: &mut Window,
11762        cx: &mut Context<Self>,
11763    ) {
11764        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11765        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11766            s.move_cursors_with(|map, head, _| {
11767                (movement::next_subword_end(map, head), SelectionGoal::None)
11768            });
11769        })
11770    }
11771
11772    pub fn select_to_next_word_end(
11773        &mut self,
11774        _: &SelectToNextWordEnd,
11775        window: &mut Window,
11776        cx: &mut Context<Self>,
11777    ) {
11778        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11779        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11780            s.move_heads_with(|map, head, _| {
11781                (movement::next_word_end(map, head), SelectionGoal::None)
11782            });
11783        })
11784    }
11785
11786    pub fn select_to_next_subword_end(
11787        &mut self,
11788        _: &SelectToNextSubwordEnd,
11789        window: &mut Window,
11790        cx: &mut Context<Self>,
11791    ) {
11792        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11793        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11794            s.move_heads_with(|map, head, _| {
11795                (movement::next_subword_end(map, head), SelectionGoal::None)
11796            });
11797        })
11798    }
11799
11800    pub fn delete_to_next_word_end(
11801        &mut self,
11802        action: &DeleteToNextWordEnd,
11803        window: &mut Window,
11804        cx: &mut Context<Self>,
11805    ) {
11806        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11807        self.transact(window, cx, |this, window, cx| {
11808            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11809                s.move_with(|map, selection| {
11810                    if selection.is_empty() {
11811                        let cursor = if action.ignore_newlines {
11812                            movement::next_word_end(map, selection.head())
11813                        } else {
11814                            movement::next_word_end_or_newline(map, selection.head())
11815                        };
11816                        selection.set_head(cursor, SelectionGoal::None);
11817                    }
11818                });
11819            });
11820            this.insert("", window, cx);
11821        });
11822    }
11823
11824    pub fn delete_to_next_subword_end(
11825        &mut self,
11826        _: &DeleteToNextSubwordEnd,
11827        window: &mut Window,
11828        cx: &mut Context<Self>,
11829    ) {
11830        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11831        self.transact(window, cx, |this, window, cx| {
11832            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11833                s.move_with(|map, selection| {
11834                    if selection.is_empty() {
11835                        let cursor = movement::next_subword_end(map, selection.head());
11836                        selection.set_head(cursor, SelectionGoal::None);
11837                    }
11838                });
11839            });
11840            this.insert("", window, cx);
11841        });
11842    }
11843
11844    pub fn move_to_beginning_of_line(
11845        &mut self,
11846        action: &MoveToBeginningOfLine,
11847        window: &mut Window,
11848        cx: &mut Context<Self>,
11849    ) {
11850        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11851        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11852            s.move_cursors_with(|map, head, _| {
11853                (
11854                    movement::indented_line_beginning(
11855                        map,
11856                        head,
11857                        action.stop_at_soft_wraps,
11858                        action.stop_at_indent,
11859                    ),
11860                    SelectionGoal::None,
11861                )
11862            });
11863        })
11864    }
11865
11866    pub fn select_to_beginning_of_line(
11867        &mut self,
11868        action: &SelectToBeginningOfLine,
11869        window: &mut Window,
11870        cx: &mut Context<Self>,
11871    ) {
11872        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11873        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11874            s.move_heads_with(|map, head, _| {
11875                (
11876                    movement::indented_line_beginning(
11877                        map,
11878                        head,
11879                        action.stop_at_soft_wraps,
11880                        action.stop_at_indent,
11881                    ),
11882                    SelectionGoal::None,
11883                )
11884            });
11885        });
11886    }
11887
11888    pub fn delete_to_beginning_of_line(
11889        &mut self,
11890        action: &DeleteToBeginningOfLine,
11891        window: &mut Window,
11892        cx: &mut Context<Self>,
11893    ) {
11894        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11895        self.transact(window, cx, |this, window, cx| {
11896            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11897                s.move_with(|_, selection| {
11898                    selection.reversed = true;
11899                });
11900            });
11901
11902            this.select_to_beginning_of_line(
11903                &SelectToBeginningOfLine {
11904                    stop_at_soft_wraps: false,
11905                    stop_at_indent: action.stop_at_indent,
11906                },
11907                window,
11908                cx,
11909            );
11910            this.backspace(&Backspace, window, cx);
11911        });
11912    }
11913
11914    pub fn move_to_end_of_line(
11915        &mut self,
11916        action: &MoveToEndOfLine,
11917        window: &mut Window,
11918        cx: &mut Context<Self>,
11919    ) {
11920        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11921        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11922            s.move_cursors_with(|map, head, _| {
11923                (
11924                    movement::line_end(map, head, action.stop_at_soft_wraps),
11925                    SelectionGoal::None,
11926                )
11927            });
11928        })
11929    }
11930
11931    pub fn select_to_end_of_line(
11932        &mut self,
11933        action: &SelectToEndOfLine,
11934        window: &mut Window,
11935        cx: &mut Context<Self>,
11936    ) {
11937        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11938        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11939            s.move_heads_with(|map, head, _| {
11940                (
11941                    movement::line_end(map, head, action.stop_at_soft_wraps),
11942                    SelectionGoal::None,
11943                )
11944            });
11945        })
11946    }
11947
11948    pub fn delete_to_end_of_line(
11949        &mut self,
11950        _: &DeleteToEndOfLine,
11951        window: &mut Window,
11952        cx: &mut Context<Self>,
11953    ) {
11954        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11955        self.transact(window, cx, |this, window, cx| {
11956            this.select_to_end_of_line(
11957                &SelectToEndOfLine {
11958                    stop_at_soft_wraps: false,
11959                },
11960                window,
11961                cx,
11962            );
11963            this.delete(&Delete, window, cx);
11964        });
11965    }
11966
11967    pub fn cut_to_end_of_line(
11968        &mut self,
11969        _: &CutToEndOfLine,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11974        self.transact(window, cx, |this, window, cx| {
11975            this.select_to_end_of_line(
11976                &SelectToEndOfLine {
11977                    stop_at_soft_wraps: false,
11978                },
11979                window,
11980                cx,
11981            );
11982            this.cut(&Cut, window, cx);
11983        });
11984    }
11985
11986    pub fn move_to_start_of_paragraph(
11987        &mut self,
11988        _: &MoveToStartOfParagraph,
11989        window: &mut Window,
11990        cx: &mut Context<Self>,
11991    ) {
11992        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11993            cx.propagate();
11994            return;
11995        }
11996        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11997        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11998            s.move_with(|map, selection| {
11999                selection.collapse_to(
12000                    movement::start_of_paragraph(map, selection.head(), 1),
12001                    SelectionGoal::None,
12002                )
12003            });
12004        })
12005    }
12006
12007    pub fn move_to_end_of_paragraph(
12008        &mut self,
12009        _: &MoveToEndOfParagraph,
12010        window: &mut Window,
12011        cx: &mut Context<Self>,
12012    ) {
12013        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12014            cx.propagate();
12015            return;
12016        }
12017        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12018        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12019            s.move_with(|map, selection| {
12020                selection.collapse_to(
12021                    movement::end_of_paragraph(map, selection.head(), 1),
12022                    SelectionGoal::None,
12023                )
12024            });
12025        })
12026    }
12027
12028    pub fn select_to_start_of_paragraph(
12029        &mut self,
12030        _: &SelectToStartOfParagraph,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12035            cx.propagate();
12036            return;
12037        }
12038        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12039        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12040            s.move_heads_with(|map, head, _| {
12041                (
12042                    movement::start_of_paragraph(map, head, 1),
12043                    SelectionGoal::None,
12044                )
12045            });
12046        })
12047    }
12048
12049    pub fn select_to_end_of_paragraph(
12050        &mut self,
12051        _: &SelectToEndOfParagraph,
12052        window: &mut Window,
12053        cx: &mut Context<Self>,
12054    ) {
12055        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12056            cx.propagate();
12057            return;
12058        }
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12061            s.move_heads_with(|map, head, _| {
12062                (
12063                    movement::end_of_paragraph(map, head, 1),
12064                    SelectionGoal::None,
12065                )
12066            });
12067        })
12068    }
12069
12070    pub fn move_to_start_of_excerpt(
12071        &mut self,
12072        _: &MoveToStartOfExcerpt,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12077            cx.propagate();
12078            return;
12079        }
12080        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12081        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12082            s.move_with(|map, selection| {
12083                selection.collapse_to(
12084                    movement::start_of_excerpt(
12085                        map,
12086                        selection.head(),
12087                        workspace::searchable::Direction::Prev,
12088                    ),
12089                    SelectionGoal::None,
12090                )
12091            });
12092        })
12093    }
12094
12095    pub fn move_to_start_of_next_excerpt(
12096        &mut self,
12097        _: &MoveToStartOfNextExcerpt,
12098        window: &mut Window,
12099        cx: &mut Context<Self>,
12100    ) {
12101        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12102            cx.propagate();
12103            return;
12104        }
12105
12106        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12107            s.move_with(|map, selection| {
12108                selection.collapse_to(
12109                    movement::start_of_excerpt(
12110                        map,
12111                        selection.head(),
12112                        workspace::searchable::Direction::Next,
12113                    ),
12114                    SelectionGoal::None,
12115                )
12116            });
12117        })
12118    }
12119
12120    pub fn move_to_end_of_excerpt(
12121        &mut self,
12122        _: &MoveToEndOfExcerpt,
12123        window: &mut Window,
12124        cx: &mut Context<Self>,
12125    ) {
12126        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12127            cx.propagate();
12128            return;
12129        }
12130        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12131        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12132            s.move_with(|map, selection| {
12133                selection.collapse_to(
12134                    movement::end_of_excerpt(
12135                        map,
12136                        selection.head(),
12137                        workspace::searchable::Direction::Next,
12138                    ),
12139                    SelectionGoal::None,
12140                )
12141            });
12142        })
12143    }
12144
12145    pub fn move_to_end_of_previous_excerpt(
12146        &mut self,
12147        _: &MoveToEndOfPreviousExcerpt,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12152            cx.propagate();
12153            return;
12154        }
12155        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12156        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12157            s.move_with(|map, selection| {
12158                selection.collapse_to(
12159                    movement::end_of_excerpt(
12160                        map,
12161                        selection.head(),
12162                        workspace::searchable::Direction::Prev,
12163                    ),
12164                    SelectionGoal::None,
12165                )
12166            });
12167        })
12168    }
12169
12170    pub fn select_to_start_of_excerpt(
12171        &mut self,
12172        _: &SelectToStartOfExcerpt,
12173        window: &mut Window,
12174        cx: &mut Context<Self>,
12175    ) {
12176        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12177            cx.propagate();
12178            return;
12179        }
12180        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12181        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12182            s.move_heads_with(|map, head, _| {
12183                (
12184                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12185                    SelectionGoal::None,
12186                )
12187            });
12188        })
12189    }
12190
12191    pub fn select_to_start_of_next_excerpt(
12192        &mut self,
12193        _: &SelectToStartOfNextExcerpt,
12194        window: &mut Window,
12195        cx: &mut Context<Self>,
12196    ) {
12197        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12198            cx.propagate();
12199            return;
12200        }
12201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12202        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12203            s.move_heads_with(|map, head, _| {
12204                (
12205                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12206                    SelectionGoal::None,
12207                )
12208            });
12209        })
12210    }
12211
12212    pub fn select_to_end_of_excerpt(
12213        &mut self,
12214        _: &SelectToEndOfExcerpt,
12215        window: &mut Window,
12216        cx: &mut Context<Self>,
12217    ) {
12218        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12219            cx.propagate();
12220            return;
12221        }
12222        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12224            s.move_heads_with(|map, head, _| {
12225                (
12226                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12227                    SelectionGoal::None,
12228                )
12229            });
12230        })
12231    }
12232
12233    pub fn select_to_end_of_previous_excerpt(
12234        &mut self,
12235        _: &SelectToEndOfPreviousExcerpt,
12236        window: &mut Window,
12237        cx: &mut Context<Self>,
12238    ) {
12239        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12240            cx.propagate();
12241            return;
12242        }
12243        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12244        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12245            s.move_heads_with(|map, head, _| {
12246                (
12247                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12248                    SelectionGoal::None,
12249                )
12250            });
12251        })
12252    }
12253
12254    pub fn move_to_beginning(
12255        &mut self,
12256        _: &MoveToBeginning,
12257        window: &mut Window,
12258        cx: &mut Context<Self>,
12259    ) {
12260        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12261            cx.propagate();
12262            return;
12263        }
12264        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12265        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12266            s.select_ranges(vec![0..0]);
12267        });
12268    }
12269
12270    pub fn select_to_beginning(
12271        &mut self,
12272        _: &SelectToBeginning,
12273        window: &mut Window,
12274        cx: &mut Context<Self>,
12275    ) {
12276        let mut selection = self.selections.last::<Point>(cx);
12277        selection.set_head(Point::zero(), SelectionGoal::None);
12278        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12279        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12280            s.select(vec![selection]);
12281        });
12282    }
12283
12284    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12285        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12286            cx.propagate();
12287            return;
12288        }
12289        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12290        let cursor = self.buffer.read(cx).read(cx).len();
12291        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12292            s.select_ranges(vec![cursor..cursor])
12293        });
12294    }
12295
12296    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12297        self.nav_history = nav_history;
12298    }
12299
12300    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12301        self.nav_history.as_ref()
12302    }
12303
12304    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12305        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12306    }
12307
12308    fn push_to_nav_history(
12309        &mut self,
12310        cursor_anchor: Anchor,
12311        new_position: Option<Point>,
12312        is_deactivate: bool,
12313        cx: &mut Context<Self>,
12314    ) {
12315        if let Some(nav_history) = self.nav_history.as_mut() {
12316            let buffer = self.buffer.read(cx).read(cx);
12317            let cursor_position = cursor_anchor.to_point(&buffer);
12318            let scroll_state = self.scroll_manager.anchor();
12319            let scroll_top_row = scroll_state.top_row(&buffer);
12320            drop(buffer);
12321
12322            if let Some(new_position) = new_position {
12323                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12324                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12325                    return;
12326                }
12327            }
12328
12329            nav_history.push(
12330                Some(NavigationData {
12331                    cursor_anchor,
12332                    cursor_position,
12333                    scroll_anchor: scroll_state,
12334                    scroll_top_row,
12335                }),
12336                cx,
12337            );
12338            cx.emit(EditorEvent::PushedToNavHistory {
12339                anchor: cursor_anchor,
12340                is_deactivate,
12341            })
12342        }
12343    }
12344
12345    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12346        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12347        let buffer = self.buffer.read(cx).snapshot(cx);
12348        let mut selection = self.selections.first::<usize>(cx);
12349        selection.set_head(buffer.len(), SelectionGoal::None);
12350        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12351            s.select(vec![selection]);
12352        });
12353    }
12354
12355    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12356        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12357        let end = self.buffer.read(cx).read(cx).len();
12358        self.change_selections(None, window, cx, |s| {
12359            s.select_ranges(vec![0..end]);
12360        });
12361    }
12362
12363    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12364        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12366        let mut selections = self.selections.all::<Point>(cx);
12367        let max_point = display_map.buffer_snapshot.max_point();
12368        for selection in &mut selections {
12369            let rows = selection.spanned_rows(true, &display_map);
12370            selection.start = Point::new(rows.start.0, 0);
12371            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12372            selection.reversed = false;
12373        }
12374        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12375            s.select(selections);
12376        });
12377    }
12378
12379    pub fn split_selection_into_lines(
12380        &mut self,
12381        _: &SplitSelectionIntoLines,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        let selections = self
12386            .selections
12387            .all::<Point>(cx)
12388            .into_iter()
12389            .map(|selection| selection.start..selection.end)
12390            .collect::<Vec<_>>();
12391        self.unfold_ranges(&selections, true, true, cx);
12392
12393        let mut new_selection_ranges = Vec::new();
12394        {
12395            let buffer = self.buffer.read(cx).read(cx);
12396            for selection in selections {
12397                for row in selection.start.row..selection.end.row {
12398                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12399                    new_selection_ranges.push(cursor..cursor);
12400                }
12401
12402                let is_multiline_selection = selection.start.row != selection.end.row;
12403                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12404                // so this action feels more ergonomic when paired with other selection operations
12405                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12406                if !should_skip_last {
12407                    new_selection_ranges.push(selection.end..selection.end);
12408                }
12409            }
12410        }
12411        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12412            s.select_ranges(new_selection_ranges);
12413        });
12414    }
12415
12416    pub fn add_selection_above(
12417        &mut self,
12418        _: &AddSelectionAbove,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        self.add_selection(true, window, cx);
12423    }
12424
12425    pub fn add_selection_below(
12426        &mut self,
12427        _: &AddSelectionBelow,
12428        window: &mut Window,
12429        cx: &mut Context<Self>,
12430    ) {
12431        self.add_selection(false, window, cx);
12432    }
12433
12434    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12435        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12436
12437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12438        let mut selections = self.selections.all::<Point>(cx);
12439        let text_layout_details = self.text_layout_details(window);
12440        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12441            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12442            let range = oldest_selection.display_range(&display_map).sorted();
12443
12444            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12445            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12446            let positions = start_x.min(end_x)..start_x.max(end_x);
12447
12448            selections.clear();
12449            let mut stack = Vec::new();
12450            for row in range.start.row().0..=range.end.row().0 {
12451                if let Some(selection) = self.selections.build_columnar_selection(
12452                    &display_map,
12453                    DisplayRow(row),
12454                    &positions,
12455                    oldest_selection.reversed,
12456                    &text_layout_details,
12457                ) {
12458                    stack.push(selection.id);
12459                    selections.push(selection);
12460                }
12461            }
12462
12463            if above {
12464                stack.reverse();
12465            }
12466
12467            AddSelectionsState { above, stack }
12468        });
12469
12470        let last_added_selection = *state.stack.last().unwrap();
12471        let mut new_selections = Vec::new();
12472        if above == state.above {
12473            let end_row = if above {
12474                DisplayRow(0)
12475            } else {
12476                display_map.max_point().row()
12477            };
12478
12479            'outer: for selection in selections {
12480                if selection.id == last_added_selection {
12481                    let range = selection.display_range(&display_map).sorted();
12482                    debug_assert_eq!(range.start.row(), range.end.row());
12483                    let mut row = range.start.row();
12484                    let positions =
12485                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12486                            px(start)..px(end)
12487                        } else {
12488                            let start_x =
12489                                display_map.x_for_display_point(range.start, &text_layout_details);
12490                            let end_x =
12491                                display_map.x_for_display_point(range.end, &text_layout_details);
12492                            start_x.min(end_x)..start_x.max(end_x)
12493                        };
12494
12495                    while row != end_row {
12496                        if above {
12497                            row.0 -= 1;
12498                        } else {
12499                            row.0 += 1;
12500                        }
12501
12502                        if let Some(new_selection) = self.selections.build_columnar_selection(
12503                            &display_map,
12504                            row,
12505                            &positions,
12506                            selection.reversed,
12507                            &text_layout_details,
12508                        ) {
12509                            state.stack.push(new_selection.id);
12510                            if above {
12511                                new_selections.push(new_selection);
12512                                new_selections.push(selection);
12513                            } else {
12514                                new_selections.push(selection);
12515                                new_selections.push(new_selection);
12516                            }
12517
12518                            continue 'outer;
12519                        }
12520                    }
12521                }
12522
12523                new_selections.push(selection);
12524            }
12525        } else {
12526            new_selections = selections;
12527            new_selections.retain(|s| s.id != last_added_selection);
12528            state.stack.pop();
12529        }
12530
12531        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12532            s.select(new_selections);
12533        });
12534        if state.stack.len() > 1 {
12535            self.add_selections_state = Some(state);
12536        }
12537    }
12538
12539    fn select_match_ranges(
12540        &mut self,
12541        range: Range<usize>,
12542        reversed: bool,
12543        replace_newest: bool,
12544        auto_scroll: Option<Autoscroll>,
12545        window: &mut Window,
12546        cx: &mut Context<Editor>,
12547    ) {
12548        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12549        self.change_selections(auto_scroll, window, cx, |s| {
12550            if replace_newest {
12551                s.delete(s.newest_anchor().id);
12552            }
12553            if reversed {
12554                s.insert_range(range.end..range.start);
12555            } else {
12556                s.insert_range(range);
12557            }
12558        });
12559    }
12560
12561    pub fn select_next_match_internal(
12562        &mut self,
12563        display_map: &DisplaySnapshot,
12564        replace_newest: bool,
12565        autoscroll: Option<Autoscroll>,
12566        window: &mut Window,
12567        cx: &mut Context<Self>,
12568    ) -> Result<()> {
12569        let buffer = &display_map.buffer_snapshot;
12570        let mut selections = self.selections.all::<usize>(cx);
12571        if let Some(mut select_next_state) = self.select_next_state.take() {
12572            let query = &select_next_state.query;
12573            if !select_next_state.done {
12574                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12575                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12576                let mut next_selected_range = None;
12577
12578                let bytes_after_last_selection =
12579                    buffer.bytes_in_range(last_selection.end..buffer.len());
12580                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12581                let query_matches = query
12582                    .stream_find_iter(bytes_after_last_selection)
12583                    .map(|result| (last_selection.end, result))
12584                    .chain(
12585                        query
12586                            .stream_find_iter(bytes_before_first_selection)
12587                            .map(|result| (0, result)),
12588                    );
12589
12590                for (start_offset, query_match) in query_matches {
12591                    let query_match = query_match.unwrap(); // can only fail due to I/O
12592                    let offset_range =
12593                        start_offset + query_match.start()..start_offset + query_match.end();
12594                    let display_range = offset_range.start.to_display_point(display_map)
12595                        ..offset_range.end.to_display_point(display_map);
12596
12597                    if !select_next_state.wordwise
12598                        || (!movement::is_inside_word(display_map, display_range.start)
12599                            && !movement::is_inside_word(display_map, display_range.end))
12600                    {
12601                        // TODO: This is n^2, because we might check all the selections
12602                        if !selections
12603                            .iter()
12604                            .any(|selection| selection.range().overlaps(&offset_range))
12605                        {
12606                            next_selected_range = Some(offset_range);
12607                            break;
12608                        }
12609                    }
12610                }
12611
12612                if let Some(next_selected_range) = next_selected_range {
12613                    self.select_match_ranges(
12614                        next_selected_range,
12615                        last_selection.reversed,
12616                        replace_newest,
12617                        autoscroll,
12618                        window,
12619                        cx,
12620                    );
12621                } else {
12622                    select_next_state.done = true;
12623                }
12624            }
12625
12626            self.select_next_state = Some(select_next_state);
12627        } else {
12628            let mut only_carets = true;
12629            let mut same_text_selected = true;
12630            let mut selected_text = None;
12631
12632            let mut selections_iter = selections.iter().peekable();
12633            while let Some(selection) = selections_iter.next() {
12634                if selection.start != selection.end {
12635                    only_carets = false;
12636                }
12637
12638                if same_text_selected {
12639                    if selected_text.is_none() {
12640                        selected_text =
12641                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12642                    }
12643
12644                    if let Some(next_selection) = selections_iter.peek() {
12645                        if next_selection.range().len() == selection.range().len() {
12646                            let next_selected_text = buffer
12647                                .text_for_range(next_selection.range())
12648                                .collect::<String>();
12649                            if Some(next_selected_text) != selected_text {
12650                                same_text_selected = false;
12651                                selected_text = None;
12652                            }
12653                        } else {
12654                            same_text_selected = false;
12655                            selected_text = None;
12656                        }
12657                    }
12658                }
12659            }
12660
12661            if only_carets {
12662                for selection in &mut selections {
12663                    let word_range = movement::surrounding_word(
12664                        display_map,
12665                        selection.start.to_display_point(display_map),
12666                    );
12667                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12668                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12669                    selection.goal = SelectionGoal::None;
12670                    selection.reversed = false;
12671                    self.select_match_ranges(
12672                        selection.start..selection.end,
12673                        selection.reversed,
12674                        replace_newest,
12675                        autoscroll,
12676                        window,
12677                        cx,
12678                    );
12679                }
12680
12681                if selections.len() == 1 {
12682                    let selection = selections
12683                        .last()
12684                        .expect("ensured that there's only one selection");
12685                    let query = buffer
12686                        .text_for_range(selection.start..selection.end)
12687                        .collect::<String>();
12688                    let is_empty = query.is_empty();
12689                    let select_state = SelectNextState {
12690                        query: AhoCorasick::new(&[query])?,
12691                        wordwise: true,
12692                        done: is_empty,
12693                    };
12694                    self.select_next_state = Some(select_state);
12695                } else {
12696                    self.select_next_state = None;
12697                }
12698            } else if let Some(selected_text) = selected_text {
12699                self.select_next_state = Some(SelectNextState {
12700                    query: AhoCorasick::new(&[selected_text])?,
12701                    wordwise: false,
12702                    done: false,
12703                });
12704                self.select_next_match_internal(
12705                    display_map,
12706                    replace_newest,
12707                    autoscroll,
12708                    window,
12709                    cx,
12710                )?;
12711            }
12712        }
12713        Ok(())
12714    }
12715
12716    pub fn select_all_matches(
12717        &mut self,
12718        _action: &SelectAllMatches,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) -> Result<()> {
12722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12723
12724        self.push_to_selection_history();
12725        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12726
12727        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12728        let Some(select_next_state) = self.select_next_state.as_mut() else {
12729            return Ok(());
12730        };
12731        if select_next_state.done {
12732            return Ok(());
12733        }
12734
12735        let mut new_selections = Vec::new();
12736
12737        let reversed = self.selections.oldest::<usize>(cx).reversed;
12738        let buffer = &display_map.buffer_snapshot;
12739        let query_matches = select_next_state
12740            .query
12741            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12742
12743        for query_match in query_matches.into_iter() {
12744            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12745            let offset_range = if reversed {
12746                query_match.end()..query_match.start()
12747            } else {
12748                query_match.start()..query_match.end()
12749            };
12750            let display_range = offset_range.start.to_display_point(&display_map)
12751                ..offset_range.end.to_display_point(&display_map);
12752
12753            if !select_next_state.wordwise
12754                || (!movement::is_inside_word(&display_map, display_range.start)
12755                    && !movement::is_inside_word(&display_map, display_range.end))
12756            {
12757                new_selections.push(offset_range.start..offset_range.end);
12758            }
12759        }
12760
12761        select_next_state.done = true;
12762        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12763        self.change_selections(None, window, cx, |selections| {
12764            selections.select_ranges(new_selections)
12765        });
12766
12767        Ok(())
12768    }
12769
12770    pub fn select_next(
12771        &mut self,
12772        action: &SelectNext,
12773        window: &mut Window,
12774        cx: &mut Context<Self>,
12775    ) -> Result<()> {
12776        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12777        self.push_to_selection_history();
12778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12779        self.select_next_match_internal(
12780            &display_map,
12781            action.replace_newest,
12782            Some(Autoscroll::newest()),
12783            window,
12784            cx,
12785        )?;
12786        Ok(())
12787    }
12788
12789    pub fn select_previous(
12790        &mut self,
12791        action: &SelectPrevious,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) -> Result<()> {
12795        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12796        self.push_to_selection_history();
12797        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12798        let buffer = &display_map.buffer_snapshot;
12799        let mut selections = self.selections.all::<usize>(cx);
12800        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12801            let query = &select_prev_state.query;
12802            if !select_prev_state.done {
12803                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12804                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12805                let mut next_selected_range = None;
12806                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12807                let bytes_before_last_selection =
12808                    buffer.reversed_bytes_in_range(0..last_selection.start);
12809                let bytes_after_first_selection =
12810                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12811                let query_matches = query
12812                    .stream_find_iter(bytes_before_last_selection)
12813                    .map(|result| (last_selection.start, result))
12814                    .chain(
12815                        query
12816                            .stream_find_iter(bytes_after_first_selection)
12817                            .map(|result| (buffer.len(), result)),
12818                    );
12819                for (end_offset, query_match) in query_matches {
12820                    let query_match = query_match.unwrap(); // can only fail due to I/O
12821                    let offset_range =
12822                        end_offset - query_match.end()..end_offset - query_match.start();
12823                    let display_range = offset_range.start.to_display_point(&display_map)
12824                        ..offset_range.end.to_display_point(&display_map);
12825
12826                    if !select_prev_state.wordwise
12827                        || (!movement::is_inside_word(&display_map, display_range.start)
12828                            && !movement::is_inside_word(&display_map, display_range.end))
12829                    {
12830                        next_selected_range = Some(offset_range);
12831                        break;
12832                    }
12833                }
12834
12835                if let Some(next_selected_range) = next_selected_range {
12836                    self.select_match_ranges(
12837                        next_selected_range,
12838                        last_selection.reversed,
12839                        action.replace_newest,
12840                        Some(Autoscroll::newest()),
12841                        window,
12842                        cx,
12843                    );
12844                } else {
12845                    select_prev_state.done = true;
12846                }
12847            }
12848
12849            self.select_prev_state = Some(select_prev_state);
12850        } else {
12851            let mut only_carets = true;
12852            let mut same_text_selected = true;
12853            let mut selected_text = None;
12854
12855            let mut selections_iter = selections.iter().peekable();
12856            while let Some(selection) = selections_iter.next() {
12857                if selection.start != selection.end {
12858                    only_carets = false;
12859                }
12860
12861                if same_text_selected {
12862                    if selected_text.is_none() {
12863                        selected_text =
12864                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12865                    }
12866
12867                    if let Some(next_selection) = selections_iter.peek() {
12868                        if next_selection.range().len() == selection.range().len() {
12869                            let next_selected_text = buffer
12870                                .text_for_range(next_selection.range())
12871                                .collect::<String>();
12872                            if Some(next_selected_text) != selected_text {
12873                                same_text_selected = false;
12874                                selected_text = None;
12875                            }
12876                        } else {
12877                            same_text_selected = false;
12878                            selected_text = None;
12879                        }
12880                    }
12881                }
12882            }
12883
12884            if only_carets {
12885                for selection in &mut selections {
12886                    let word_range = movement::surrounding_word(
12887                        &display_map,
12888                        selection.start.to_display_point(&display_map),
12889                    );
12890                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12891                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12892                    selection.goal = SelectionGoal::None;
12893                    selection.reversed = false;
12894                    self.select_match_ranges(
12895                        selection.start..selection.end,
12896                        selection.reversed,
12897                        action.replace_newest,
12898                        Some(Autoscroll::newest()),
12899                        window,
12900                        cx,
12901                    );
12902                }
12903                if selections.len() == 1 {
12904                    let selection = selections
12905                        .last()
12906                        .expect("ensured that there's only one selection");
12907                    let query = buffer
12908                        .text_for_range(selection.start..selection.end)
12909                        .collect::<String>();
12910                    let is_empty = query.is_empty();
12911                    let select_state = SelectNextState {
12912                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12913                        wordwise: true,
12914                        done: is_empty,
12915                    };
12916                    self.select_prev_state = Some(select_state);
12917                } else {
12918                    self.select_prev_state = None;
12919                }
12920            } else if let Some(selected_text) = selected_text {
12921                self.select_prev_state = Some(SelectNextState {
12922                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12923                    wordwise: false,
12924                    done: false,
12925                });
12926                self.select_previous(action, window, cx)?;
12927            }
12928        }
12929        Ok(())
12930    }
12931
12932    pub fn find_next_match(
12933        &mut self,
12934        _: &FindNextMatch,
12935        window: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) -> Result<()> {
12938        let selections = self.selections.disjoint_anchors();
12939        match selections.first() {
12940            Some(first) if selections.len() >= 2 => {
12941                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12942                    s.select_ranges([first.range()]);
12943                });
12944            }
12945            _ => self.select_next(
12946                &SelectNext {
12947                    replace_newest: true,
12948                },
12949                window,
12950                cx,
12951            )?,
12952        }
12953        Ok(())
12954    }
12955
12956    pub fn find_previous_match(
12957        &mut self,
12958        _: &FindPreviousMatch,
12959        window: &mut Window,
12960        cx: &mut Context<Self>,
12961    ) -> Result<()> {
12962        let selections = self.selections.disjoint_anchors();
12963        match selections.last() {
12964            Some(last) if selections.len() >= 2 => {
12965                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12966                    s.select_ranges([last.range()]);
12967                });
12968            }
12969            _ => self.select_previous(
12970                &SelectPrevious {
12971                    replace_newest: true,
12972                },
12973                window,
12974                cx,
12975            )?,
12976        }
12977        Ok(())
12978    }
12979
12980    pub fn toggle_comments(
12981        &mut self,
12982        action: &ToggleComments,
12983        window: &mut Window,
12984        cx: &mut Context<Self>,
12985    ) {
12986        if self.read_only(cx) {
12987            return;
12988        }
12989        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12990        let text_layout_details = &self.text_layout_details(window);
12991        self.transact(window, cx, |this, window, cx| {
12992            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12993            let mut edits = Vec::new();
12994            let mut selection_edit_ranges = Vec::new();
12995            let mut last_toggled_row = None;
12996            let snapshot = this.buffer.read(cx).read(cx);
12997            let empty_str: Arc<str> = Arc::default();
12998            let mut suffixes_inserted = Vec::new();
12999            let ignore_indent = action.ignore_indent;
13000
13001            fn comment_prefix_range(
13002                snapshot: &MultiBufferSnapshot,
13003                row: MultiBufferRow,
13004                comment_prefix: &str,
13005                comment_prefix_whitespace: &str,
13006                ignore_indent: bool,
13007            ) -> Range<Point> {
13008                let indent_size = if ignore_indent {
13009                    0
13010                } else {
13011                    snapshot.indent_size_for_line(row).len
13012                };
13013
13014                let start = Point::new(row.0, indent_size);
13015
13016                let mut line_bytes = snapshot
13017                    .bytes_in_range(start..snapshot.max_point())
13018                    .flatten()
13019                    .copied();
13020
13021                // If this line currently begins with the line comment prefix, then record
13022                // the range containing the prefix.
13023                if line_bytes
13024                    .by_ref()
13025                    .take(comment_prefix.len())
13026                    .eq(comment_prefix.bytes())
13027                {
13028                    // Include any whitespace that matches the comment prefix.
13029                    let matching_whitespace_len = line_bytes
13030                        .zip(comment_prefix_whitespace.bytes())
13031                        .take_while(|(a, b)| a == b)
13032                        .count() as u32;
13033                    let end = Point::new(
13034                        start.row,
13035                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13036                    );
13037                    start..end
13038                } else {
13039                    start..start
13040                }
13041            }
13042
13043            fn comment_suffix_range(
13044                snapshot: &MultiBufferSnapshot,
13045                row: MultiBufferRow,
13046                comment_suffix: &str,
13047                comment_suffix_has_leading_space: bool,
13048            ) -> Range<Point> {
13049                let end = Point::new(row.0, snapshot.line_len(row));
13050                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13051
13052                let mut line_end_bytes = snapshot
13053                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13054                    .flatten()
13055                    .copied();
13056
13057                let leading_space_len = if suffix_start_column > 0
13058                    && line_end_bytes.next() == Some(b' ')
13059                    && comment_suffix_has_leading_space
13060                {
13061                    1
13062                } else {
13063                    0
13064                };
13065
13066                // If this line currently begins with the line comment prefix, then record
13067                // the range containing the prefix.
13068                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13069                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13070                    start..end
13071                } else {
13072                    end..end
13073                }
13074            }
13075
13076            // TODO: Handle selections that cross excerpts
13077            for selection in &mut selections {
13078                let start_column = snapshot
13079                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13080                    .len;
13081                let language = if let Some(language) =
13082                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13083                {
13084                    language
13085                } else {
13086                    continue;
13087                };
13088
13089                selection_edit_ranges.clear();
13090
13091                // If multiple selections contain a given row, avoid processing that
13092                // row more than once.
13093                let mut start_row = MultiBufferRow(selection.start.row);
13094                if last_toggled_row == Some(start_row) {
13095                    start_row = start_row.next_row();
13096                }
13097                let end_row =
13098                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13099                        MultiBufferRow(selection.end.row - 1)
13100                    } else {
13101                        MultiBufferRow(selection.end.row)
13102                    };
13103                last_toggled_row = Some(end_row);
13104
13105                if start_row > end_row {
13106                    continue;
13107                }
13108
13109                // If the language has line comments, toggle those.
13110                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13111
13112                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13113                if ignore_indent {
13114                    full_comment_prefixes = full_comment_prefixes
13115                        .into_iter()
13116                        .map(|s| Arc::from(s.trim_end()))
13117                        .collect();
13118                }
13119
13120                if !full_comment_prefixes.is_empty() {
13121                    let first_prefix = full_comment_prefixes
13122                        .first()
13123                        .expect("prefixes is non-empty");
13124                    let prefix_trimmed_lengths = full_comment_prefixes
13125                        .iter()
13126                        .map(|p| p.trim_end_matches(' ').len())
13127                        .collect::<SmallVec<[usize; 4]>>();
13128
13129                    let mut all_selection_lines_are_comments = true;
13130
13131                    for row in start_row.0..=end_row.0 {
13132                        let row = MultiBufferRow(row);
13133                        if start_row < end_row && snapshot.is_line_blank(row) {
13134                            continue;
13135                        }
13136
13137                        let prefix_range = full_comment_prefixes
13138                            .iter()
13139                            .zip(prefix_trimmed_lengths.iter().copied())
13140                            .map(|(prefix, trimmed_prefix_len)| {
13141                                comment_prefix_range(
13142                                    snapshot.deref(),
13143                                    row,
13144                                    &prefix[..trimmed_prefix_len],
13145                                    &prefix[trimmed_prefix_len..],
13146                                    ignore_indent,
13147                                )
13148                            })
13149                            .max_by_key(|range| range.end.column - range.start.column)
13150                            .expect("prefixes is non-empty");
13151
13152                        if prefix_range.is_empty() {
13153                            all_selection_lines_are_comments = false;
13154                        }
13155
13156                        selection_edit_ranges.push(prefix_range);
13157                    }
13158
13159                    if all_selection_lines_are_comments {
13160                        edits.extend(
13161                            selection_edit_ranges
13162                                .iter()
13163                                .cloned()
13164                                .map(|range| (range, empty_str.clone())),
13165                        );
13166                    } else {
13167                        let min_column = selection_edit_ranges
13168                            .iter()
13169                            .map(|range| range.start.column)
13170                            .min()
13171                            .unwrap_or(0);
13172                        edits.extend(selection_edit_ranges.iter().map(|range| {
13173                            let position = Point::new(range.start.row, min_column);
13174                            (position..position, first_prefix.clone())
13175                        }));
13176                    }
13177                } else if let Some((full_comment_prefix, comment_suffix)) =
13178                    language.block_comment_delimiters()
13179                {
13180                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13181                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13182                    let prefix_range = comment_prefix_range(
13183                        snapshot.deref(),
13184                        start_row,
13185                        comment_prefix,
13186                        comment_prefix_whitespace,
13187                        ignore_indent,
13188                    );
13189                    let suffix_range = comment_suffix_range(
13190                        snapshot.deref(),
13191                        end_row,
13192                        comment_suffix.trim_start_matches(' '),
13193                        comment_suffix.starts_with(' '),
13194                    );
13195
13196                    if prefix_range.is_empty() || suffix_range.is_empty() {
13197                        edits.push((
13198                            prefix_range.start..prefix_range.start,
13199                            full_comment_prefix.clone(),
13200                        ));
13201                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13202                        suffixes_inserted.push((end_row, comment_suffix.len()));
13203                    } else {
13204                        edits.push((prefix_range, empty_str.clone()));
13205                        edits.push((suffix_range, empty_str.clone()));
13206                    }
13207                } else {
13208                    continue;
13209                }
13210            }
13211
13212            drop(snapshot);
13213            this.buffer.update(cx, |buffer, cx| {
13214                buffer.edit(edits, None, cx);
13215            });
13216
13217            // Adjust selections so that they end before any comment suffixes that
13218            // were inserted.
13219            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13220            let mut selections = this.selections.all::<Point>(cx);
13221            let snapshot = this.buffer.read(cx).read(cx);
13222            for selection in &mut selections {
13223                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13224                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13225                        Ordering::Less => {
13226                            suffixes_inserted.next();
13227                            continue;
13228                        }
13229                        Ordering::Greater => break,
13230                        Ordering::Equal => {
13231                            if selection.end.column == snapshot.line_len(row) {
13232                                if selection.is_empty() {
13233                                    selection.start.column -= suffix_len as u32;
13234                                }
13235                                selection.end.column -= suffix_len as u32;
13236                            }
13237                            break;
13238                        }
13239                    }
13240                }
13241            }
13242
13243            drop(snapshot);
13244            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13245                s.select(selections)
13246            });
13247
13248            let selections = this.selections.all::<Point>(cx);
13249            let selections_on_single_row = selections.windows(2).all(|selections| {
13250                selections[0].start.row == selections[1].start.row
13251                    && selections[0].end.row == selections[1].end.row
13252                    && selections[0].start.row == selections[0].end.row
13253            });
13254            let selections_selecting = selections
13255                .iter()
13256                .any(|selection| selection.start != selection.end);
13257            let advance_downwards = action.advance_downwards
13258                && selections_on_single_row
13259                && !selections_selecting
13260                && !matches!(this.mode, EditorMode::SingleLine { .. });
13261
13262            if advance_downwards {
13263                let snapshot = this.buffer.read(cx).snapshot(cx);
13264
13265                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13266                    s.move_cursors_with(|display_snapshot, display_point, _| {
13267                        let mut point = display_point.to_point(display_snapshot);
13268                        point.row += 1;
13269                        point = snapshot.clip_point(point, Bias::Left);
13270                        let display_point = point.to_display_point(display_snapshot);
13271                        let goal = SelectionGoal::HorizontalPosition(
13272                            display_snapshot
13273                                .x_for_display_point(display_point, text_layout_details)
13274                                .into(),
13275                        );
13276                        (display_point, goal)
13277                    })
13278                });
13279            }
13280        });
13281    }
13282
13283    pub fn select_enclosing_symbol(
13284        &mut self,
13285        _: &SelectEnclosingSymbol,
13286        window: &mut Window,
13287        cx: &mut Context<Self>,
13288    ) {
13289        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13290
13291        let buffer = self.buffer.read(cx).snapshot(cx);
13292        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13293
13294        fn update_selection(
13295            selection: &Selection<usize>,
13296            buffer_snap: &MultiBufferSnapshot,
13297        ) -> Option<Selection<usize>> {
13298            let cursor = selection.head();
13299            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13300            for symbol in symbols.iter().rev() {
13301                let start = symbol.range.start.to_offset(buffer_snap);
13302                let end = symbol.range.end.to_offset(buffer_snap);
13303                let new_range = start..end;
13304                if start < selection.start || end > selection.end {
13305                    return Some(Selection {
13306                        id: selection.id,
13307                        start: new_range.start,
13308                        end: new_range.end,
13309                        goal: SelectionGoal::None,
13310                        reversed: selection.reversed,
13311                    });
13312                }
13313            }
13314            None
13315        }
13316
13317        let mut selected_larger_symbol = false;
13318        let new_selections = old_selections
13319            .iter()
13320            .map(|selection| match update_selection(selection, &buffer) {
13321                Some(new_selection) => {
13322                    if new_selection.range() != selection.range() {
13323                        selected_larger_symbol = true;
13324                    }
13325                    new_selection
13326                }
13327                None => selection.clone(),
13328            })
13329            .collect::<Vec<_>>();
13330
13331        if selected_larger_symbol {
13332            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13333                s.select(new_selections);
13334            });
13335        }
13336    }
13337
13338    pub fn select_larger_syntax_node(
13339        &mut self,
13340        _: &SelectLargerSyntaxNode,
13341        window: &mut Window,
13342        cx: &mut Context<Self>,
13343    ) {
13344        let Some(visible_row_count) = self.visible_row_count() else {
13345            return;
13346        };
13347        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13348        if old_selections.is_empty() {
13349            return;
13350        }
13351
13352        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13353
13354        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13355        let buffer = self.buffer.read(cx).snapshot(cx);
13356
13357        let mut selected_larger_node = false;
13358        let mut new_selections = old_selections
13359            .iter()
13360            .map(|selection| {
13361                let old_range = selection.start..selection.end;
13362
13363                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13364                    // manually select word at selection
13365                    if ["string_content", "inline"].contains(&node.kind()) {
13366                        let word_range = {
13367                            let display_point = buffer
13368                                .offset_to_point(old_range.start)
13369                                .to_display_point(&display_map);
13370                            let Range { start, end } =
13371                                movement::surrounding_word(&display_map, display_point);
13372                            start.to_point(&display_map).to_offset(&buffer)
13373                                ..end.to_point(&display_map).to_offset(&buffer)
13374                        };
13375                        // ignore if word is already selected
13376                        if !word_range.is_empty() && old_range != word_range {
13377                            let last_word_range = {
13378                                let display_point = buffer
13379                                    .offset_to_point(old_range.end)
13380                                    .to_display_point(&display_map);
13381                                let Range { start, end } =
13382                                    movement::surrounding_word(&display_map, display_point);
13383                                start.to_point(&display_map).to_offset(&buffer)
13384                                    ..end.to_point(&display_map).to_offset(&buffer)
13385                            };
13386                            // only select word if start and end point belongs to same word
13387                            if word_range == last_word_range {
13388                                selected_larger_node = true;
13389                                return Selection {
13390                                    id: selection.id,
13391                                    start: word_range.start,
13392                                    end: word_range.end,
13393                                    goal: SelectionGoal::None,
13394                                    reversed: selection.reversed,
13395                                };
13396                            }
13397                        }
13398                    }
13399                }
13400
13401                let mut new_range = old_range.clone();
13402                while let Some((_node, containing_range)) =
13403                    buffer.syntax_ancestor(new_range.clone())
13404                {
13405                    new_range = match containing_range {
13406                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13407                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13408                    };
13409                    if !display_map.intersects_fold(new_range.start)
13410                        && !display_map.intersects_fold(new_range.end)
13411                    {
13412                        break;
13413                    }
13414                }
13415
13416                selected_larger_node |= new_range != old_range;
13417                Selection {
13418                    id: selection.id,
13419                    start: new_range.start,
13420                    end: new_range.end,
13421                    goal: SelectionGoal::None,
13422                    reversed: selection.reversed,
13423                }
13424            })
13425            .collect::<Vec<_>>();
13426
13427        if !selected_larger_node {
13428            return; // don't put this call in the history
13429        }
13430
13431        // scroll based on transformation done to the last selection created by the user
13432        let (last_old, last_new) = old_selections
13433            .last()
13434            .zip(new_selections.last().cloned())
13435            .expect("old_selections isn't empty");
13436
13437        // revert selection
13438        let is_selection_reversed = {
13439            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13440            new_selections.last_mut().expect("checked above").reversed =
13441                should_newest_selection_be_reversed;
13442            should_newest_selection_be_reversed
13443        };
13444
13445        if selected_larger_node {
13446            self.select_syntax_node_history.disable_clearing = true;
13447            self.change_selections(None, window, cx, |s| {
13448                s.select(new_selections.clone());
13449            });
13450            self.select_syntax_node_history.disable_clearing = false;
13451        }
13452
13453        let start_row = last_new.start.to_display_point(&display_map).row().0;
13454        let end_row = last_new.end.to_display_point(&display_map).row().0;
13455        let selection_height = end_row - start_row + 1;
13456        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13457
13458        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13459        let scroll_behavior = if fits_on_the_screen {
13460            self.request_autoscroll(Autoscroll::fit(), cx);
13461            SelectSyntaxNodeScrollBehavior::FitSelection
13462        } else if is_selection_reversed {
13463            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13464            SelectSyntaxNodeScrollBehavior::CursorTop
13465        } else {
13466            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13467            SelectSyntaxNodeScrollBehavior::CursorBottom
13468        };
13469
13470        self.select_syntax_node_history.push((
13471            old_selections,
13472            scroll_behavior,
13473            is_selection_reversed,
13474        ));
13475    }
13476
13477    pub fn select_smaller_syntax_node(
13478        &mut self,
13479        _: &SelectSmallerSyntaxNode,
13480        window: &mut Window,
13481        cx: &mut Context<Self>,
13482    ) {
13483        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13484
13485        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13486            self.select_syntax_node_history.pop()
13487        {
13488            if let Some(selection) = selections.last_mut() {
13489                selection.reversed = is_selection_reversed;
13490            }
13491
13492            self.select_syntax_node_history.disable_clearing = true;
13493            self.change_selections(None, window, cx, |s| {
13494                s.select(selections.to_vec());
13495            });
13496            self.select_syntax_node_history.disable_clearing = false;
13497
13498            match scroll_behavior {
13499                SelectSyntaxNodeScrollBehavior::CursorTop => {
13500                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13501                }
13502                SelectSyntaxNodeScrollBehavior::FitSelection => {
13503                    self.request_autoscroll(Autoscroll::fit(), cx);
13504                }
13505                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13506                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13507                }
13508            }
13509        }
13510    }
13511
13512    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13513        if !EditorSettings::get_global(cx).gutter.runnables {
13514            self.clear_tasks();
13515            return Task::ready(());
13516        }
13517        let project = self.project.as_ref().map(Entity::downgrade);
13518        let task_sources = self.lsp_task_sources(cx);
13519        cx.spawn_in(window, async move |editor, cx| {
13520            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13521            let Some(project) = project.and_then(|p| p.upgrade()) else {
13522                return;
13523            };
13524            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13525                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13526            }) else {
13527                return;
13528            };
13529
13530            let hide_runnables = project
13531                .update(cx, |project, cx| {
13532                    // Do not display any test indicators in non-dev server remote projects.
13533                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13534                })
13535                .unwrap_or(true);
13536            if hide_runnables {
13537                return;
13538            }
13539            let new_rows =
13540                cx.background_spawn({
13541                    let snapshot = display_snapshot.clone();
13542                    async move {
13543                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13544                    }
13545                })
13546                    .await;
13547            let Ok(lsp_tasks) =
13548                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13549            else {
13550                return;
13551            };
13552            let lsp_tasks = lsp_tasks.await;
13553
13554            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13555                lsp_tasks
13556                    .into_iter()
13557                    .flat_map(|(kind, tasks)| {
13558                        tasks.into_iter().filter_map(move |(location, task)| {
13559                            Some((kind.clone(), location?, task))
13560                        })
13561                    })
13562                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13563                        let buffer = location.target.buffer;
13564                        let buffer_snapshot = buffer.read(cx).snapshot();
13565                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13566                            |(excerpt_id, snapshot, _)| {
13567                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13568                                    display_snapshot
13569                                        .buffer_snapshot
13570                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13571                                } else {
13572                                    None
13573                                }
13574                            },
13575                        );
13576                        if let Some(offset) = offset {
13577                            let task_buffer_range =
13578                                location.target.range.to_point(&buffer_snapshot);
13579                            let context_buffer_range =
13580                                task_buffer_range.to_offset(&buffer_snapshot);
13581                            let context_range = BufferOffset(context_buffer_range.start)
13582                                ..BufferOffset(context_buffer_range.end);
13583
13584                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13585                                .or_insert_with(|| RunnableTasks {
13586                                    templates: Vec::new(),
13587                                    offset,
13588                                    column: task_buffer_range.start.column,
13589                                    extra_variables: HashMap::default(),
13590                                    context_range,
13591                                })
13592                                .templates
13593                                .push((kind, task.original_task().clone()));
13594                        }
13595
13596                        acc
13597                    })
13598            }) else {
13599                return;
13600            };
13601
13602            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13603            editor
13604                .update(cx, |editor, _| {
13605                    editor.clear_tasks();
13606                    for (key, mut value) in rows {
13607                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13608                            value.templates.extend(lsp_tasks.templates);
13609                        }
13610
13611                        editor.insert_tasks(key, value);
13612                    }
13613                    for (key, value) in lsp_tasks_by_rows {
13614                        editor.insert_tasks(key, value);
13615                    }
13616                })
13617                .ok();
13618        })
13619    }
13620    fn fetch_runnable_ranges(
13621        snapshot: &DisplaySnapshot,
13622        range: Range<Anchor>,
13623    ) -> Vec<language::RunnableRange> {
13624        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13625    }
13626
13627    fn runnable_rows(
13628        project: Entity<Project>,
13629        snapshot: DisplaySnapshot,
13630        runnable_ranges: Vec<RunnableRange>,
13631        mut cx: AsyncWindowContext,
13632    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13633        runnable_ranges
13634            .into_iter()
13635            .filter_map(|mut runnable| {
13636                let tasks = cx
13637                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13638                    .ok()?;
13639                if tasks.is_empty() {
13640                    return None;
13641                }
13642
13643                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13644
13645                let row = snapshot
13646                    .buffer_snapshot
13647                    .buffer_line_for_row(MultiBufferRow(point.row))?
13648                    .1
13649                    .start
13650                    .row;
13651
13652                let context_range =
13653                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13654                Some((
13655                    (runnable.buffer_id, row),
13656                    RunnableTasks {
13657                        templates: tasks,
13658                        offset: snapshot
13659                            .buffer_snapshot
13660                            .anchor_before(runnable.run_range.start),
13661                        context_range,
13662                        column: point.column,
13663                        extra_variables: runnable.extra_captures,
13664                    },
13665                ))
13666            })
13667            .collect()
13668    }
13669
13670    fn templates_with_tags(
13671        project: &Entity<Project>,
13672        runnable: &mut Runnable,
13673        cx: &mut App,
13674    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13675        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13676            let (worktree_id, file) = project
13677                .buffer_for_id(runnable.buffer, cx)
13678                .and_then(|buffer| buffer.read(cx).file())
13679                .map(|file| (file.worktree_id(cx), file.clone()))
13680                .unzip();
13681
13682            (
13683                project.task_store().read(cx).task_inventory().cloned(),
13684                worktree_id,
13685                file,
13686            )
13687        });
13688
13689        let mut templates_with_tags = mem::take(&mut runnable.tags)
13690            .into_iter()
13691            .flat_map(|RunnableTag(tag)| {
13692                inventory
13693                    .as_ref()
13694                    .into_iter()
13695                    .flat_map(|inventory| {
13696                        inventory.read(cx).list_tasks(
13697                            file.clone(),
13698                            Some(runnable.language.clone()),
13699                            worktree_id,
13700                            cx,
13701                        )
13702                    })
13703                    .filter(move |(_, template)| {
13704                        template.tags.iter().any(|source_tag| source_tag == &tag)
13705                    })
13706            })
13707            .sorted_by_key(|(kind, _)| kind.to_owned())
13708            .collect::<Vec<_>>();
13709        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13710            // Strongest source wins; if we have worktree tag binding, prefer that to
13711            // global and language bindings;
13712            // if we have a global binding, prefer that to language binding.
13713            let first_mismatch = templates_with_tags
13714                .iter()
13715                .position(|(tag_source, _)| tag_source != leading_tag_source);
13716            if let Some(index) = first_mismatch {
13717                templates_with_tags.truncate(index);
13718            }
13719        }
13720
13721        templates_with_tags
13722    }
13723
13724    pub fn move_to_enclosing_bracket(
13725        &mut self,
13726        _: &MoveToEnclosingBracket,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13731        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13732            s.move_offsets_with(|snapshot, selection| {
13733                let Some(enclosing_bracket_ranges) =
13734                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13735                else {
13736                    return;
13737                };
13738
13739                let mut best_length = usize::MAX;
13740                let mut best_inside = false;
13741                let mut best_in_bracket_range = false;
13742                let mut best_destination = None;
13743                for (open, close) in enclosing_bracket_ranges {
13744                    let close = close.to_inclusive();
13745                    let length = close.end() - open.start;
13746                    let inside = selection.start >= open.end && selection.end <= *close.start();
13747                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13748                        || close.contains(&selection.head());
13749
13750                    // If best is next to a bracket and current isn't, skip
13751                    if !in_bracket_range && best_in_bracket_range {
13752                        continue;
13753                    }
13754
13755                    // Prefer smaller lengths unless best is inside and current isn't
13756                    if length > best_length && (best_inside || !inside) {
13757                        continue;
13758                    }
13759
13760                    best_length = length;
13761                    best_inside = inside;
13762                    best_in_bracket_range = in_bracket_range;
13763                    best_destination = Some(
13764                        if close.contains(&selection.start) && close.contains(&selection.end) {
13765                            if inside { open.end } else { open.start }
13766                        } else if inside {
13767                            *close.start()
13768                        } else {
13769                            *close.end()
13770                        },
13771                    );
13772                }
13773
13774                if let Some(destination) = best_destination {
13775                    selection.collapse_to(destination, SelectionGoal::None);
13776                }
13777            })
13778        });
13779    }
13780
13781    pub fn undo_selection(
13782        &mut self,
13783        _: &UndoSelection,
13784        window: &mut Window,
13785        cx: &mut Context<Self>,
13786    ) {
13787        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13788        self.end_selection(window, cx);
13789        self.selection_history.mode = SelectionHistoryMode::Undoing;
13790        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13791            self.change_selections(None, window, cx, |s| {
13792                s.select_anchors(entry.selections.to_vec())
13793            });
13794            self.select_next_state = entry.select_next_state;
13795            self.select_prev_state = entry.select_prev_state;
13796            self.add_selections_state = entry.add_selections_state;
13797            self.request_autoscroll(Autoscroll::newest(), cx);
13798        }
13799        self.selection_history.mode = SelectionHistoryMode::Normal;
13800    }
13801
13802    pub fn redo_selection(
13803        &mut self,
13804        _: &RedoSelection,
13805        window: &mut Window,
13806        cx: &mut Context<Self>,
13807    ) {
13808        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13809        self.end_selection(window, cx);
13810        self.selection_history.mode = SelectionHistoryMode::Redoing;
13811        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13812            self.change_selections(None, window, cx, |s| {
13813                s.select_anchors(entry.selections.to_vec())
13814            });
13815            self.select_next_state = entry.select_next_state;
13816            self.select_prev_state = entry.select_prev_state;
13817            self.add_selections_state = entry.add_selections_state;
13818            self.request_autoscroll(Autoscroll::newest(), cx);
13819        }
13820        self.selection_history.mode = SelectionHistoryMode::Normal;
13821    }
13822
13823    pub fn expand_excerpts(
13824        &mut self,
13825        action: &ExpandExcerpts,
13826        _: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) {
13829        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13830    }
13831
13832    pub fn expand_excerpts_down(
13833        &mut self,
13834        action: &ExpandExcerptsDown,
13835        _: &mut Window,
13836        cx: &mut Context<Self>,
13837    ) {
13838        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13839    }
13840
13841    pub fn expand_excerpts_up(
13842        &mut self,
13843        action: &ExpandExcerptsUp,
13844        _: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13848    }
13849
13850    pub fn expand_excerpts_for_direction(
13851        &mut self,
13852        lines: u32,
13853        direction: ExpandExcerptDirection,
13854
13855        cx: &mut Context<Self>,
13856    ) {
13857        let selections = self.selections.disjoint_anchors();
13858
13859        let lines = if lines == 0 {
13860            EditorSettings::get_global(cx).expand_excerpt_lines
13861        } else {
13862            lines
13863        };
13864
13865        self.buffer.update(cx, |buffer, cx| {
13866            let snapshot = buffer.snapshot(cx);
13867            let mut excerpt_ids = selections
13868                .iter()
13869                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13870                .collect::<Vec<_>>();
13871            excerpt_ids.sort();
13872            excerpt_ids.dedup();
13873            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13874        })
13875    }
13876
13877    pub fn expand_excerpt(
13878        &mut self,
13879        excerpt: ExcerptId,
13880        direction: ExpandExcerptDirection,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        let current_scroll_position = self.scroll_position(cx);
13885        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13886        let mut should_scroll_up = false;
13887
13888        if direction == ExpandExcerptDirection::Down {
13889            let multi_buffer = self.buffer.read(cx);
13890            let snapshot = multi_buffer.snapshot(cx);
13891            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13892                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13893                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13894                        let buffer_snapshot = buffer.read(cx).snapshot();
13895                        let excerpt_end_row =
13896                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13897                        let last_row = buffer_snapshot.max_point().row;
13898                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13899                        should_scroll_up = lines_below >= lines_to_expand;
13900                    }
13901                }
13902            }
13903        }
13904
13905        self.buffer.update(cx, |buffer, cx| {
13906            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13907        });
13908
13909        if should_scroll_up {
13910            let new_scroll_position =
13911                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13912            self.set_scroll_position(new_scroll_position, window, cx);
13913        }
13914    }
13915
13916    pub fn go_to_singleton_buffer_point(
13917        &mut self,
13918        point: Point,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        self.go_to_singleton_buffer_range(point..point, window, cx);
13923    }
13924
13925    pub fn go_to_singleton_buffer_range(
13926        &mut self,
13927        range: Range<Point>,
13928        window: &mut Window,
13929        cx: &mut Context<Self>,
13930    ) {
13931        let multibuffer = self.buffer().read(cx);
13932        let Some(buffer) = multibuffer.as_singleton() else {
13933            return;
13934        };
13935        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13936            return;
13937        };
13938        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13939            return;
13940        };
13941        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13942            s.select_anchor_ranges([start..end])
13943        });
13944    }
13945
13946    pub fn go_to_diagnostic(
13947        &mut self,
13948        _: &GoToDiagnostic,
13949        window: &mut Window,
13950        cx: &mut Context<Self>,
13951    ) {
13952        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13953        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13954    }
13955
13956    pub fn go_to_prev_diagnostic(
13957        &mut self,
13958        _: &GoToPreviousDiagnostic,
13959        window: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) {
13962        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13963        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13964    }
13965
13966    pub fn go_to_diagnostic_impl(
13967        &mut self,
13968        direction: Direction,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        let buffer = self.buffer.read(cx).snapshot(cx);
13973        let selection = self.selections.newest::<usize>(cx);
13974
13975        let mut active_group_id = None;
13976        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13977            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13978                active_group_id = Some(active_group.group_id);
13979            }
13980        }
13981
13982        fn filtered(
13983            snapshot: EditorSnapshot,
13984            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13985        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13986            diagnostics
13987                .filter(|entry| entry.range.start != entry.range.end)
13988                .filter(|entry| !entry.diagnostic.is_unnecessary)
13989                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13990        }
13991
13992        let snapshot = self.snapshot(window, cx);
13993        let before = filtered(
13994            snapshot.clone(),
13995            buffer
13996                .diagnostics_in_range(0..selection.start)
13997                .filter(|entry| entry.range.start <= selection.start),
13998        );
13999        let after = filtered(
14000            snapshot,
14001            buffer
14002                .diagnostics_in_range(selection.start..buffer.len())
14003                .filter(|entry| entry.range.start >= selection.start),
14004        );
14005
14006        let mut found: Option<DiagnosticEntry<usize>> = None;
14007        if direction == Direction::Prev {
14008            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14009            {
14010                for diagnostic in prev_diagnostics.into_iter().rev() {
14011                    if diagnostic.range.start != selection.start
14012                        || active_group_id
14013                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14014                    {
14015                        found = Some(diagnostic);
14016                        break 'outer;
14017                    }
14018                }
14019            }
14020        } else {
14021            for diagnostic in after.chain(before) {
14022                if diagnostic.range.start != selection.start
14023                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14024                {
14025                    found = Some(diagnostic);
14026                    break;
14027                }
14028            }
14029        }
14030        let Some(next_diagnostic) = found else {
14031            return;
14032        };
14033
14034        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14035            return;
14036        };
14037        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14038            s.select_ranges(vec![
14039                next_diagnostic.range.start..next_diagnostic.range.start,
14040            ])
14041        });
14042        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14043        self.refresh_inline_completion(false, true, window, cx);
14044    }
14045
14046    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14047        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14048        let snapshot = self.snapshot(window, cx);
14049        let selection = self.selections.newest::<Point>(cx);
14050        self.go_to_hunk_before_or_after_position(
14051            &snapshot,
14052            selection.head(),
14053            Direction::Next,
14054            window,
14055            cx,
14056        );
14057    }
14058
14059    pub fn go_to_hunk_before_or_after_position(
14060        &mut self,
14061        snapshot: &EditorSnapshot,
14062        position: Point,
14063        direction: Direction,
14064        window: &mut Window,
14065        cx: &mut Context<Editor>,
14066    ) {
14067        let row = if direction == Direction::Next {
14068            self.hunk_after_position(snapshot, position)
14069                .map(|hunk| hunk.row_range.start)
14070        } else {
14071            self.hunk_before_position(snapshot, position)
14072        };
14073
14074        if let Some(row) = row {
14075            let destination = Point::new(row.0, 0);
14076            let autoscroll = Autoscroll::center();
14077
14078            self.unfold_ranges(&[destination..destination], false, false, cx);
14079            self.change_selections(Some(autoscroll), window, cx, |s| {
14080                s.select_ranges([destination..destination]);
14081            });
14082        }
14083    }
14084
14085    fn hunk_after_position(
14086        &mut self,
14087        snapshot: &EditorSnapshot,
14088        position: Point,
14089    ) -> Option<MultiBufferDiffHunk> {
14090        snapshot
14091            .buffer_snapshot
14092            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14093            .find(|hunk| hunk.row_range.start.0 > position.row)
14094            .or_else(|| {
14095                snapshot
14096                    .buffer_snapshot
14097                    .diff_hunks_in_range(Point::zero()..position)
14098                    .find(|hunk| hunk.row_range.end.0 < position.row)
14099            })
14100    }
14101
14102    fn go_to_prev_hunk(
14103        &mut self,
14104        _: &GoToPreviousHunk,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) {
14108        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14109        let snapshot = self.snapshot(window, cx);
14110        let selection = self.selections.newest::<Point>(cx);
14111        self.go_to_hunk_before_or_after_position(
14112            &snapshot,
14113            selection.head(),
14114            Direction::Prev,
14115            window,
14116            cx,
14117        );
14118    }
14119
14120    fn hunk_before_position(
14121        &mut self,
14122        snapshot: &EditorSnapshot,
14123        position: Point,
14124    ) -> Option<MultiBufferRow> {
14125        snapshot
14126            .buffer_snapshot
14127            .diff_hunk_before(position)
14128            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14129    }
14130
14131    fn go_to_next_change(
14132        &mut self,
14133        _: &GoToNextChange,
14134        window: &mut Window,
14135        cx: &mut Context<Self>,
14136    ) {
14137        if let Some(selections) = self
14138            .change_list
14139            .next_change(1, Direction::Next)
14140            .map(|s| s.to_vec())
14141        {
14142            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14143                let map = s.display_map();
14144                s.select_display_ranges(selections.iter().map(|a| {
14145                    let point = a.to_display_point(&map);
14146                    point..point
14147                }))
14148            })
14149        }
14150    }
14151
14152    fn go_to_previous_change(
14153        &mut self,
14154        _: &GoToPreviousChange,
14155        window: &mut Window,
14156        cx: &mut Context<Self>,
14157    ) {
14158        if let Some(selections) = self
14159            .change_list
14160            .next_change(1, Direction::Prev)
14161            .map(|s| s.to_vec())
14162        {
14163            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14164                let map = s.display_map();
14165                s.select_display_ranges(selections.iter().map(|a| {
14166                    let point = a.to_display_point(&map);
14167                    point..point
14168                }))
14169            })
14170        }
14171    }
14172
14173    fn go_to_line<T: 'static>(
14174        &mut self,
14175        position: Anchor,
14176        highlight_color: Option<Hsla>,
14177        window: &mut Window,
14178        cx: &mut Context<Self>,
14179    ) {
14180        let snapshot = self.snapshot(window, cx).display_snapshot;
14181        let position = position.to_point(&snapshot.buffer_snapshot);
14182        let start = snapshot
14183            .buffer_snapshot
14184            .clip_point(Point::new(position.row, 0), Bias::Left);
14185        let end = start + Point::new(1, 0);
14186        let start = snapshot.buffer_snapshot.anchor_before(start);
14187        let end = snapshot.buffer_snapshot.anchor_before(end);
14188
14189        self.highlight_rows::<T>(
14190            start..end,
14191            highlight_color
14192                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14193            Default::default(),
14194            cx,
14195        );
14196
14197        if self.buffer.read(cx).is_singleton() {
14198            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14199        }
14200    }
14201
14202    pub fn go_to_definition(
14203        &mut self,
14204        _: &GoToDefinition,
14205        window: &mut Window,
14206        cx: &mut Context<Self>,
14207    ) -> Task<Result<Navigated>> {
14208        let definition =
14209            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14210        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14211        cx.spawn_in(window, async move |editor, cx| {
14212            if definition.await? == Navigated::Yes {
14213                return Ok(Navigated::Yes);
14214            }
14215            match fallback_strategy {
14216                GoToDefinitionFallback::None => Ok(Navigated::No),
14217                GoToDefinitionFallback::FindAllReferences => {
14218                    match editor.update_in(cx, |editor, window, cx| {
14219                        editor.find_all_references(&FindAllReferences, window, cx)
14220                    })? {
14221                        Some(references) => references.await,
14222                        None => Ok(Navigated::No),
14223                    }
14224                }
14225            }
14226        })
14227    }
14228
14229    pub fn go_to_declaration(
14230        &mut self,
14231        _: &GoToDeclaration,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) -> Task<Result<Navigated>> {
14235        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14236    }
14237
14238    pub fn go_to_declaration_split(
14239        &mut self,
14240        _: &GoToDeclaration,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Task<Result<Navigated>> {
14244        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14245    }
14246
14247    pub fn go_to_implementation(
14248        &mut self,
14249        _: &GoToImplementation,
14250        window: &mut Window,
14251        cx: &mut Context<Self>,
14252    ) -> Task<Result<Navigated>> {
14253        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14254    }
14255
14256    pub fn go_to_implementation_split(
14257        &mut self,
14258        _: &GoToImplementationSplit,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) -> Task<Result<Navigated>> {
14262        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14263    }
14264
14265    pub fn go_to_type_definition(
14266        &mut self,
14267        _: &GoToTypeDefinition,
14268        window: &mut Window,
14269        cx: &mut Context<Self>,
14270    ) -> Task<Result<Navigated>> {
14271        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14272    }
14273
14274    pub fn go_to_definition_split(
14275        &mut self,
14276        _: &GoToDefinitionSplit,
14277        window: &mut Window,
14278        cx: &mut Context<Self>,
14279    ) -> Task<Result<Navigated>> {
14280        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14281    }
14282
14283    pub fn go_to_type_definition_split(
14284        &mut self,
14285        _: &GoToTypeDefinitionSplit,
14286        window: &mut Window,
14287        cx: &mut Context<Self>,
14288    ) -> Task<Result<Navigated>> {
14289        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14290    }
14291
14292    fn go_to_definition_of_kind(
14293        &mut self,
14294        kind: GotoDefinitionKind,
14295        split: bool,
14296        window: &mut Window,
14297        cx: &mut Context<Self>,
14298    ) -> Task<Result<Navigated>> {
14299        let Some(provider) = self.semantics_provider.clone() else {
14300            return Task::ready(Ok(Navigated::No));
14301        };
14302        let head = self.selections.newest::<usize>(cx).head();
14303        let buffer = self.buffer.read(cx);
14304        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14305            text_anchor
14306        } else {
14307            return Task::ready(Ok(Navigated::No));
14308        };
14309
14310        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14311            return Task::ready(Ok(Navigated::No));
14312        };
14313
14314        cx.spawn_in(window, async move |editor, cx| {
14315            let definitions = definitions.await?;
14316            let navigated = editor
14317                .update_in(cx, |editor, window, cx| {
14318                    editor.navigate_to_hover_links(
14319                        Some(kind),
14320                        definitions
14321                            .into_iter()
14322                            .filter(|location| {
14323                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14324                            })
14325                            .map(HoverLink::Text)
14326                            .collect::<Vec<_>>(),
14327                        split,
14328                        window,
14329                        cx,
14330                    )
14331                })?
14332                .await?;
14333            anyhow::Ok(navigated)
14334        })
14335    }
14336
14337    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14338        let selection = self.selections.newest_anchor();
14339        let head = selection.head();
14340        let tail = selection.tail();
14341
14342        let Some((buffer, start_position)) =
14343            self.buffer.read(cx).text_anchor_for_position(head, cx)
14344        else {
14345            return;
14346        };
14347
14348        let end_position = if head != tail {
14349            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14350                return;
14351            };
14352            Some(pos)
14353        } else {
14354            None
14355        };
14356
14357        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14358            let url = if let Some(end_pos) = end_position {
14359                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14360            } else {
14361                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14362            };
14363
14364            if let Some(url) = url {
14365                editor.update(cx, |_, cx| {
14366                    cx.open_url(&url);
14367                })
14368            } else {
14369                Ok(())
14370            }
14371        });
14372
14373        url_finder.detach();
14374    }
14375
14376    pub fn open_selected_filename(
14377        &mut self,
14378        _: &OpenSelectedFilename,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        let Some(workspace) = self.workspace() else {
14383            return;
14384        };
14385
14386        let position = self.selections.newest_anchor().head();
14387
14388        let Some((buffer, buffer_position)) =
14389            self.buffer.read(cx).text_anchor_for_position(position, cx)
14390        else {
14391            return;
14392        };
14393
14394        let project = self.project.clone();
14395
14396        cx.spawn_in(window, async move |_, cx| {
14397            let result = find_file(&buffer, project, buffer_position, cx).await;
14398
14399            if let Some((_, path)) = result {
14400                workspace
14401                    .update_in(cx, |workspace, window, cx| {
14402                        workspace.open_resolved_path(path, window, cx)
14403                    })?
14404                    .await?;
14405            }
14406            anyhow::Ok(())
14407        })
14408        .detach();
14409    }
14410
14411    pub(crate) fn navigate_to_hover_links(
14412        &mut self,
14413        kind: Option<GotoDefinitionKind>,
14414        mut definitions: Vec<HoverLink>,
14415        split: bool,
14416        window: &mut Window,
14417        cx: &mut Context<Editor>,
14418    ) -> Task<Result<Navigated>> {
14419        // If there is one definition, just open it directly
14420        if definitions.len() == 1 {
14421            let definition = definitions.pop().unwrap();
14422
14423            enum TargetTaskResult {
14424                Location(Option<Location>),
14425                AlreadyNavigated,
14426            }
14427
14428            let target_task = match definition {
14429                HoverLink::Text(link) => {
14430                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14431                }
14432                HoverLink::InlayHint(lsp_location, server_id) => {
14433                    let computation =
14434                        self.compute_target_location(lsp_location, server_id, window, cx);
14435                    cx.background_spawn(async move {
14436                        let location = computation.await?;
14437                        Ok(TargetTaskResult::Location(location))
14438                    })
14439                }
14440                HoverLink::Url(url) => {
14441                    cx.open_url(&url);
14442                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14443                }
14444                HoverLink::File(path) => {
14445                    if let Some(workspace) = self.workspace() {
14446                        cx.spawn_in(window, async move |_, cx| {
14447                            workspace
14448                                .update_in(cx, |workspace, window, cx| {
14449                                    workspace.open_resolved_path(path, window, cx)
14450                                })?
14451                                .await
14452                                .map(|_| TargetTaskResult::AlreadyNavigated)
14453                        })
14454                    } else {
14455                        Task::ready(Ok(TargetTaskResult::Location(None)))
14456                    }
14457                }
14458            };
14459            cx.spawn_in(window, async move |editor, cx| {
14460                let target = match target_task.await.context("target resolution task")? {
14461                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14462                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14463                    TargetTaskResult::Location(Some(target)) => target,
14464                };
14465
14466                editor.update_in(cx, |editor, window, cx| {
14467                    let Some(workspace) = editor.workspace() else {
14468                        return Navigated::No;
14469                    };
14470                    let pane = workspace.read(cx).active_pane().clone();
14471
14472                    let range = target.range.to_point(target.buffer.read(cx));
14473                    let range = editor.range_for_match(&range);
14474                    let range = collapse_multiline_range(range);
14475
14476                    if !split
14477                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14478                    {
14479                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14480                    } else {
14481                        window.defer(cx, move |window, cx| {
14482                            let target_editor: Entity<Self> =
14483                                workspace.update(cx, |workspace, cx| {
14484                                    let pane = if split {
14485                                        workspace.adjacent_pane(window, cx)
14486                                    } else {
14487                                        workspace.active_pane().clone()
14488                                    };
14489
14490                                    workspace.open_project_item(
14491                                        pane,
14492                                        target.buffer.clone(),
14493                                        true,
14494                                        true,
14495                                        window,
14496                                        cx,
14497                                    )
14498                                });
14499                            target_editor.update(cx, |target_editor, cx| {
14500                                // When selecting a definition in a different buffer, disable the nav history
14501                                // to avoid creating a history entry at the previous cursor location.
14502                                pane.update(cx, |pane, _| pane.disable_history());
14503                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14504                                pane.update(cx, |pane, _| pane.enable_history());
14505                            });
14506                        });
14507                    }
14508                    Navigated::Yes
14509                })
14510            })
14511        } else if !definitions.is_empty() {
14512            cx.spawn_in(window, async move |editor, cx| {
14513                let (title, location_tasks, workspace) = editor
14514                    .update_in(cx, |editor, window, cx| {
14515                        let tab_kind = match kind {
14516                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14517                            _ => "Definitions",
14518                        };
14519                        let title = definitions
14520                            .iter()
14521                            .find_map(|definition| match definition {
14522                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14523                                    let buffer = origin.buffer.read(cx);
14524                                    format!(
14525                                        "{} for {}",
14526                                        tab_kind,
14527                                        buffer
14528                                            .text_for_range(origin.range.clone())
14529                                            .collect::<String>()
14530                                    )
14531                                }),
14532                                HoverLink::InlayHint(_, _) => None,
14533                                HoverLink::Url(_) => None,
14534                                HoverLink::File(_) => None,
14535                            })
14536                            .unwrap_or(tab_kind.to_string());
14537                        let location_tasks = definitions
14538                            .into_iter()
14539                            .map(|definition| match definition {
14540                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14541                                HoverLink::InlayHint(lsp_location, server_id) => editor
14542                                    .compute_target_location(lsp_location, server_id, window, cx),
14543                                HoverLink::Url(_) => Task::ready(Ok(None)),
14544                                HoverLink::File(_) => Task::ready(Ok(None)),
14545                            })
14546                            .collect::<Vec<_>>();
14547                        (title, location_tasks, editor.workspace().clone())
14548                    })
14549                    .context("location tasks preparation")?;
14550
14551                let locations = future::join_all(location_tasks)
14552                    .await
14553                    .into_iter()
14554                    .filter_map(|location| location.transpose())
14555                    .collect::<Result<_>>()
14556                    .context("location tasks")?;
14557
14558                let Some(workspace) = workspace else {
14559                    return Ok(Navigated::No);
14560                };
14561                let opened = workspace
14562                    .update_in(cx, |workspace, window, cx| {
14563                        Self::open_locations_in_multibuffer(
14564                            workspace,
14565                            locations,
14566                            title,
14567                            split,
14568                            MultibufferSelectionMode::First,
14569                            window,
14570                            cx,
14571                        )
14572                    })
14573                    .ok();
14574
14575                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14576            })
14577        } else {
14578            Task::ready(Ok(Navigated::No))
14579        }
14580    }
14581
14582    fn compute_target_location(
14583        &self,
14584        lsp_location: lsp::Location,
14585        server_id: LanguageServerId,
14586        window: &mut Window,
14587        cx: &mut Context<Self>,
14588    ) -> Task<anyhow::Result<Option<Location>>> {
14589        let Some(project) = self.project.clone() else {
14590            return Task::ready(Ok(None));
14591        };
14592
14593        cx.spawn_in(window, async move |editor, cx| {
14594            let location_task = editor.update(cx, |_, cx| {
14595                project.update(cx, |project, cx| {
14596                    let language_server_name = project
14597                        .language_server_statuses(cx)
14598                        .find(|(id, _)| server_id == *id)
14599                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14600                    language_server_name.map(|language_server_name| {
14601                        project.open_local_buffer_via_lsp(
14602                            lsp_location.uri.clone(),
14603                            server_id,
14604                            language_server_name,
14605                            cx,
14606                        )
14607                    })
14608                })
14609            })?;
14610            let location = match location_task {
14611                Some(task) => Some({
14612                    let target_buffer_handle = task.await.context("open local buffer")?;
14613                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14614                        let target_start = target_buffer
14615                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14616                        let target_end = target_buffer
14617                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14618                        target_buffer.anchor_after(target_start)
14619                            ..target_buffer.anchor_before(target_end)
14620                    })?;
14621                    Location {
14622                        buffer: target_buffer_handle,
14623                        range,
14624                    }
14625                }),
14626                None => None,
14627            };
14628            Ok(location)
14629        })
14630    }
14631
14632    pub fn find_all_references(
14633        &mut self,
14634        _: &FindAllReferences,
14635        window: &mut Window,
14636        cx: &mut Context<Self>,
14637    ) -> Option<Task<Result<Navigated>>> {
14638        let selection = self.selections.newest::<usize>(cx);
14639        let multi_buffer = self.buffer.read(cx);
14640        let head = selection.head();
14641
14642        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14643        let head_anchor = multi_buffer_snapshot.anchor_at(
14644            head,
14645            if head < selection.tail() {
14646                Bias::Right
14647            } else {
14648                Bias::Left
14649            },
14650        );
14651
14652        match self
14653            .find_all_references_task_sources
14654            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14655        {
14656            Ok(_) => {
14657                log::info!(
14658                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14659                );
14660                return None;
14661            }
14662            Err(i) => {
14663                self.find_all_references_task_sources.insert(i, head_anchor);
14664            }
14665        }
14666
14667        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14668        let workspace = self.workspace()?;
14669        let project = workspace.read(cx).project().clone();
14670        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14671        Some(cx.spawn_in(window, async move |editor, cx| {
14672            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14673                if let Ok(i) = editor
14674                    .find_all_references_task_sources
14675                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14676                {
14677                    editor.find_all_references_task_sources.remove(i);
14678                }
14679            });
14680
14681            let locations = references.await?;
14682            if locations.is_empty() {
14683                return anyhow::Ok(Navigated::No);
14684            }
14685
14686            workspace.update_in(cx, |workspace, window, cx| {
14687                let title = locations
14688                    .first()
14689                    .as_ref()
14690                    .map(|location| {
14691                        let buffer = location.buffer.read(cx);
14692                        format!(
14693                            "References to `{}`",
14694                            buffer
14695                                .text_for_range(location.range.clone())
14696                                .collect::<String>()
14697                        )
14698                    })
14699                    .unwrap();
14700                Self::open_locations_in_multibuffer(
14701                    workspace,
14702                    locations,
14703                    title,
14704                    false,
14705                    MultibufferSelectionMode::First,
14706                    window,
14707                    cx,
14708                );
14709                Navigated::Yes
14710            })
14711        }))
14712    }
14713
14714    /// Opens a multibuffer with the given project locations in it
14715    pub fn open_locations_in_multibuffer(
14716        workspace: &mut Workspace,
14717        mut locations: Vec<Location>,
14718        title: String,
14719        split: bool,
14720        multibuffer_selection_mode: MultibufferSelectionMode,
14721        window: &mut Window,
14722        cx: &mut Context<Workspace>,
14723    ) {
14724        // If there are multiple definitions, open them in a multibuffer
14725        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14726        let mut locations = locations.into_iter().peekable();
14727        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14728        let capability = workspace.project().read(cx).capability();
14729
14730        let excerpt_buffer = cx.new(|cx| {
14731            let mut multibuffer = MultiBuffer::new(capability);
14732            while let Some(location) = locations.next() {
14733                let buffer = location.buffer.read(cx);
14734                let mut ranges_for_buffer = Vec::new();
14735                let range = location.range.to_point(buffer);
14736                ranges_for_buffer.push(range.clone());
14737
14738                while let Some(next_location) = locations.peek() {
14739                    if next_location.buffer == location.buffer {
14740                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14741                        locations.next();
14742                    } else {
14743                        break;
14744                    }
14745                }
14746
14747                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14748                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14749                    PathKey::for_buffer(&location.buffer, cx),
14750                    location.buffer.clone(),
14751                    ranges_for_buffer,
14752                    DEFAULT_MULTIBUFFER_CONTEXT,
14753                    cx,
14754                );
14755                ranges.extend(new_ranges)
14756            }
14757
14758            multibuffer.with_title(title)
14759        });
14760
14761        let editor = cx.new(|cx| {
14762            Editor::for_multibuffer(
14763                excerpt_buffer,
14764                Some(workspace.project().clone()),
14765                window,
14766                cx,
14767            )
14768        });
14769        editor.update(cx, |editor, cx| {
14770            match multibuffer_selection_mode {
14771                MultibufferSelectionMode::First => {
14772                    if let Some(first_range) = ranges.first() {
14773                        editor.change_selections(None, window, cx, |selections| {
14774                            selections.clear_disjoint();
14775                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14776                        });
14777                    }
14778                    editor.highlight_background::<Self>(
14779                        &ranges,
14780                        |theme| theme.editor_highlighted_line_background,
14781                        cx,
14782                    );
14783                }
14784                MultibufferSelectionMode::All => {
14785                    editor.change_selections(None, window, cx, |selections| {
14786                        selections.clear_disjoint();
14787                        selections.select_anchor_ranges(ranges);
14788                    });
14789                }
14790            }
14791            editor.register_buffers_with_language_servers(cx);
14792        });
14793
14794        let item = Box::new(editor);
14795        let item_id = item.item_id();
14796
14797        if split {
14798            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14799        } else {
14800            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14801                let (preview_item_id, preview_item_idx) =
14802                    workspace.active_pane().update(cx, |pane, _| {
14803                        (pane.preview_item_id(), pane.preview_item_idx())
14804                    });
14805
14806                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14807
14808                if let Some(preview_item_id) = preview_item_id {
14809                    workspace.active_pane().update(cx, |pane, cx| {
14810                        pane.remove_item(preview_item_id, false, false, window, cx);
14811                    });
14812                }
14813            } else {
14814                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14815            }
14816        }
14817        workspace.active_pane().update(cx, |pane, cx| {
14818            pane.set_preview_item_id(Some(item_id), cx);
14819        });
14820    }
14821
14822    pub fn rename(
14823        &mut self,
14824        _: &Rename,
14825        window: &mut Window,
14826        cx: &mut Context<Self>,
14827    ) -> Option<Task<Result<()>>> {
14828        use language::ToOffset as _;
14829
14830        let provider = self.semantics_provider.clone()?;
14831        let selection = self.selections.newest_anchor().clone();
14832        let (cursor_buffer, cursor_buffer_position) = self
14833            .buffer
14834            .read(cx)
14835            .text_anchor_for_position(selection.head(), cx)?;
14836        let (tail_buffer, cursor_buffer_position_end) = self
14837            .buffer
14838            .read(cx)
14839            .text_anchor_for_position(selection.tail(), cx)?;
14840        if tail_buffer != cursor_buffer {
14841            return None;
14842        }
14843
14844        let snapshot = cursor_buffer.read(cx).snapshot();
14845        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14846        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14847        let prepare_rename = provider
14848            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14849            .unwrap_or_else(|| Task::ready(Ok(None)));
14850        drop(snapshot);
14851
14852        Some(cx.spawn_in(window, async move |this, cx| {
14853            let rename_range = if let Some(range) = prepare_rename.await? {
14854                Some(range)
14855            } else {
14856                this.update(cx, |this, cx| {
14857                    let buffer = this.buffer.read(cx).snapshot(cx);
14858                    let mut buffer_highlights = this
14859                        .document_highlights_for_position(selection.head(), &buffer)
14860                        .filter(|highlight| {
14861                            highlight.start.excerpt_id == selection.head().excerpt_id
14862                                && highlight.end.excerpt_id == selection.head().excerpt_id
14863                        });
14864                    buffer_highlights
14865                        .next()
14866                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14867                })?
14868            };
14869            if let Some(rename_range) = rename_range {
14870                this.update_in(cx, |this, window, cx| {
14871                    let snapshot = cursor_buffer.read(cx).snapshot();
14872                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14873                    let cursor_offset_in_rename_range =
14874                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14875                    let cursor_offset_in_rename_range_end =
14876                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14877
14878                    this.take_rename(false, window, cx);
14879                    let buffer = this.buffer.read(cx).read(cx);
14880                    let cursor_offset = selection.head().to_offset(&buffer);
14881                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14882                    let rename_end = rename_start + rename_buffer_range.len();
14883                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14884                    let mut old_highlight_id = None;
14885                    let old_name: Arc<str> = buffer
14886                        .chunks(rename_start..rename_end, true)
14887                        .map(|chunk| {
14888                            if old_highlight_id.is_none() {
14889                                old_highlight_id = chunk.syntax_highlight_id;
14890                            }
14891                            chunk.text
14892                        })
14893                        .collect::<String>()
14894                        .into();
14895
14896                    drop(buffer);
14897
14898                    // Position the selection in the rename editor so that it matches the current selection.
14899                    this.show_local_selections = false;
14900                    let rename_editor = cx.new(|cx| {
14901                        let mut editor = Editor::single_line(window, cx);
14902                        editor.buffer.update(cx, |buffer, cx| {
14903                            buffer.edit([(0..0, old_name.clone())], None, cx)
14904                        });
14905                        let rename_selection_range = match cursor_offset_in_rename_range
14906                            .cmp(&cursor_offset_in_rename_range_end)
14907                        {
14908                            Ordering::Equal => {
14909                                editor.select_all(&SelectAll, window, cx);
14910                                return editor;
14911                            }
14912                            Ordering::Less => {
14913                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14914                            }
14915                            Ordering::Greater => {
14916                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14917                            }
14918                        };
14919                        if rename_selection_range.end > old_name.len() {
14920                            editor.select_all(&SelectAll, window, cx);
14921                        } else {
14922                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14923                                s.select_ranges([rename_selection_range]);
14924                            });
14925                        }
14926                        editor
14927                    });
14928                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14929                        if e == &EditorEvent::Focused {
14930                            cx.emit(EditorEvent::FocusedIn)
14931                        }
14932                    })
14933                    .detach();
14934
14935                    let write_highlights =
14936                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14937                    let read_highlights =
14938                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14939                    let ranges = write_highlights
14940                        .iter()
14941                        .flat_map(|(_, ranges)| ranges.iter())
14942                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14943                        .cloned()
14944                        .collect();
14945
14946                    this.highlight_text::<Rename>(
14947                        ranges,
14948                        HighlightStyle {
14949                            fade_out: Some(0.6),
14950                            ..Default::default()
14951                        },
14952                        cx,
14953                    );
14954                    let rename_focus_handle = rename_editor.focus_handle(cx);
14955                    window.focus(&rename_focus_handle);
14956                    let block_id = this.insert_blocks(
14957                        [BlockProperties {
14958                            style: BlockStyle::Flex,
14959                            placement: BlockPlacement::Below(range.start),
14960                            height: Some(1),
14961                            render: Arc::new({
14962                                let rename_editor = rename_editor.clone();
14963                                move |cx: &mut BlockContext| {
14964                                    let mut text_style = cx.editor_style.text.clone();
14965                                    if let Some(highlight_style) = old_highlight_id
14966                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14967                                    {
14968                                        text_style = text_style.highlight(highlight_style);
14969                                    }
14970                                    div()
14971                                        .block_mouse_down()
14972                                        .pl(cx.anchor_x)
14973                                        .child(EditorElement::new(
14974                                            &rename_editor,
14975                                            EditorStyle {
14976                                                background: cx.theme().system().transparent,
14977                                                local_player: cx.editor_style.local_player,
14978                                                text: text_style,
14979                                                scrollbar_width: cx.editor_style.scrollbar_width,
14980                                                syntax: cx.editor_style.syntax.clone(),
14981                                                status: cx.editor_style.status.clone(),
14982                                                inlay_hints_style: HighlightStyle {
14983                                                    font_weight: Some(FontWeight::BOLD),
14984                                                    ..make_inlay_hints_style(cx.app)
14985                                                },
14986                                                inline_completion_styles: make_suggestion_styles(
14987                                                    cx.app,
14988                                                ),
14989                                                ..EditorStyle::default()
14990                                            },
14991                                        ))
14992                                        .into_any_element()
14993                                }
14994                            }),
14995                            priority: 0,
14996                            render_in_minimap: true,
14997                        }],
14998                        Some(Autoscroll::fit()),
14999                        cx,
15000                    )[0];
15001                    this.pending_rename = Some(RenameState {
15002                        range,
15003                        old_name,
15004                        editor: rename_editor,
15005                        block_id,
15006                    });
15007                })?;
15008            }
15009
15010            Ok(())
15011        }))
15012    }
15013
15014    pub fn confirm_rename(
15015        &mut self,
15016        _: &ConfirmRename,
15017        window: &mut Window,
15018        cx: &mut Context<Self>,
15019    ) -> Option<Task<Result<()>>> {
15020        let rename = self.take_rename(false, window, cx)?;
15021        let workspace = self.workspace()?.downgrade();
15022        let (buffer, start) = self
15023            .buffer
15024            .read(cx)
15025            .text_anchor_for_position(rename.range.start, cx)?;
15026        let (end_buffer, _) = self
15027            .buffer
15028            .read(cx)
15029            .text_anchor_for_position(rename.range.end, cx)?;
15030        if buffer != end_buffer {
15031            return None;
15032        }
15033
15034        let old_name = rename.old_name;
15035        let new_name = rename.editor.read(cx).text(cx);
15036
15037        let rename = self.semantics_provider.as_ref()?.perform_rename(
15038            &buffer,
15039            start,
15040            new_name.clone(),
15041            cx,
15042        )?;
15043
15044        Some(cx.spawn_in(window, async move |editor, cx| {
15045            let project_transaction = rename.await?;
15046            Self::open_project_transaction(
15047                &editor,
15048                workspace,
15049                project_transaction,
15050                format!("Rename: {}{}", old_name, new_name),
15051                cx,
15052            )
15053            .await?;
15054
15055            editor.update(cx, |editor, cx| {
15056                editor.refresh_document_highlights(cx);
15057            })?;
15058            Ok(())
15059        }))
15060    }
15061
15062    fn take_rename(
15063        &mut self,
15064        moving_cursor: bool,
15065        window: &mut Window,
15066        cx: &mut Context<Self>,
15067    ) -> Option<RenameState> {
15068        let rename = self.pending_rename.take()?;
15069        if rename.editor.focus_handle(cx).is_focused(window) {
15070            window.focus(&self.focus_handle);
15071        }
15072
15073        self.remove_blocks(
15074            [rename.block_id].into_iter().collect(),
15075            Some(Autoscroll::fit()),
15076            cx,
15077        );
15078        self.clear_highlights::<Rename>(cx);
15079        self.show_local_selections = true;
15080
15081        if moving_cursor {
15082            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15083                editor.selections.newest::<usize>(cx).head()
15084            });
15085
15086            // Update the selection to match the position of the selection inside
15087            // the rename editor.
15088            let snapshot = self.buffer.read(cx).read(cx);
15089            let rename_range = rename.range.to_offset(&snapshot);
15090            let cursor_in_editor = snapshot
15091                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15092                .min(rename_range.end);
15093            drop(snapshot);
15094
15095            self.change_selections(None, window, cx, |s| {
15096                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15097            });
15098        } else {
15099            self.refresh_document_highlights(cx);
15100        }
15101
15102        Some(rename)
15103    }
15104
15105    pub fn pending_rename(&self) -> Option<&RenameState> {
15106        self.pending_rename.as_ref()
15107    }
15108
15109    fn format(
15110        &mut self,
15111        _: &Format,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) -> Option<Task<Result<()>>> {
15115        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15116
15117        let project = match &self.project {
15118            Some(project) => project.clone(),
15119            None => return None,
15120        };
15121
15122        Some(self.perform_format(
15123            project,
15124            FormatTrigger::Manual,
15125            FormatTarget::Buffers,
15126            window,
15127            cx,
15128        ))
15129    }
15130
15131    fn format_selections(
15132        &mut self,
15133        _: &FormatSelections,
15134        window: &mut Window,
15135        cx: &mut Context<Self>,
15136    ) -> Option<Task<Result<()>>> {
15137        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15138
15139        let project = match &self.project {
15140            Some(project) => project.clone(),
15141            None => return None,
15142        };
15143
15144        let ranges = self
15145            .selections
15146            .all_adjusted(cx)
15147            .into_iter()
15148            .map(|selection| selection.range())
15149            .collect_vec();
15150
15151        Some(self.perform_format(
15152            project,
15153            FormatTrigger::Manual,
15154            FormatTarget::Ranges(ranges),
15155            window,
15156            cx,
15157        ))
15158    }
15159
15160    fn perform_format(
15161        &mut self,
15162        project: Entity<Project>,
15163        trigger: FormatTrigger,
15164        target: FormatTarget,
15165        window: &mut Window,
15166        cx: &mut Context<Self>,
15167    ) -> Task<Result<()>> {
15168        let buffer = self.buffer.clone();
15169        let (buffers, target) = match target {
15170            FormatTarget::Buffers => {
15171                let mut buffers = buffer.read(cx).all_buffers();
15172                if trigger == FormatTrigger::Save {
15173                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15174                }
15175                (buffers, LspFormatTarget::Buffers)
15176            }
15177            FormatTarget::Ranges(selection_ranges) => {
15178                let multi_buffer = buffer.read(cx);
15179                let snapshot = multi_buffer.read(cx);
15180                let mut buffers = HashSet::default();
15181                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15182                    BTreeMap::new();
15183                for selection_range in selection_ranges {
15184                    for (buffer, buffer_range, _) in
15185                        snapshot.range_to_buffer_ranges(selection_range)
15186                    {
15187                        let buffer_id = buffer.remote_id();
15188                        let start = buffer.anchor_before(buffer_range.start);
15189                        let end = buffer.anchor_after(buffer_range.end);
15190                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15191                        buffer_id_to_ranges
15192                            .entry(buffer_id)
15193                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15194                            .or_insert_with(|| vec![start..end]);
15195                    }
15196                }
15197                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15198            }
15199        };
15200
15201        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15202        let selections_prev = transaction_id_prev
15203            .and_then(|transaction_id_prev| {
15204                // default to selections as they were after the last edit, if we have them,
15205                // instead of how they are now.
15206                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15207                // will take you back to where you made the last edit, instead of staying where you scrolled
15208                self.selection_history
15209                    .transaction(transaction_id_prev)
15210                    .map(|t| t.0.clone())
15211            })
15212            .unwrap_or_else(|| {
15213                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15214                self.selections.disjoint_anchors()
15215            });
15216
15217        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15218        let format = project.update(cx, |project, cx| {
15219            project.format(buffers, target, true, trigger, cx)
15220        });
15221
15222        cx.spawn_in(window, async move |editor, cx| {
15223            let transaction = futures::select_biased! {
15224                transaction = format.log_err().fuse() => transaction,
15225                () = timeout => {
15226                    log::warn!("timed out waiting for formatting");
15227                    None
15228                }
15229            };
15230
15231            buffer
15232                .update(cx, |buffer, cx| {
15233                    if let Some(transaction) = transaction {
15234                        if !buffer.is_singleton() {
15235                            buffer.push_transaction(&transaction.0, cx);
15236                        }
15237                    }
15238                    cx.notify();
15239                })
15240                .ok();
15241
15242            if let Some(transaction_id_now) =
15243                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15244            {
15245                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15246                if has_new_transaction {
15247                    _ = editor.update(cx, |editor, _| {
15248                        editor
15249                            .selection_history
15250                            .insert_transaction(transaction_id_now, selections_prev);
15251                    });
15252                }
15253            }
15254
15255            Ok(())
15256        })
15257    }
15258
15259    fn organize_imports(
15260        &mut self,
15261        _: &OrganizeImports,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) -> Option<Task<Result<()>>> {
15265        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15266        let project = match &self.project {
15267            Some(project) => project.clone(),
15268            None => return None,
15269        };
15270        Some(self.perform_code_action_kind(
15271            project,
15272            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15273            window,
15274            cx,
15275        ))
15276    }
15277
15278    fn perform_code_action_kind(
15279        &mut self,
15280        project: Entity<Project>,
15281        kind: CodeActionKind,
15282        window: &mut Window,
15283        cx: &mut Context<Self>,
15284    ) -> Task<Result<()>> {
15285        let buffer = self.buffer.clone();
15286        let buffers = buffer.read(cx).all_buffers();
15287        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15288        let apply_action = project.update(cx, |project, cx| {
15289            project.apply_code_action_kind(buffers, kind, true, cx)
15290        });
15291        cx.spawn_in(window, async move |_, cx| {
15292            let transaction = futures::select_biased! {
15293                () = timeout => {
15294                    log::warn!("timed out waiting for executing code action");
15295                    None
15296                }
15297                transaction = apply_action.log_err().fuse() => transaction,
15298            };
15299            buffer
15300                .update(cx, |buffer, cx| {
15301                    // check if we need this
15302                    if let Some(transaction) = transaction {
15303                        if !buffer.is_singleton() {
15304                            buffer.push_transaction(&transaction.0, cx);
15305                        }
15306                    }
15307                    cx.notify();
15308                })
15309                .ok();
15310            Ok(())
15311        })
15312    }
15313
15314    fn restart_language_server(
15315        &mut self,
15316        _: &RestartLanguageServer,
15317        _: &mut Window,
15318        cx: &mut Context<Self>,
15319    ) {
15320        if let Some(project) = self.project.clone() {
15321            self.buffer.update(cx, |multi_buffer, cx| {
15322                project.update(cx, |project, cx| {
15323                    project.restart_language_servers_for_buffers(
15324                        multi_buffer.all_buffers().into_iter().collect(),
15325                        cx,
15326                    );
15327                });
15328            })
15329        }
15330    }
15331
15332    fn stop_language_server(
15333        &mut self,
15334        _: &StopLanguageServer,
15335        _: &mut Window,
15336        cx: &mut Context<Self>,
15337    ) {
15338        if let Some(project) = self.project.clone() {
15339            self.buffer.update(cx, |multi_buffer, cx| {
15340                project.update(cx, |project, cx| {
15341                    project.stop_language_servers_for_buffers(
15342                        multi_buffer.all_buffers().into_iter().collect(),
15343                        cx,
15344                    );
15345                    cx.emit(project::Event::RefreshInlayHints);
15346                });
15347            });
15348        }
15349    }
15350
15351    fn cancel_language_server_work(
15352        workspace: &mut Workspace,
15353        _: &actions::CancelLanguageServerWork,
15354        _: &mut Window,
15355        cx: &mut Context<Workspace>,
15356    ) {
15357        let project = workspace.project();
15358        let buffers = workspace
15359            .active_item(cx)
15360            .and_then(|item| item.act_as::<Editor>(cx))
15361            .map_or(HashSet::default(), |editor| {
15362                editor.read(cx).buffer.read(cx).all_buffers()
15363            });
15364        project.update(cx, |project, cx| {
15365            project.cancel_language_server_work_for_buffers(buffers, cx);
15366        });
15367    }
15368
15369    fn show_character_palette(
15370        &mut self,
15371        _: &ShowCharacterPalette,
15372        window: &mut Window,
15373        _: &mut Context<Self>,
15374    ) {
15375        window.show_character_palette();
15376    }
15377
15378    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15379        if self.mode.is_minimap() {
15380            return;
15381        }
15382
15383        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15384            let buffer = self.buffer.read(cx).snapshot(cx);
15385            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15386            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15387            let is_valid = buffer
15388                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15389                .any(|entry| {
15390                    entry.diagnostic.is_primary
15391                        && !entry.range.is_empty()
15392                        && entry.range.start == primary_range_start
15393                        && entry.diagnostic.message == active_diagnostics.active_message
15394                });
15395
15396            if !is_valid {
15397                self.dismiss_diagnostics(cx);
15398            }
15399        }
15400    }
15401
15402    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15403        match &self.active_diagnostics {
15404            ActiveDiagnostic::Group(group) => Some(group),
15405            _ => None,
15406        }
15407    }
15408
15409    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15410        self.dismiss_diagnostics(cx);
15411        self.active_diagnostics = ActiveDiagnostic::All;
15412    }
15413
15414    fn activate_diagnostics(
15415        &mut self,
15416        buffer_id: BufferId,
15417        diagnostic: DiagnosticEntry<usize>,
15418        window: &mut Window,
15419        cx: &mut Context<Self>,
15420    ) {
15421        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15422            return;
15423        }
15424        self.dismiss_diagnostics(cx);
15425        let snapshot = self.snapshot(window, cx);
15426        let buffer = self.buffer.read(cx).snapshot(cx);
15427        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15428            return;
15429        };
15430
15431        let diagnostic_group = buffer
15432            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15433            .collect::<Vec<_>>();
15434
15435        let blocks =
15436            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15437
15438        let blocks = self.display_map.update(cx, |display_map, cx| {
15439            display_map.insert_blocks(blocks, cx).into_iter().collect()
15440        });
15441        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15442            active_range: buffer.anchor_before(diagnostic.range.start)
15443                ..buffer.anchor_after(diagnostic.range.end),
15444            active_message: diagnostic.diagnostic.message.clone(),
15445            group_id: diagnostic.diagnostic.group_id,
15446            blocks,
15447        });
15448        cx.notify();
15449    }
15450
15451    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15452        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15453            return;
15454        };
15455
15456        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15457        if let ActiveDiagnostic::Group(group) = prev {
15458            self.display_map.update(cx, |display_map, cx| {
15459                display_map.remove_blocks(group.blocks, cx);
15460            });
15461            cx.notify();
15462        }
15463    }
15464
15465    /// Disable inline diagnostics rendering for this editor.
15466    pub fn disable_inline_diagnostics(&mut self) {
15467        self.inline_diagnostics_enabled = false;
15468        self.inline_diagnostics_update = Task::ready(());
15469        self.inline_diagnostics.clear();
15470    }
15471
15472    pub fn diagnostics_enabled(&self) -> bool {
15473        self.mode.is_full()
15474    }
15475
15476    pub fn inline_diagnostics_enabled(&self) -> bool {
15477        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15478    }
15479
15480    pub fn show_inline_diagnostics(&self) -> bool {
15481        self.show_inline_diagnostics
15482    }
15483
15484    pub fn toggle_inline_diagnostics(
15485        &mut self,
15486        _: &ToggleInlineDiagnostics,
15487        window: &mut Window,
15488        cx: &mut Context<Editor>,
15489    ) {
15490        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15491        self.refresh_inline_diagnostics(false, window, cx);
15492    }
15493
15494    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15495        self.diagnostics_max_severity = severity;
15496        self.display_map.update(cx, |display_map, _| {
15497            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15498        });
15499    }
15500
15501    pub fn toggle_diagnostics(
15502        &mut self,
15503        _: &ToggleDiagnostics,
15504        window: &mut Window,
15505        cx: &mut Context<Editor>,
15506    ) {
15507        if !self.diagnostics_enabled() {
15508            return;
15509        }
15510
15511        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15512            EditorSettings::get_global(cx)
15513                .diagnostics_max_severity
15514                .filter(|severity| severity != &DiagnosticSeverity::Off)
15515                .unwrap_or(DiagnosticSeverity::Hint)
15516        } else {
15517            DiagnosticSeverity::Off
15518        };
15519        self.set_max_diagnostics_severity(new_severity, cx);
15520        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15521            self.active_diagnostics = ActiveDiagnostic::None;
15522            self.inline_diagnostics_update = Task::ready(());
15523            self.inline_diagnostics.clear();
15524        } else {
15525            self.refresh_inline_diagnostics(false, window, cx);
15526        }
15527
15528        cx.notify();
15529    }
15530
15531    pub fn toggle_minimap(
15532        &mut self,
15533        _: &ToggleMinimap,
15534        window: &mut Window,
15535        cx: &mut Context<Editor>,
15536    ) {
15537        if self.supports_minimap(cx) {
15538            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15539        }
15540    }
15541
15542    fn refresh_inline_diagnostics(
15543        &mut self,
15544        debounce: bool,
15545        window: &mut Window,
15546        cx: &mut Context<Self>,
15547    ) {
15548        let max_severity = ProjectSettings::get_global(cx)
15549            .diagnostics
15550            .inline
15551            .max_severity
15552            .unwrap_or(self.diagnostics_max_severity);
15553
15554        if !self.inline_diagnostics_enabled()
15555            || !self.show_inline_diagnostics
15556            || max_severity == DiagnosticSeverity::Off
15557        {
15558            self.inline_diagnostics_update = Task::ready(());
15559            self.inline_diagnostics.clear();
15560            return;
15561        }
15562
15563        let debounce_ms = ProjectSettings::get_global(cx)
15564            .diagnostics
15565            .inline
15566            .update_debounce_ms;
15567        let debounce = if debounce && debounce_ms > 0 {
15568            Some(Duration::from_millis(debounce_ms))
15569        } else {
15570            None
15571        };
15572        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15573            let editor = editor.upgrade().unwrap();
15574
15575            if let Some(debounce) = debounce {
15576                cx.background_executor().timer(debounce).await;
15577            }
15578            let Some(snapshot) = editor
15579                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15580                .ok()
15581            else {
15582                return;
15583            };
15584
15585            let new_inline_diagnostics = cx
15586                .background_spawn(async move {
15587                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15588                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15589                        let message = diagnostic_entry
15590                            .diagnostic
15591                            .message
15592                            .split_once('\n')
15593                            .map(|(line, _)| line)
15594                            .map(SharedString::new)
15595                            .unwrap_or_else(|| {
15596                                SharedString::from(diagnostic_entry.diagnostic.message)
15597                            });
15598                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15599                        let (Ok(i) | Err(i)) = inline_diagnostics
15600                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15601                        inline_diagnostics.insert(
15602                            i,
15603                            (
15604                                start_anchor,
15605                                InlineDiagnostic {
15606                                    message,
15607                                    group_id: diagnostic_entry.diagnostic.group_id,
15608                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15609                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15610                                    severity: diagnostic_entry.diagnostic.severity,
15611                                },
15612                            ),
15613                        );
15614                    }
15615                    inline_diagnostics
15616                })
15617                .await;
15618
15619            editor
15620                .update(cx, |editor, cx| {
15621                    editor.inline_diagnostics = new_inline_diagnostics;
15622                    cx.notify();
15623                })
15624                .ok();
15625        });
15626    }
15627
15628    pub fn set_selections_from_remote(
15629        &mut self,
15630        selections: Vec<Selection<Anchor>>,
15631        pending_selection: Option<Selection<Anchor>>,
15632        window: &mut Window,
15633        cx: &mut Context<Self>,
15634    ) {
15635        let old_cursor_position = self.selections.newest_anchor().head();
15636        self.selections.change_with(cx, |s| {
15637            s.select_anchors(selections);
15638            if let Some(pending_selection) = pending_selection {
15639                s.set_pending(pending_selection, SelectMode::Character);
15640            } else {
15641                s.clear_pending();
15642            }
15643        });
15644        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15645    }
15646
15647    fn push_to_selection_history(&mut self) {
15648        self.selection_history.push(SelectionHistoryEntry {
15649            selections: self.selections.disjoint_anchors(),
15650            select_next_state: self.select_next_state.clone(),
15651            select_prev_state: self.select_prev_state.clone(),
15652            add_selections_state: self.add_selections_state.clone(),
15653        });
15654    }
15655
15656    pub fn transact(
15657        &mut self,
15658        window: &mut Window,
15659        cx: &mut Context<Self>,
15660        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15661    ) -> Option<TransactionId> {
15662        self.start_transaction_at(Instant::now(), window, cx);
15663        update(self, window, cx);
15664        self.end_transaction_at(Instant::now(), cx)
15665    }
15666
15667    pub fn start_transaction_at(
15668        &mut self,
15669        now: Instant,
15670        window: &mut Window,
15671        cx: &mut Context<Self>,
15672    ) {
15673        self.end_selection(window, cx);
15674        if let Some(tx_id) = self
15675            .buffer
15676            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15677        {
15678            self.selection_history
15679                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15680            cx.emit(EditorEvent::TransactionBegun {
15681                transaction_id: tx_id,
15682            })
15683        }
15684    }
15685
15686    pub fn end_transaction_at(
15687        &mut self,
15688        now: Instant,
15689        cx: &mut Context<Self>,
15690    ) -> Option<TransactionId> {
15691        if let Some(transaction_id) = self
15692            .buffer
15693            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15694        {
15695            if let Some((_, end_selections)) =
15696                self.selection_history.transaction_mut(transaction_id)
15697            {
15698                *end_selections = Some(self.selections.disjoint_anchors());
15699            } else {
15700                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15701            }
15702
15703            cx.emit(EditorEvent::Edited { transaction_id });
15704            Some(transaction_id)
15705        } else {
15706            None
15707        }
15708    }
15709
15710    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15711        if self.selection_mark_mode {
15712            self.change_selections(None, window, cx, |s| {
15713                s.move_with(|_, sel| {
15714                    sel.collapse_to(sel.head(), SelectionGoal::None);
15715                });
15716            })
15717        }
15718        self.selection_mark_mode = true;
15719        cx.notify();
15720    }
15721
15722    pub fn swap_selection_ends(
15723        &mut self,
15724        _: &actions::SwapSelectionEnds,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) {
15728        self.change_selections(None, window, cx, |s| {
15729            s.move_with(|_, sel| {
15730                if sel.start != sel.end {
15731                    sel.reversed = !sel.reversed
15732                }
15733            });
15734        });
15735        self.request_autoscroll(Autoscroll::newest(), cx);
15736        cx.notify();
15737    }
15738
15739    pub fn toggle_fold(
15740        &mut self,
15741        _: &actions::ToggleFold,
15742        window: &mut Window,
15743        cx: &mut Context<Self>,
15744    ) {
15745        if self.is_singleton(cx) {
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_lines(&Default::default(), window, cx)
15760            } else {
15761                self.fold(&Default::default(), window, cx)
15762            }
15763        } else {
15764            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15765            let buffer_ids: HashSet<_> = self
15766                .selections
15767                .disjoint_anchor_ranges()
15768                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15769                .collect();
15770
15771            let should_unfold = buffer_ids
15772                .iter()
15773                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15774
15775            for buffer_id in buffer_ids {
15776                if should_unfold {
15777                    self.unfold_buffer(buffer_id, cx);
15778                } else {
15779                    self.fold_buffer(buffer_id, cx);
15780                }
15781            }
15782        }
15783    }
15784
15785    pub fn toggle_fold_recursive(
15786        &mut self,
15787        _: &actions::ToggleFoldRecursive,
15788        window: &mut Window,
15789        cx: &mut Context<Self>,
15790    ) {
15791        let selection = self.selections.newest::<Point>(cx);
15792
15793        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15794        let range = if selection.is_empty() {
15795            let point = selection.head().to_display_point(&display_map);
15796            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15797            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15798                .to_point(&display_map);
15799            start..end
15800        } else {
15801            selection.range()
15802        };
15803        if display_map.folds_in_range(range).next().is_some() {
15804            self.unfold_recursive(&Default::default(), window, cx)
15805        } else {
15806            self.fold_recursive(&Default::default(), window, cx)
15807        }
15808    }
15809
15810    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15811        if self.is_singleton(cx) {
15812            let mut to_fold = Vec::new();
15813            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15814            let selections = self.selections.all_adjusted(cx);
15815
15816            for selection in selections {
15817                let range = selection.range().sorted();
15818                let buffer_start_row = range.start.row;
15819
15820                if range.start.row != range.end.row {
15821                    let mut found = false;
15822                    let mut row = range.start.row;
15823                    while row <= range.end.row {
15824                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15825                        {
15826                            found = true;
15827                            row = crease.range().end.row + 1;
15828                            to_fold.push(crease);
15829                        } else {
15830                            row += 1
15831                        }
15832                    }
15833                    if found {
15834                        continue;
15835                    }
15836                }
15837
15838                for row in (0..=range.start.row).rev() {
15839                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15840                        if crease.range().end.row >= buffer_start_row {
15841                            to_fold.push(crease);
15842                            if row <= range.start.row {
15843                                break;
15844                            }
15845                        }
15846                    }
15847                }
15848            }
15849
15850            self.fold_creases(to_fold, true, window, cx);
15851        } else {
15852            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15853            let buffer_ids = self
15854                .selections
15855                .disjoint_anchor_ranges()
15856                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15857                .collect::<HashSet<_>>();
15858            for buffer_id in buffer_ids {
15859                self.fold_buffer(buffer_id, cx);
15860            }
15861        }
15862    }
15863
15864    fn fold_at_level(
15865        &mut self,
15866        fold_at: &FoldAtLevel,
15867        window: &mut Window,
15868        cx: &mut Context<Self>,
15869    ) {
15870        if !self.buffer.read(cx).is_singleton() {
15871            return;
15872        }
15873
15874        let fold_at_level = fold_at.0;
15875        let snapshot = self.buffer.read(cx).snapshot(cx);
15876        let mut to_fold = Vec::new();
15877        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15878
15879        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15880            while start_row < end_row {
15881                match self
15882                    .snapshot(window, cx)
15883                    .crease_for_buffer_row(MultiBufferRow(start_row))
15884                {
15885                    Some(crease) => {
15886                        let nested_start_row = crease.range().start.row + 1;
15887                        let nested_end_row = crease.range().end.row;
15888
15889                        if current_level < fold_at_level {
15890                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15891                        } else if current_level == fold_at_level {
15892                            to_fold.push(crease);
15893                        }
15894
15895                        start_row = nested_end_row + 1;
15896                    }
15897                    None => start_row += 1,
15898                }
15899            }
15900        }
15901
15902        self.fold_creases(to_fold, true, window, cx);
15903    }
15904
15905    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15906        if self.buffer.read(cx).is_singleton() {
15907            let mut fold_ranges = Vec::new();
15908            let snapshot = self.buffer.read(cx).snapshot(cx);
15909
15910            for row in 0..snapshot.max_row().0 {
15911                if let Some(foldable_range) = self
15912                    .snapshot(window, cx)
15913                    .crease_for_buffer_row(MultiBufferRow(row))
15914                {
15915                    fold_ranges.push(foldable_range);
15916                }
15917            }
15918
15919            self.fold_creases(fold_ranges, true, window, cx);
15920        } else {
15921            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15922                editor
15923                    .update_in(cx, |editor, _, cx| {
15924                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15925                            editor.fold_buffer(buffer_id, cx);
15926                        }
15927                    })
15928                    .ok();
15929            });
15930        }
15931    }
15932
15933    pub fn fold_function_bodies(
15934        &mut self,
15935        _: &actions::FoldFunctionBodies,
15936        window: &mut Window,
15937        cx: &mut Context<Self>,
15938    ) {
15939        let snapshot = self.buffer.read(cx).snapshot(cx);
15940
15941        let ranges = snapshot
15942            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15943            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15944            .collect::<Vec<_>>();
15945
15946        let creases = ranges
15947            .into_iter()
15948            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15949            .collect();
15950
15951        self.fold_creases(creases, true, window, cx);
15952    }
15953
15954    pub fn fold_recursive(
15955        &mut self,
15956        _: &actions::FoldRecursive,
15957        window: &mut Window,
15958        cx: &mut Context<Self>,
15959    ) {
15960        let mut to_fold = Vec::new();
15961        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15962        let selections = self.selections.all_adjusted(cx);
15963
15964        for selection in selections {
15965            let range = selection.range().sorted();
15966            let buffer_start_row = range.start.row;
15967
15968            if range.start.row != range.end.row {
15969                let mut found = false;
15970                for row in range.start.row..=range.end.row {
15971                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15972                        found = true;
15973                        to_fold.push(crease);
15974                    }
15975                }
15976                if found {
15977                    continue;
15978                }
15979            }
15980
15981            for row in (0..=range.start.row).rev() {
15982                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15983                    if crease.range().end.row >= buffer_start_row {
15984                        to_fold.push(crease);
15985                    } else {
15986                        break;
15987                    }
15988                }
15989            }
15990        }
15991
15992        self.fold_creases(to_fold, true, window, cx);
15993    }
15994
15995    pub fn fold_at(
15996        &mut self,
15997        buffer_row: MultiBufferRow,
15998        window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16002
16003        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16004            let autoscroll = self
16005                .selections
16006                .all::<Point>(cx)
16007                .iter()
16008                .any(|selection| crease.range().overlaps(&selection.range()));
16009
16010            self.fold_creases(vec![crease], autoscroll, window, cx);
16011        }
16012    }
16013
16014    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16015        if self.is_singleton(cx) {
16016            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16017            let buffer = &display_map.buffer_snapshot;
16018            let selections = self.selections.all::<Point>(cx);
16019            let ranges = selections
16020                .iter()
16021                .map(|s| {
16022                    let range = s.display_range(&display_map).sorted();
16023                    let mut start = range.start.to_point(&display_map);
16024                    let mut end = range.end.to_point(&display_map);
16025                    start.column = 0;
16026                    end.column = buffer.line_len(MultiBufferRow(end.row));
16027                    start..end
16028                })
16029                .collect::<Vec<_>>();
16030
16031            self.unfold_ranges(&ranges, true, true, cx);
16032        } else {
16033            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16034            let buffer_ids = self
16035                .selections
16036                .disjoint_anchor_ranges()
16037                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16038                .collect::<HashSet<_>>();
16039            for buffer_id in buffer_ids {
16040                self.unfold_buffer(buffer_id, cx);
16041            }
16042        }
16043    }
16044
16045    pub fn unfold_recursive(
16046        &mut self,
16047        _: &UnfoldRecursive,
16048        _window: &mut Window,
16049        cx: &mut Context<Self>,
16050    ) {
16051        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16052        let selections = self.selections.all::<Point>(cx);
16053        let ranges = selections
16054            .iter()
16055            .map(|s| {
16056                let mut range = s.display_range(&display_map).sorted();
16057                *range.start.column_mut() = 0;
16058                *range.end.column_mut() = display_map.line_len(range.end.row());
16059                let start = range.start.to_point(&display_map);
16060                let end = range.end.to_point(&display_map);
16061                start..end
16062            })
16063            .collect::<Vec<_>>();
16064
16065        self.unfold_ranges(&ranges, true, true, cx);
16066    }
16067
16068    pub fn unfold_at(
16069        &mut self,
16070        buffer_row: MultiBufferRow,
16071        _window: &mut Window,
16072        cx: &mut Context<Self>,
16073    ) {
16074        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16075
16076        let intersection_range = Point::new(buffer_row.0, 0)
16077            ..Point::new(
16078                buffer_row.0,
16079                display_map.buffer_snapshot.line_len(buffer_row),
16080            );
16081
16082        let autoscroll = self
16083            .selections
16084            .all::<Point>(cx)
16085            .iter()
16086            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16087
16088        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16089    }
16090
16091    pub fn unfold_all(
16092        &mut self,
16093        _: &actions::UnfoldAll,
16094        _window: &mut Window,
16095        cx: &mut Context<Self>,
16096    ) {
16097        if self.buffer.read(cx).is_singleton() {
16098            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16099            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16100        } else {
16101            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16102                editor
16103                    .update(cx, |editor, cx| {
16104                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16105                            editor.unfold_buffer(buffer_id, cx);
16106                        }
16107                    })
16108                    .ok();
16109            });
16110        }
16111    }
16112
16113    pub fn fold_selected_ranges(
16114        &mut self,
16115        _: &FoldSelectedRanges,
16116        window: &mut Window,
16117        cx: &mut Context<Self>,
16118    ) {
16119        let selections = self.selections.all_adjusted(cx);
16120        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16121        let ranges = selections
16122            .into_iter()
16123            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16124            .collect::<Vec<_>>();
16125        self.fold_creases(ranges, true, window, cx);
16126    }
16127
16128    pub fn fold_ranges<T: ToOffset + Clone>(
16129        &mut self,
16130        ranges: Vec<Range<T>>,
16131        auto_scroll: bool,
16132        window: &mut Window,
16133        cx: &mut Context<Self>,
16134    ) {
16135        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16136        let ranges = ranges
16137            .into_iter()
16138            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16139            .collect::<Vec<_>>();
16140        self.fold_creases(ranges, auto_scroll, window, cx);
16141    }
16142
16143    pub fn fold_creases<T: ToOffset + Clone>(
16144        &mut self,
16145        creases: Vec<Crease<T>>,
16146        auto_scroll: bool,
16147        _window: &mut Window,
16148        cx: &mut Context<Self>,
16149    ) {
16150        if creases.is_empty() {
16151            return;
16152        }
16153
16154        let mut buffers_affected = HashSet::default();
16155        let multi_buffer = self.buffer().read(cx);
16156        for crease in &creases {
16157            if let Some((_, buffer, _)) =
16158                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16159            {
16160                buffers_affected.insert(buffer.read(cx).remote_id());
16161            };
16162        }
16163
16164        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16165
16166        if auto_scroll {
16167            self.request_autoscroll(Autoscroll::fit(), cx);
16168        }
16169
16170        cx.notify();
16171
16172        self.scrollbar_marker_state.dirty = true;
16173        self.folds_did_change(cx);
16174    }
16175
16176    /// Removes any folds whose ranges intersect any of the given ranges.
16177    pub fn unfold_ranges<T: ToOffset + Clone>(
16178        &mut self,
16179        ranges: &[Range<T>],
16180        inclusive: bool,
16181        auto_scroll: bool,
16182        cx: &mut Context<Self>,
16183    ) {
16184        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16185            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16186        });
16187        self.folds_did_change(cx);
16188    }
16189
16190    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16191        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16192            return;
16193        }
16194        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16195        self.display_map.update(cx, |display_map, cx| {
16196            display_map.fold_buffers([buffer_id], cx)
16197        });
16198        cx.emit(EditorEvent::BufferFoldToggled {
16199            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16200            folded: true,
16201        });
16202        cx.notify();
16203    }
16204
16205    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16206        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16207            return;
16208        }
16209        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16210        self.display_map.update(cx, |display_map, cx| {
16211            display_map.unfold_buffers([buffer_id], cx);
16212        });
16213        cx.emit(EditorEvent::BufferFoldToggled {
16214            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16215            folded: false,
16216        });
16217        cx.notify();
16218    }
16219
16220    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16221        self.display_map.read(cx).is_buffer_folded(buffer)
16222    }
16223
16224    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16225        self.display_map.read(cx).folded_buffers()
16226    }
16227
16228    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16229        self.display_map.update(cx, |display_map, cx| {
16230            display_map.disable_header_for_buffer(buffer_id, cx);
16231        });
16232        cx.notify();
16233    }
16234
16235    /// Removes any folds with the given ranges.
16236    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16237        &mut self,
16238        ranges: &[Range<T>],
16239        type_id: TypeId,
16240        auto_scroll: bool,
16241        cx: &mut Context<Self>,
16242    ) {
16243        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16244            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16245        });
16246        self.folds_did_change(cx);
16247    }
16248
16249    fn remove_folds_with<T: ToOffset + Clone>(
16250        &mut self,
16251        ranges: &[Range<T>],
16252        auto_scroll: bool,
16253        cx: &mut Context<Self>,
16254        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16255    ) {
16256        if ranges.is_empty() {
16257            return;
16258        }
16259
16260        let mut buffers_affected = HashSet::default();
16261        let multi_buffer = self.buffer().read(cx);
16262        for range in ranges {
16263            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16264                buffers_affected.insert(buffer.read(cx).remote_id());
16265            };
16266        }
16267
16268        self.display_map.update(cx, update);
16269
16270        if auto_scroll {
16271            self.request_autoscroll(Autoscroll::fit(), cx);
16272        }
16273
16274        cx.notify();
16275        self.scrollbar_marker_state.dirty = true;
16276        self.active_indent_guides_state.dirty = true;
16277    }
16278
16279    pub fn update_fold_widths(
16280        &mut self,
16281        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16282        cx: &mut Context<Self>,
16283    ) -> bool {
16284        self.display_map
16285            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16286    }
16287
16288    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16289        self.display_map.read(cx).fold_placeholder.clone()
16290    }
16291
16292    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16293        self.buffer.update(cx, |buffer, cx| {
16294            buffer.set_all_diff_hunks_expanded(cx);
16295        });
16296    }
16297
16298    pub fn expand_all_diff_hunks(
16299        &mut self,
16300        _: &ExpandAllDiffHunks,
16301        _window: &mut Window,
16302        cx: &mut Context<Self>,
16303    ) {
16304        self.buffer.update(cx, |buffer, cx| {
16305            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16306        });
16307    }
16308
16309    pub fn toggle_selected_diff_hunks(
16310        &mut self,
16311        _: &ToggleSelectedDiffHunks,
16312        _window: &mut Window,
16313        cx: &mut Context<Self>,
16314    ) {
16315        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16316        self.toggle_diff_hunks_in_ranges(ranges, cx);
16317    }
16318
16319    pub fn diff_hunks_in_ranges<'a>(
16320        &'a self,
16321        ranges: &'a [Range<Anchor>],
16322        buffer: &'a MultiBufferSnapshot,
16323    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16324        ranges.iter().flat_map(move |range| {
16325            let end_excerpt_id = range.end.excerpt_id;
16326            let range = range.to_point(buffer);
16327            let mut peek_end = range.end;
16328            if range.end.row < buffer.max_row().0 {
16329                peek_end = Point::new(range.end.row + 1, 0);
16330            }
16331            buffer
16332                .diff_hunks_in_range(range.start..peek_end)
16333                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16334        })
16335    }
16336
16337    pub fn has_stageable_diff_hunks_in_ranges(
16338        &self,
16339        ranges: &[Range<Anchor>],
16340        snapshot: &MultiBufferSnapshot,
16341    ) -> bool {
16342        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16343        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16344    }
16345
16346    pub fn toggle_staged_selected_diff_hunks(
16347        &mut self,
16348        _: &::git::ToggleStaged,
16349        _: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) {
16352        let snapshot = self.buffer.read(cx).snapshot(cx);
16353        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16354        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16355        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16356    }
16357
16358    pub fn set_render_diff_hunk_controls(
16359        &mut self,
16360        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16361        cx: &mut Context<Self>,
16362    ) {
16363        self.render_diff_hunk_controls = render_diff_hunk_controls;
16364        cx.notify();
16365    }
16366
16367    pub fn stage_and_next(
16368        &mut self,
16369        _: &::git::StageAndNext,
16370        window: &mut Window,
16371        cx: &mut Context<Self>,
16372    ) {
16373        self.do_stage_or_unstage_and_next(true, window, cx);
16374    }
16375
16376    pub fn unstage_and_next(
16377        &mut self,
16378        _: &::git::UnstageAndNext,
16379        window: &mut Window,
16380        cx: &mut Context<Self>,
16381    ) {
16382        self.do_stage_or_unstage_and_next(false, window, cx);
16383    }
16384
16385    pub fn stage_or_unstage_diff_hunks(
16386        &mut self,
16387        stage: bool,
16388        ranges: Vec<Range<Anchor>>,
16389        cx: &mut Context<Self>,
16390    ) {
16391        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16392        cx.spawn(async move |this, cx| {
16393            task.await?;
16394            this.update(cx, |this, cx| {
16395                let snapshot = this.buffer.read(cx).snapshot(cx);
16396                let chunk_by = this
16397                    .diff_hunks_in_ranges(&ranges, &snapshot)
16398                    .chunk_by(|hunk| hunk.buffer_id);
16399                for (buffer_id, hunks) in &chunk_by {
16400                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16401                }
16402            })
16403        })
16404        .detach_and_log_err(cx);
16405    }
16406
16407    fn save_buffers_for_ranges_if_needed(
16408        &mut self,
16409        ranges: &[Range<Anchor>],
16410        cx: &mut Context<Editor>,
16411    ) -> Task<Result<()>> {
16412        let multibuffer = self.buffer.read(cx);
16413        let snapshot = multibuffer.read(cx);
16414        let buffer_ids: HashSet<_> = ranges
16415            .iter()
16416            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16417            .collect();
16418        drop(snapshot);
16419
16420        let mut buffers = HashSet::default();
16421        for buffer_id in buffer_ids {
16422            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16423                let buffer = buffer_entity.read(cx);
16424                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16425                {
16426                    buffers.insert(buffer_entity);
16427                }
16428            }
16429        }
16430
16431        if let Some(project) = &self.project {
16432            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16433        } else {
16434            Task::ready(Ok(()))
16435        }
16436    }
16437
16438    fn do_stage_or_unstage_and_next(
16439        &mut self,
16440        stage: bool,
16441        window: &mut Window,
16442        cx: &mut Context<Self>,
16443    ) {
16444        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16445
16446        if ranges.iter().any(|range| range.start != range.end) {
16447            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16448            return;
16449        }
16450
16451        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16452        let snapshot = self.snapshot(window, cx);
16453        let position = self.selections.newest::<Point>(cx).head();
16454        let mut row = snapshot
16455            .buffer_snapshot
16456            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16457            .find(|hunk| hunk.row_range.start.0 > position.row)
16458            .map(|hunk| hunk.row_range.start);
16459
16460        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16461        // Outside of the project diff editor, wrap around to the beginning.
16462        if !all_diff_hunks_expanded {
16463            row = row.or_else(|| {
16464                snapshot
16465                    .buffer_snapshot
16466                    .diff_hunks_in_range(Point::zero()..position)
16467                    .find(|hunk| hunk.row_range.end.0 < position.row)
16468                    .map(|hunk| hunk.row_range.start)
16469            });
16470        }
16471
16472        if let Some(row) = row {
16473            let destination = Point::new(row.0, 0);
16474            let autoscroll = Autoscroll::center();
16475
16476            self.unfold_ranges(&[destination..destination], false, false, cx);
16477            self.change_selections(Some(autoscroll), window, cx, |s| {
16478                s.select_ranges([destination..destination]);
16479            });
16480        }
16481    }
16482
16483    fn do_stage_or_unstage(
16484        &self,
16485        stage: bool,
16486        buffer_id: BufferId,
16487        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16488        cx: &mut App,
16489    ) -> Option<()> {
16490        let project = self.project.as_ref()?;
16491        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16492        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16493        let buffer_snapshot = buffer.read(cx).snapshot();
16494        let file_exists = buffer_snapshot
16495            .file()
16496            .is_some_and(|file| file.disk_state().exists());
16497        diff.update(cx, |diff, cx| {
16498            diff.stage_or_unstage_hunks(
16499                stage,
16500                &hunks
16501                    .map(|hunk| buffer_diff::DiffHunk {
16502                        buffer_range: hunk.buffer_range,
16503                        diff_base_byte_range: hunk.diff_base_byte_range,
16504                        secondary_status: hunk.secondary_status,
16505                        range: Point::zero()..Point::zero(), // unused
16506                    })
16507                    .collect::<Vec<_>>(),
16508                &buffer_snapshot,
16509                file_exists,
16510                cx,
16511            )
16512        });
16513        None
16514    }
16515
16516    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16517        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16518        self.buffer
16519            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16520    }
16521
16522    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16523        self.buffer.update(cx, |buffer, cx| {
16524            let ranges = vec![Anchor::min()..Anchor::max()];
16525            if !buffer.all_diff_hunks_expanded()
16526                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16527            {
16528                buffer.collapse_diff_hunks(ranges, cx);
16529                true
16530            } else {
16531                false
16532            }
16533        })
16534    }
16535
16536    fn toggle_diff_hunks_in_ranges(
16537        &mut self,
16538        ranges: Vec<Range<Anchor>>,
16539        cx: &mut Context<Editor>,
16540    ) {
16541        self.buffer.update(cx, |buffer, cx| {
16542            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16543            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16544        })
16545    }
16546
16547    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16548        self.buffer.update(cx, |buffer, cx| {
16549            let snapshot = buffer.snapshot(cx);
16550            let excerpt_id = range.end.excerpt_id;
16551            let point_range = range.to_point(&snapshot);
16552            let expand = !buffer.single_hunk_is_expanded(range, cx);
16553            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16554        })
16555    }
16556
16557    pub(crate) fn apply_all_diff_hunks(
16558        &mut self,
16559        _: &ApplyAllDiffHunks,
16560        window: &mut Window,
16561        cx: &mut Context<Self>,
16562    ) {
16563        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16564
16565        let buffers = self.buffer.read(cx).all_buffers();
16566        for branch_buffer in buffers {
16567            branch_buffer.update(cx, |branch_buffer, cx| {
16568                branch_buffer.merge_into_base(Vec::new(), cx);
16569            });
16570        }
16571
16572        if let Some(project) = self.project.clone() {
16573            self.save(true, project, window, cx).detach_and_log_err(cx);
16574        }
16575    }
16576
16577    pub(crate) fn apply_selected_diff_hunks(
16578        &mut self,
16579        _: &ApplyDiffHunk,
16580        window: &mut Window,
16581        cx: &mut Context<Self>,
16582    ) {
16583        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16584        let snapshot = self.snapshot(window, cx);
16585        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16586        let mut ranges_by_buffer = HashMap::default();
16587        self.transact(window, cx, |editor, _window, cx| {
16588            for hunk in hunks {
16589                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16590                    ranges_by_buffer
16591                        .entry(buffer.clone())
16592                        .or_insert_with(Vec::new)
16593                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16594                }
16595            }
16596
16597            for (buffer, ranges) in ranges_by_buffer {
16598                buffer.update(cx, |buffer, cx| {
16599                    buffer.merge_into_base(ranges, cx);
16600                });
16601            }
16602        });
16603
16604        if let Some(project) = self.project.clone() {
16605            self.save(true, project, window, cx).detach_and_log_err(cx);
16606        }
16607    }
16608
16609    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16610        if hovered != self.gutter_hovered {
16611            self.gutter_hovered = hovered;
16612            cx.notify();
16613        }
16614    }
16615
16616    pub fn insert_blocks(
16617        &mut self,
16618        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16619        autoscroll: Option<Autoscroll>,
16620        cx: &mut Context<Self>,
16621    ) -> Vec<CustomBlockId> {
16622        let blocks = self
16623            .display_map
16624            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16625        if let Some(autoscroll) = autoscroll {
16626            self.request_autoscroll(autoscroll, cx);
16627        }
16628        cx.notify();
16629        blocks
16630    }
16631
16632    pub fn resize_blocks(
16633        &mut self,
16634        heights: HashMap<CustomBlockId, u32>,
16635        autoscroll: Option<Autoscroll>,
16636        cx: &mut Context<Self>,
16637    ) {
16638        self.display_map
16639            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16640        if let Some(autoscroll) = autoscroll {
16641            self.request_autoscroll(autoscroll, cx);
16642        }
16643        cx.notify();
16644    }
16645
16646    pub fn replace_blocks(
16647        &mut self,
16648        renderers: HashMap<CustomBlockId, RenderBlock>,
16649        autoscroll: Option<Autoscroll>,
16650        cx: &mut Context<Self>,
16651    ) {
16652        self.display_map
16653            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16654        if let Some(autoscroll) = autoscroll {
16655            self.request_autoscroll(autoscroll, cx);
16656        }
16657        cx.notify();
16658    }
16659
16660    pub fn remove_blocks(
16661        &mut self,
16662        block_ids: HashSet<CustomBlockId>,
16663        autoscroll: Option<Autoscroll>,
16664        cx: &mut Context<Self>,
16665    ) {
16666        self.display_map.update(cx, |display_map, cx| {
16667            display_map.remove_blocks(block_ids, cx)
16668        });
16669        if let Some(autoscroll) = autoscroll {
16670            self.request_autoscroll(autoscroll, cx);
16671        }
16672        cx.notify();
16673    }
16674
16675    pub fn row_for_block(
16676        &self,
16677        block_id: CustomBlockId,
16678        cx: &mut Context<Self>,
16679    ) -> Option<DisplayRow> {
16680        self.display_map
16681            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16682    }
16683
16684    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16685        self.focused_block = Some(focused_block);
16686    }
16687
16688    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16689        self.focused_block.take()
16690    }
16691
16692    pub fn insert_creases(
16693        &mut self,
16694        creases: impl IntoIterator<Item = Crease<Anchor>>,
16695        cx: &mut Context<Self>,
16696    ) -> Vec<CreaseId> {
16697        self.display_map
16698            .update(cx, |map, cx| map.insert_creases(creases, cx))
16699    }
16700
16701    pub fn remove_creases(
16702        &mut self,
16703        ids: impl IntoIterator<Item = CreaseId>,
16704        cx: &mut Context<Self>,
16705    ) -> Vec<(CreaseId, Range<Anchor>)> {
16706        self.display_map
16707            .update(cx, |map, cx| map.remove_creases(ids, cx))
16708    }
16709
16710    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16711        self.display_map
16712            .update(cx, |map, cx| map.snapshot(cx))
16713            .longest_row()
16714    }
16715
16716    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16717        self.display_map
16718            .update(cx, |map, cx| map.snapshot(cx))
16719            .max_point()
16720    }
16721
16722    pub fn text(&self, cx: &App) -> String {
16723        self.buffer.read(cx).read(cx).text()
16724    }
16725
16726    pub fn is_empty(&self, cx: &App) -> bool {
16727        self.buffer.read(cx).read(cx).is_empty()
16728    }
16729
16730    pub fn text_option(&self, cx: &App) -> Option<String> {
16731        let text = self.text(cx);
16732        let text = text.trim();
16733
16734        if text.is_empty() {
16735            return None;
16736        }
16737
16738        Some(text.to_string())
16739    }
16740
16741    pub fn set_text(
16742        &mut self,
16743        text: impl Into<Arc<str>>,
16744        window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) {
16747        self.transact(window, cx, |this, _, cx| {
16748            this.buffer
16749                .read(cx)
16750                .as_singleton()
16751                .expect("you can only call set_text on editors for singleton buffers")
16752                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16753        });
16754    }
16755
16756    pub fn display_text(&self, cx: &mut App) -> String {
16757        self.display_map
16758            .update(cx, |map, cx| map.snapshot(cx))
16759            .text()
16760    }
16761
16762    fn create_minimap(
16763        &self,
16764        minimap_settings: MinimapSettings,
16765        window: &mut Window,
16766        cx: &mut Context<Self>,
16767    ) -> Option<Entity<Self>> {
16768        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16769            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16770    }
16771
16772    fn initialize_new_minimap(
16773        &self,
16774        minimap_settings: MinimapSettings,
16775        window: &mut Window,
16776        cx: &mut Context<Self>,
16777    ) -> Entity<Self> {
16778        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16779
16780        let mut minimap = Editor::new_internal(
16781            EditorMode::Minimap {
16782                parent: cx.weak_entity(),
16783            },
16784            self.buffer.clone(),
16785            self.project.clone(),
16786            Some(self.display_map.clone()),
16787            window,
16788            cx,
16789        );
16790        minimap.scroll_manager.clone_state(&self.scroll_manager);
16791        minimap.set_text_style_refinement(TextStyleRefinement {
16792            font_size: Some(MINIMAP_FONT_SIZE),
16793            font_weight: Some(MINIMAP_FONT_WEIGHT),
16794            ..Default::default()
16795        });
16796        minimap.update_minimap_configuration(minimap_settings, cx);
16797        cx.new(|_| minimap)
16798    }
16799
16800    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16801        let current_line_highlight = minimap_settings
16802            .current_line_highlight
16803            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16804        self.set_current_line_highlight(Some(current_line_highlight));
16805    }
16806
16807    pub fn minimap(&self) -> Option<&Entity<Self>> {
16808        self.minimap
16809            .as_ref()
16810            .filter(|_| self.minimap_visibility.visible())
16811    }
16812
16813    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16814        let mut wrap_guides = smallvec![];
16815
16816        if self.show_wrap_guides == Some(false) {
16817            return wrap_guides;
16818        }
16819
16820        let settings = self.buffer.read(cx).language_settings(cx);
16821        if settings.show_wrap_guides {
16822            match self.soft_wrap_mode(cx) {
16823                SoftWrap::Column(soft_wrap) => {
16824                    wrap_guides.push((soft_wrap as usize, true));
16825                }
16826                SoftWrap::Bounded(soft_wrap) => {
16827                    wrap_guides.push((soft_wrap as usize, true));
16828                }
16829                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16830            }
16831            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16832        }
16833
16834        wrap_guides
16835    }
16836
16837    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16838        let settings = self.buffer.read(cx).language_settings(cx);
16839        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16840        match mode {
16841            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16842                SoftWrap::None
16843            }
16844            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16845            language_settings::SoftWrap::PreferredLineLength => {
16846                SoftWrap::Column(settings.preferred_line_length)
16847            }
16848            language_settings::SoftWrap::Bounded => {
16849                SoftWrap::Bounded(settings.preferred_line_length)
16850            }
16851        }
16852    }
16853
16854    pub fn set_soft_wrap_mode(
16855        &mut self,
16856        mode: language_settings::SoftWrap,
16857
16858        cx: &mut Context<Self>,
16859    ) {
16860        self.soft_wrap_mode_override = Some(mode);
16861        cx.notify();
16862    }
16863
16864    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16865        self.hard_wrap = hard_wrap;
16866        cx.notify();
16867    }
16868
16869    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16870        self.text_style_refinement = Some(style);
16871    }
16872
16873    /// called by the Element so we know what style we were most recently rendered with.
16874    pub(crate) fn set_style(
16875        &mut self,
16876        style: EditorStyle,
16877        window: &mut Window,
16878        cx: &mut Context<Self>,
16879    ) {
16880        // We intentionally do not inform the display map about the minimap style
16881        // so that wrapping is not recalculated and stays consistent for the editor
16882        // and its linked minimap.
16883        if !self.mode.is_minimap() {
16884            let rem_size = window.rem_size();
16885            self.display_map.update(cx, |map, cx| {
16886                map.set_font(
16887                    style.text.font(),
16888                    style.text.font_size.to_pixels(rem_size),
16889                    cx,
16890                )
16891            });
16892        }
16893        self.style = Some(style);
16894    }
16895
16896    pub fn style(&self) -> Option<&EditorStyle> {
16897        self.style.as_ref()
16898    }
16899
16900    // Called by the element. This method is not designed to be called outside of the editor
16901    // element's layout code because it does not notify when rewrapping is computed synchronously.
16902    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16903        self.display_map
16904            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16905    }
16906
16907    pub fn set_soft_wrap(&mut self) {
16908        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16909    }
16910
16911    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16912        if self.soft_wrap_mode_override.is_some() {
16913            self.soft_wrap_mode_override.take();
16914        } else {
16915            let soft_wrap = match self.soft_wrap_mode(cx) {
16916                SoftWrap::GitDiff => return,
16917                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16918                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16919                    language_settings::SoftWrap::None
16920                }
16921            };
16922            self.soft_wrap_mode_override = Some(soft_wrap);
16923        }
16924        cx.notify();
16925    }
16926
16927    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16928        let Some(workspace) = self.workspace() else {
16929            return;
16930        };
16931        let fs = workspace.read(cx).app_state().fs.clone();
16932        let current_show = TabBarSettings::get_global(cx).show;
16933        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16934            setting.show = Some(!current_show);
16935        });
16936    }
16937
16938    pub fn toggle_indent_guides(
16939        &mut self,
16940        _: &ToggleIndentGuides,
16941        _: &mut Window,
16942        cx: &mut Context<Self>,
16943    ) {
16944        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16945            self.buffer
16946                .read(cx)
16947                .language_settings(cx)
16948                .indent_guides
16949                .enabled
16950        });
16951        self.show_indent_guides = Some(!currently_enabled);
16952        cx.notify();
16953    }
16954
16955    fn should_show_indent_guides(&self) -> Option<bool> {
16956        self.show_indent_guides
16957    }
16958
16959    pub fn toggle_line_numbers(
16960        &mut self,
16961        _: &ToggleLineNumbers,
16962        _: &mut Window,
16963        cx: &mut Context<Self>,
16964    ) {
16965        let mut editor_settings = EditorSettings::get_global(cx).clone();
16966        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16967        EditorSettings::override_global(editor_settings, cx);
16968    }
16969
16970    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16971        if let Some(show_line_numbers) = self.show_line_numbers {
16972            return show_line_numbers;
16973        }
16974        EditorSettings::get_global(cx).gutter.line_numbers
16975    }
16976
16977    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16978        self.use_relative_line_numbers
16979            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16980    }
16981
16982    pub fn toggle_relative_line_numbers(
16983        &mut self,
16984        _: &ToggleRelativeLineNumbers,
16985        _: &mut Window,
16986        cx: &mut Context<Self>,
16987    ) {
16988        let is_relative = self.should_use_relative_line_numbers(cx);
16989        self.set_relative_line_number(Some(!is_relative), cx)
16990    }
16991
16992    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16993        self.use_relative_line_numbers = is_relative;
16994        cx.notify();
16995    }
16996
16997    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16998        self.show_gutter = show_gutter;
16999        cx.notify();
17000    }
17001
17002    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
17003        self.show_scrollbars = show_scrollbars;
17004        cx.notify();
17005    }
17006
17007    pub fn set_minimap_visibility(
17008        &mut self,
17009        minimap_visibility: MinimapVisibility,
17010        window: &mut Window,
17011        cx: &mut Context<Self>,
17012    ) {
17013        if self.minimap_visibility != minimap_visibility {
17014            if minimap_visibility.visible() && self.minimap.is_none() {
17015                let minimap_settings = EditorSettings::get_global(cx).minimap;
17016                self.minimap =
17017                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17018            }
17019            self.minimap_visibility = minimap_visibility;
17020            cx.notify();
17021        }
17022    }
17023
17024    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17025        self.set_show_scrollbars(false, cx);
17026        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17027    }
17028
17029    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17030        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17031    }
17032
17033    /// Normally the text in full mode and auto height editors is padded on the
17034    /// left side by roughly half a character width for improved hit testing.
17035    ///
17036    /// Use this method to disable this for cases where this is not wanted (e.g.
17037    /// if you want to align the editor text with some other text above or below)
17038    /// or if you want to add this padding to single-line editors.
17039    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17040        self.offset_content = offset_content;
17041        cx.notify();
17042    }
17043
17044    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17045        self.show_line_numbers = Some(show_line_numbers);
17046        cx.notify();
17047    }
17048
17049    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17050        self.disable_expand_excerpt_buttons = true;
17051        cx.notify();
17052    }
17053
17054    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17055        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17056        cx.notify();
17057    }
17058
17059    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17060        self.show_code_actions = Some(show_code_actions);
17061        cx.notify();
17062    }
17063
17064    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17065        self.show_runnables = Some(show_runnables);
17066        cx.notify();
17067    }
17068
17069    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17070        self.show_breakpoints = Some(show_breakpoints);
17071        cx.notify();
17072    }
17073
17074    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17075        if self.display_map.read(cx).masked != masked {
17076            self.display_map.update(cx, |map, _| map.masked = masked);
17077        }
17078        cx.notify()
17079    }
17080
17081    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17082        self.show_wrap_guides = Some(show_wrap_guides);
17083        cx.notify();
17084    }
17085
17086    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17087        self.show_indent_guides = Some(show_indent_guides);
17088        cx.notify();
17089    }
17090
17091    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17092        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17093            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17094                if let Some(dir) = file.abs_path(cx).parent() {
17095                    return Some(dir.to_owned());
17096                }
17097            }
17098
17099            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17100                return Some(project_path.path.to_path_buf());
17101            }
17102        }
17103
17104        None
17105    }
17106
17107    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17108        self.active_excerpt(cx)?
17109            .1
17110            .read(cx)
17111            .file()
17112            .and_then(|f| f.as_local())
17113    }
17114
17115    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17116        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17117            let buffer = buffer.read(cx);
17118            if let Some(project_path) = buffer.project_path(cx) {
17119                let project = self.project.as_ref()?.read(cx);
17120                project.absolute_path(&project_path, cx)
17121            } else {
17122                buffer
17123                    .file()
17124                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17125            }
17126        })
17127    }
17128
17129    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17130        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17131            let project_path = buffer.read(cx).project_path(cx)?;
17132            let project = self.project.as_ref()?.read(cx);
17133            let entry = project.entry_for_path(&project_path, cx)?;
17134            let path = entry.path.to_path_buf();
17135            Some(path)
17136        })
17137    }
17138
17139    pub fn reveal_in_finder(
17140        &mut self,
17141        _: &RevealInFileManager,
17142        _window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) {
17145        if let Some(target) = self.target_file(cx) {
17146            cx.reveal_path(&target.abs_path(cx));
17147        }
17148    }
17149
17150    pub fn copy_path(
17151        &mut self,
17152        _: &zed_actions::workspace::CopyPath,
17153        _window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        if let Some(path) = self.target_file_abs_path(cx) {
17157            if let Some(path) = path.to_str() {
17158                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17159            }
17160        }
17161    }
17162
17163    pub fn copy_relative_path(
17164        &mut self,
17165        _: &zed_actions::workspace::CopyRelativePath,
17166        _window: &mut Window,
17167        cx: &mut Context<Self>,
17168    ) {
17169        if let Some(path) = self.target_file_path(cx) {
17170            if let Some(path) = path.to_str() {
17171                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17172            }
17173        }
17174    }
17175
17176    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17177        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17178            buffer.read(cx).project_path(cx)
17179        } else {
17180            None
17181        }
17182    }
17183
17184    // Returns true if the editor handled a go-to-line request
17185    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17186        maybe!({
17187            let breakpoint_store = self.breakpoint_store.as_ref()?;
17188
17189            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17190            else {
17191                self.clear_row_highlights::<ActiveDebugLine>();
17192                return None;
17193            };
17194
17195            let position = active_stack_frame.position;
17196            let buffer_id = position.buffer_id?;
17197            let snapshot = self
17198                .project
17199                .as_ref()?
17200                .read(cx)
17201                .buffer_for_id(buffer_id, cx)?
17202                .read(cx)
17203                .snapshot();
17204
17205            let mut handled = false;
17206            for (id, ExcerptRange { context, .. }) in
17207                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17208            {
17209                if context.start.cmp(&position, &snapshot).is_ge()
17210                    || context.end.cmp(&position, &snapshot).is_lt()
17211                {
17212                    continue;
17213                }
17214                let snapshot = self.buffer.read(cx).snapshot(cx);
17215                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17216
17217                handled = true;
17218                self.clear_row_highlights::<ActiveDebugLine>();
17219
17220                self.go_to_line::<ActiveDebugLine>(
17221                    multibuffer_anchor,
17222                    Some(cx.theme().colors().editor_debugger_active_line_background),
17223                    window,
17224                    cx,
17225                );
17226
17227                cx.notify();
17228            }
17229
17230            handled.then_some(())
17231        })
17232        .is_some()
17233    }
17234
17235    pub fn copy_file_name_without_extension(
17236        &mut self,
17237        _: &CopyFileNameWithoutExtension,
17238        _: &mut Window,
17239        cx: &mut Context<Self>,
17240    ) {
17241        if let Some(file) = self.target_file(cx) {
17242            if let Some(file_stem) = file.path().file_stem() {
17243                if let Some(name) = file_stem.to_str() {
17244                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17245                }
17246            }
17247        }
17248    }
17249
17250    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17251        if let Some(file) = self.target_file(cx) {
17252            if let Some(file_name) = file.path().file_name() {
17253                if let Some(name) = file_name.to_str() {
17254                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17255                }
17256            }
17257        }
17258    }
17259
17260    pub fn toggle_git_blame(
17261        &mut self,
17262        _: &::git::Blame,
17263        window: &mut Window,
17264        cx: &mut Context<Self>,
17265    ) {
17266        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17267
17268        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17269            self.start_git_blame(true, window, cx);
17270        }
17271
17272        cx.notify();
17273    }
17274
17275    pub fn toggle_git_blame_inline(
17276        &mut self,
17277        _: &ToggleGitBlameInline,
17278        window: &mut Window,
17279        cx: &mut Context<Self>,
17280    ) {
17281        self.toggle_git_blame_inline_internal(true, window, cx);
17282        cx.notify();
17283    }
17284
17285    pub fn open_git_blame_commit(
17286        &mut self,
17287        _: &OpenGitBlameCommit,
17288        window: &mut Window,
17289        cx: &mut Context<Self>,
17290    ) {
17291        self.open_git_blame_commit_internal(window, cx);
17292    }
17293
17294    fn open_git_blame_commit_internal(
17295        &mut self,
17296        window: &mut Window,
17297        cx: &mut Context<Self>,
17298    ) -> Option<()> {
17299        let blame = self.blame.as_ref()?;
17300        let snapshot = self.snapshot(window, cx);
17301        let cursor = self.selections.newest::<Point>(cx).head();
17302        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17303        let blame_entry = blame
17304            .update(cx, |blame, cx| {
17305                blame
17306                    .blame_for_rows(
17307                        &[RowInfo {
17308                            buffer_id: Some(buffer.remote_id()),
17309                            buffer_row: Some(point.row),
17310                            ..Default::default()
17311                        }],
17312                        cx,
17313                    )
17314                    .next()
17315            })
17316            .flatten()?;
17317        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17318        let repo = blame.read(cx).repository(cx)?;
17319        let workspace = self.workspace()?.downgrade();
17320        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17321        None
17322    }
17323
17324    pub fn git_blame_inline_enabled(&self) -> bool {
17325        self.git_blame_inline_enabled
17326    }
17327
17328    pub fn toggle_selection_menu(
17329        &mut self,
17330        _: &ToggleSelectionMenu,
17331        _: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) {
17334        self.show_selection_menu = self
17335            .show_selection_menu
17336            .map(|show_selections_menu| !show_selections_menu)
17337            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17338
17339        cx.notify();
17340    }
17341
17342    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17343        self.show_selection_menu
17344            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17345    }
17346
17347    fn start_git_blame(
17348        &mut self,
17349        user_triggered: bool,
17350        window: &mut Window,
17351        cx: &mut Context<Self>,
17352    ) {
17353        if let Some(project) = self.project.as_ref() {
17354            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17355                return;
17356            };
17357
17358            if buffer.read(cx).file().is_none() {
17359                return;
17360            }
17361
17362            let focused = self.focus_handle(cx).contains_focused(window, cx);
17363
17364            let project = project.clone();
17365            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17366            self.blame_subscription =
17367                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17368            self.blame = Some(blame);
17369        }
17370    }
17371
17372    fn toggle_git_blame_inline_internal(
17373        &mut self,
17374        user_triggered: bool,
17375        window: &mut Window,
17376        cx: &mut Context<Self>,
17377    ) {
17378        if self.git_blame_inline_enabled {
17379            self.git_blame_inline_enabled = false;
17380            self.show_git_blame_inline = false;
17381            self.show_git_blame_inline_delay_task.take();
17382        } else {
17383            self.git_blame_inline_enabled = true;
17384            self.start_git_blame_inline(user_triggered, window, cx);
17385        }
17386
17387        cx.notify();
17388    }
17389
17390    fn start_git_blame_inline(
17391        &mut self,
17392        user_triggered: bool,
17393        window: &mut Window,
17394        cx: &mut Context<Self>,
17395    ) {
17396        self.start_git_blame(user_triggered, window, cx);
17397
17398        if ProjectSettings::get_global(cx)
17399            .git
17400            .inline_blame_delay()
17401            .is_some()
17402        {
17403            self.start_inline_blame_timer(window, cx);
17404        } else {
17405            self.show_git_blame_inline = true
17406        }
17407    }
17408
17409    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17410        self.blame.as_ref()
17411    }
17412
17413    pub fn show_git_blame_gutter(&self) -> bool {
17414        self.show_git_blame_gutter
17415    }
17416
17417    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17418        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17419    }
17420
17421    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17422        self.show_git_blame_inline
17423            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17424            && !self.newest_selection_head_on_empty_line(cx)
17425            && self.has_blame_entries(cx)
17426    }
17427
17428    fn has_blame_entries(&self, cx: &App) -> bool {
17429        self.blame()
17430            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17431    }
17432
17433    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17434        let cursor_anchor = self.selections.newest_anchor().head();
17435
17436        let snapshot = self.buffer.read(cx).snapshot(cx);
17437        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17438
17439        snapshot.line_len(buffer_row) == 0
17440    }
17441
17442    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17443        let buffer_and_selection = maybe!({
17444            let selection = self.selections.newest::<Point>(cx);
17445            let selection_range = selection.range();
17446
17447            let multi_buffer = self.buffer().read(cx);
17448            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17449            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17450
17451            let (buffer, range, _) = if selection.reversed {
17452                buffer_ranges.first()
17453            } else {
17454                buffer_ranges.last()
17455            }?;
17456
17457            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17458                ..text::ToPoint::to_point(&range.end, &buffer).row;
17459            Some((
17460                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17461                selection,
17462            ))
17463        });
17464
17465        let Some((buffer, selection)) = buffer_and_selection else {
17466            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17467        };
17468
17469        let Some(project) = self.project.as_ref() else {
17470            return Task::ready(Err(anyhow!("editor does not have project")));
17471        };
17472
17473        project.update(cx, |project, cx| {
17474            project.get_permalink_to_line(&buffer, selection, cx)
17475        })
17476    }
17477
17478    pub fn copy_permalink_to_line(
17479        &mut self,
17480        _: &CopyPermalinkToLine,
17481        window: &mut Window,
17482        cx: &mut Context<Self>,
17483    ) {
17484        let permalink_task = self.get_permalink_to_line(cx);
17485        let workspace = self.workspace();
17486
17487        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17488            Ok(permalink) => {
17489                cx.update(|_, cx| {
17490                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17491                })
17492                .ok();
17493            }
17494            Err(err) => {
17495                let message = format!("Failed to copy permalink: {err}");
17496
17497                anyhow::Result::<()>::Err(err).log_err();
17498
17499                if let Some(workspace) = workspace {
17500                    workspace
17501                        .update_in(cx, |workspace, _, cx| {
17502                            struct CopyPermalinkToLine;
17503
17504                            workspace.show_toast(
17505                                Toast::new(
17506                                    NotificationId::unique::<CopyPermalinkToLine>(),
17507                                    message,
17508                                ),
17509                                cx,
17510                            )
17511                        })
17512                        .ok();
17513                }
17514            }
17515        })
17516        .detach();
17517    }
17518
17519    pub fn copy_file_location(
17520        &mut self,
17521        _: &CopyFileLocation,
17522        _: &mut Window,
17523        cx: &mut Context<Self>,
17524    ) {
17525        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17526        if let Some(file) = self.target_file(cx) {
17527            if let Some(path) = file.path().to_str() {
17528                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17529            }
17530        }
17531    }
17532
17533    pub fn open_permalink_to_line(
17534        &mut self,
17535        _: &OpenPermalinkToLine,
17536        window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) {
17539        let permalink_task = self.get_permalink_to_line(cx);
17540        let workspace = self.workspace();
17541
17542        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17543            Ok(permalink) => {
17544                cx.update(|_, cx| {
17545                    cx.open_url(permalink.as_ref());
17546                })
17547                .ok();
17548            }
17549            Err(err) => {
17550                let message = format!("Failed to open permalink: {err}");
17551
17552                anyhow::Result::<()>::Err(err).log_err();
17553
17554                if let Some(workspace) = workspace {
17555                    workspace
17556                        .update(cx, |workspace, cx| {
17557                            struct OpenPermalinkToLine;
17558
17559                            workspace.show_toast(
17560                                Toast::new(
17561                                    NotificationId::unique::<OpenPermalinkToLine>(),
17562                                    message,
17563                                ),
17564                                cx,
17565                            )
17566                        })
17567                        .ok();
17568                }
17569            }
17570        })
17571        .detach();
17572    }
17573
17574    pub fn insert_uuid_v4(
17575        &mut self,
17576        _: &InsertUuidV4,
17577        window: &mut Window,
17578        cx: &mut Context<Self>,
17579    ) {
17580        self.insert_uuid(UuidVersion::V4, window, cx);
17581    }
17582
17583    pub fn insert_uuid_v7(
17584        &mut self,
17585        _: &InsertUuidV7,
17586        window: &mut Window,
17587        cx: &mut Context<Self>,
17588    ) {
17589        self.insert_uuid(UuidVersion::V7, window, cx);
17590    }
17591
17592    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17593        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17594        self.transact(window, cx, |this, window, cx| {
17595            let edits = this
17596                .selections
17597                .all::<Point>(cx)
17598                .into_iter()
17599                .map(|selection| {
17600                    let uuid = match version {
17601                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17602                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17603                    };
17604
17605                    (selection.range(), uuid.to_string())
17606                });
17607            this.edit(edits, cx);
17608            this.refresh_inline_completion(true, false, window, cx);
17609        });
17610    }
17611
17612    pub fn open_selections_in_multibuffer(
17613        &mut self,
17614        _: &OpenSelectionsInMultibuffer,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        let multibuffer = self.buffer.read(cx);
17619
17620        let Some(buffer) = multibuffer.as_singleton() else {
17621            return;
17622        };
17623
17624        let Some(workspace) = self.workspace() else {
17625            return;
17626        };
17627
17628        let locations = self
17629            .selections
17630            .disjoint_anchors()
17631            .iter()
17632            .map(|selection| {
17633                let range = if selection.reversed {
17634                    selection.end.text_anchor..selection.start.text_anchor
17635                } else {
17636                    selection.start.text_anchor..selection.end.text_anchor
17637                };
17638                Location {
17639                    buffer: buffer.clone(),
17640                    range,
17641                }
17642            })
17643            .collect::<Vec<_>>();
17644
17645        let title = multibuffer.title(cx).to_string();
17646
17647        cx.spawn_in(window, async move |_, cx| {
17648            workspace.update_in(cx, |workspace, window, cx| {
17649                Self::open_locations_in_multibuffer(
17650                    workspace,
17651                    locations,
17652                    format!("Selections for '{title}'"),
17653                    false,
17654                    MultibufferSelectionMode::All,
17655                    window,
17656                    cx,
17657                );
17658            })
17659        })
17660        .detach();
17661    }
17662
17663    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17664    /// last highlight added will be used.
17665    ///
17666    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17667    pub fn highlight_rows<T: 'static>(
17668        &mut self,
17669        range: Range<Anchor>,
17670        color: Hsla,
17671        options: RowHighlightOptions,
17672        cx: &mut Context<Self>,
17673    ) {
17674        let snapshot = self.buffer().read(cx).snapshot(cx);
17675        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17676        let ix = row_highlights.binary_search_by(|highlight| {
17677            Ordering::Equal
17678                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17679                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17680        });
17681
17682        if let Err(mut ix) = ix {
17683            let index = post_inc(&mut self.highlight_order);
17684
17685            // If this range intersects with the preceding highlight, then merge it with
17686            // the preceding highlight. Otherwise insert a new highlight.
17687            let mut merged = false;
17688            if ix > 0 {
17689                let prev_highlight = &mut row_highlights[ix - 1];
17690                if prev_highlight
17691                    .range
17692                    .end
17693                    .cmp(&range.start, &snapshot)
17694                    .is_ge()
17695                {
17696                    ix -= 1;
17697                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17698                        prev_highlight.range.end = range.end;
17699                    }
17700                    merged = true;
17701                    prev_highlight.index = index;
17702                    prev_highlight.color = color;
17703                    prev_highlight.options = options;
17704                }
17705            }
17706
17707            if !merged {
17708                row_highlights.insert(
17709                    ix,
17710                    RowHighlight {
17711                        range: range.clone(),
17712                        index,
17713                        color,
17714                        options,
17715                        type_id: TypeId::of::<T>(),
17716                    },
17717                );
17718            }
17719
17720            // If any of the following highlights intersect with this one, merge them.
17721            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17722                let highlight = &row_highlights[ix];
17723                if next_highlight
17724                    .range
17725                    .start
17726                    .cmp(&highlight.range.end, &snapshot)
17727                    .is_le()
17728                {
17729                    if next_highlight
17730                        .range
17731                        .end
17732                        .cmp(&highlight.range.end, &snapshot)
17733                        .is_gt()
17734                    {
17735                        row_highlights[ix].range.end = next_highlight.range.end;
17736                    }
17737                    row_highlights.remove(ix + 1);
17738                } else {
17739                    break;
17740                }
17741            }
17742        }
17743    }
17744
17745    /// Remove any highlighted row ranges of the given type that intersect the
17746    /// given ranges.
17747    pub fn remove_highlighted_rows<T: 'static>(
17748        &mut self,
17749        ranges_to_remove: Vec<Range<Anchor>>,
17750        cx: &mut Context<Self>,
17751    ) {
17752        let snapshot = self.buffer().read(cx).snapshot(cx);
17753        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17754        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17755        row_highlights.retain(|highlight| {
17756            while let Some(range_to_remove) = ranges_to_remove.peek() {
17757                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17758                    Ordering::Less | Ordering::Equal => {
17759                        ranges_to_remove.next();
17760                    }
17761                    Ordering::Greater => {
17762                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17763                            Ordering::Less | Ordering::Equal => {
17764                                return false;
17765                            }
17766                            Ordering::Greater => break,
17767                        }
17768                    }
17769                }
17770            }
17771
17772            true
17773        })
17774    }
17775
17776    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17777    pub fn clear_row_highlights<T: 'static>(&mut self) {
17778        self.highlighted_rows.remove(&TypeId::of::<T>());
17779    }
17780
17781    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17782    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17783        self.highlighted_rows
17784            .get(&TypeId::of::<T>())
17785            .map_or(&[] as &[_], |vec| vec.as_slice())
17786            .iter()
17787            .map(|highlight| (highlight.range.clone(), highlight.color))
17788    }
17789
17790    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17791    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17792    /// Allows to ignore certain kinds of highlights.
17793    pub fn highlighted_display_rows(
17794        &self,
17795        window: &mut Window,
17796        cx: &mut App,
17797    ) -> BTreeMap<DisplayRow, LineHighlight> {
17798        let snapshot = self.snapshot(window, cx);
17799        let mut used_highlight_orders = HashMap::default();
17800        self.highlighted_rows
17801            .iter()
17802            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17803            .fold(
17804                BTreeMap::<DisplayRow, LineHighlight>::new(),
17805                |mut unique_rows, highlight| {
17806                    let start = highlight.range.start.to_display_point(&snapshot);
17807                    let end = highlight.range.end.to_display_point(&snapshot);
17808                    let start_row = start.row().0;
17809                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17810                        && end.column() == 0
17811                    {
17812                        end.row().0.saturating_sub(1)
17813                    } else {
17814                        end.row().0
17815                    };
17816                    for row in start_row..=end_row {
17817                        let used_index =
17818                            used_highlight_orders.entry(row).or_insert(highlight.index);
17819                        if highlight.index >= *used_index {
17820                            *used_index = highlight.index;
17821                            unique_rows.insert(
17822                                DisplayRow(row),
17823                                LineHighlight {
17824                                    include_gutter: highlight.options.include_gutter,
17825                                    border: None,
17826                                    background: highlight.color.into(),
17827                                    type_id: Some(highlight.type_id),
17828                                },
17829                            );
17830                        }
17831                    }
17832                    unique_rows
17833                },
17834            )
17835    }
17836
17837    pub fn highlighted_display_row_for_autoscroll(
17838        &self,
17839        snapshot: &DisplaySnapshot,
17840    ) -> Option<DisplayRow> {
17841        self.highlighted_rows
17842            .values()
17843            .flat_map(|highlighted_rows| highlighted_rows.iter())
17844            .filter_map(|highlight| {
17845                if highlight.options.autoscroll {
17846                    Some(highlight.range.start.to_display_point(snapshot).row())
17847                } else {
17848                    None
17849                }
17850            })
17851            .min()
17852    }
17853
17854    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17855        self.highlight_background::<SearchWithinRange>(
17856            ranges,
17857            |colors| colors.editor_document_highlight_read_background,
17858            cx,
17859        )
17860    }
17861
17862    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17863        self.breadcrumb_header = Some(new_header);
17864    }
17865
17866    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17867        self.clear_background_highlights::<SearchWithinRange>(cx);
17868    }
17869
17870    pub fn highlight_background<T: 'static>(
17871        &mut self,
17872        ranges: &[Range<Anchor>],
17873        color_fetcher: fn(&ThemeColors) -> Hsla,
17874        cx: &mut Context<Self>,
17875    ) {
17876        self.background_highlights
17877            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17878        self.scrollbar_marker_state.dirty = true;
17879        cx.notify();
17880    }
17881
17882    pub fn clear_background_highlights<T: 'static>(
17883        &mut self,
17884        cx: &mut Context<Self>,
17885    ) -> Option<BackgroundHighlight> {
17886        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17887        if !text_highlights.1.is_empty() {
17888            self.scrollbar_marker_state.dirty = true;
17889            cx.notify();
17890        }
17891        Some(text_highlights)
17892    }
17893
17894    pub fn highlight_gutter<T: 'static>(
17895        &mut self,
17896        ranges: &[Range<Anchor>],
17897        color_fetcher: fn(&App) -> Hsla,
17898        cx: &mut Context<Self>,
17899    ) {
17900        self.gutter_highlights
17901            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17902        cx.notify();
17903    }
17904
17905    pub fn clear_gutter_highlights<T: 'static>(
17906        &mut self,
17907        cx: &mut Context<Self>,
17908    ) -> Option<GutterHighlight> {
17909        cx.notify();
17910        self.gutter_highlights.remove(&TypeId::of::<T>())
17911    }
17912
17913    #[cfg(feature = "test-support")]
17914    pub fn all_text_background_highlights(
17915        &self,
17916        window: &mut Window,
17917        cx: &mut Context<Self>,
17918    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17919        let snapshot = self.snapshot(window, cx);
17920        let buffer = &snapshot.buffer_snapshot;
17921        let start = buffer.anchor_before(0);
17922        let end = buffer.anchor_after(buffer.len());
17923        let theme = cx.theme().colors();
17924        self.background_highlights_in_range(start..end, &snapshot, theme)
17925    }
17926
17927    #[cfg(feature = "test-support")]
17928    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17929        let snapshot = self.buffer().read(cx).snapshot(cx);
17930
17931        let highlights = self
17932            .background_highlights
17933            .get(&TypeId::of::<items::BufferSearchHighlights>());
17934
17935        if let Some((_color, ranges)) = highlights {
17936            ranges
17937                .iter()
17938                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17939                .collect_vec()
17940        } else {
17941            vec![]
17942        }
17943    }
17944
17945    fn document_highlights_for_position<'a>(
17946        &'a self,
17947        position: Anchor,
17948        buffer: &'a MultiBufferSnapshot,
17949    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17950        let read_highlights = self
17951            .background_highlights
17952            .get(&TypeId::of::<DocumentHighlightRead>())
17953            .map(|h| &h.1);
17954        let write_highlights = self
17955            .background_highlights
17956            .get(&TypeId::of::<DocumentHighlightWrite>())
17957            .map(|h| &h.1);
17958        let left_position = position.bias_left(buffer);
17959        let right_position = position.bias_right(buffer);
17960        read_highlights
17961            .into_iter()
17962            .chain(write_highlights)
17963            .flat_map(move |ranges| {
17964                let start_ix = match ranges.binary_search_by(|probe| {
17965                    let cmp = probe.end.cmp(&left_position, buffer);
17966                    if cmp.is_ge() {
17967                        Ordering::Greater
17968                    } else {
17969                        Ordering::Less
17970                    }
17971                }) {
17972                    Ok(i) | Err(i) => i,
17973                };
17974
17975                ranges[start_ix..]
17976                    .iter()
17977                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17978            })
17979    }
17980
17981    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17982        self.background_highlights
17983            .get(&TypeId::of::<T>())
17984            .map_or(false, |(_, highlights)| !highlights.is_empty())
17985    }
17986
17987    pub fn background_highlights_in_range(
17988        &self,
17989        search_range: Range<Anchor>,
17990        display_snapshot: &DisplaySnapshot,
17991        theme: &ThemeColors,
17992    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17993        let mut results = Vec::new();
17994        for (color_fetcher, ranges) in self.background_highlights.values() {
17995            let color = color_fetcher(theme);
17996            let start_ix = match ranges.binary_search_by(|probe| {
17997                let cmp = probe
17998                    .end
17999                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18000                if cmp.is_gt() {
18001                    Ordering::Greater
18002                } else {
18003                    Ordering::Less
18004                }
18005            }) {
18006                Ok(i) | Err(i) => i,
18007            };
18008            for range in &ranges[start_ix..] {
18009                if range
18010                    .start
18011                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18012                    .is_ge()
18013                {
18014                    break;
18015                }
18016
18017                let start = range.start.to_display_point(display_snapshot);
18018                let end = range.end.to_display_point(display_snapshot);
18019                results.push((start..end, color))
18020            }
18021        }
18022        results
18023    }
18024
18025    pub fn background_highlight_row_ranges<T: 'static>(
18026        &self,
18027        search_range: Range<Anchor>,
18028        display_snapshot: &DisplaySnapshot,
18029        count: usize,
18030    ) -> Vec<RangeInclusive<DisplayPoint>> {
18031        let mut results = Vec::new();
18032        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18033            return vec![];
18034        };
18035
18036        let start_ix = match ranges.binary_search_by(|probe| {
18037            let cmp = probe
18038                .end
18039                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18040            if cmp.is_gt() {
18041                Ordering::Greater
18042            } else {
18043                Ordering::Less
18044            }
18045        }) {
18046            Ok(i) | Err(i) => i,
18047        };
18048        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18049            if let (Some(start_display), Some(end_display)) = (start, end) {
18050                results.push(
18051                    start_display.to_display_point(display_snapshot)
18052                        ..=end_display.to_display_point(display_snapshot),
18053                );
18054            }
18055        };
18056        let mut start_row: Option<Point> = None;
18057        let mut end_row: Option<Point> = None;
18058        if ranges.len() > count {
18059            return Vec::new();
18060        }
18061        for range in &ranges[start_ix..] {
18062            if range
18063                .start
18064                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18065                .is_ge()
18066            {
18067                break;
18068            }
18069            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18070            if let Some(current_row) = &end_row {
18071                if end.row == current_row.row {
18072                    continue;
18073                }
18074            }
18075            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18076            if start_row.is_none() {
18077                assert_eq!(end_row, None);
18078                start_row = Some(start);
18079                end_row = Some(end);
18080                continue;
18081            }
18082            if let Some(current_end) = end_row.as_mut() {
18083                if start.row > current_end.row + 1 {
18084                    push_region(start_row, end_row);
18085                    start_row = Some(start);
18086                    end_row = Some(end);
18087                } else {
18088                    // Merge two hunks.
18089                    *current_end = end;
18090                }
18091            } else {
18092                unreachable!();
18093            }
18094        }
18095        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18096        push_region(start_row, end_row);
18097        results
18098    }
18099
18100    pub fn gutter_highlights_in_range(
18101        &self,
18102        search_range: Range<Anchor>,
18103        display_snapshot: &DisplaySnapshot,
18104        cx: &App,
18105    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18106        let mut results = Vec::new();
18107        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18108            let color = color_fetcher(cx);
18109            let start_ix = match ranges.binary_search_by(|probe| {
18110                let cmp = probe
18111                    .end
18112                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18113                if cmp.is_gt() {
18114                    Ordering::Greater
18115                } else {
18116                    Ordering::Less
18117                }
18118            }) {
18119                Ok(i) | Err(i) => i,
18120            };
18121            for range in &ranges[start_ix..] {
18122                if range
18123                    .start
18124                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18125                    .is_ge()
18126                {
18127                    break;
18128                }
18129
18130                let start = range.start.to_display_point(display_snapshot);
18131                let end = range.end.to_display_point(display_snapshot);
18132                results.push((start..end, color))
18133            }
18134        }
18135        results
18136    }
18137
18138    /// Get the text ranges corresponding to the redaction query
18139    pub fn redacted_ranges(
18140        &self,
18141        search_range: Range<Anchor>,
18142        display_snapshot: &DisplaySnapshot,
18143        cx: &App,
18144    ) -> Vec<Range<DisplayPoint>> {
18145        display_snapshot
18146            .buffer_snapshot
18147            .redacted_ranges(search_range, |file| {
18148                if let Some(file) = file {
18149                    file.is_private()
18150                        && EditorSettings::get(
18151                            Some(SettingsLocation {
18152                                worktree_id: file.worktree_id(cx),
18153                                path: file.path().as_ref(),
18154                            }),
18155                            cx,
18156                        )
18157                        .redact_private_values
18158                } else {
18159                    false
18160                }
18161            })
18162            .map(|range| {
18163                range.start.to_display_point(display_snapshot)
18164                    ..range.end.to_display_point(display_snapshot)
18165            })
18166            .collect()
18167    }
18168
18169    pub fn highlight_text<T: 'static>(
18170        &mut self,
18171        ranges: Vec<Range<Anchor>>,
18172        style: HighlightStyle,
18173        cx: &mut Context<Self>,
18174    ) {
18175        self.display_map.update(cx, |map, _| {
18176            map.highlight_text(TypeId::of::<T>(), ranges, style)
18177        });
18178        cx.notify();
18179    }
18180
18181    pub(crate) fn highlight_inlays<T: 'static>(
18182        &mut self,
18183        highlights: Vec<InlayHighlight>,
18184        style: HighlightStyle,
18185        cx: &mut Context<Self>,
18186    ) {
18187        self.display_map.update(cx, |map, _| {
18188            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18189        });
18190        cx.notify();
18191    }
18192
18193    pub fn text_highlights<'a, T: 'static>(
18194        &'a self,
18195        cx: &'a App,
18196    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18197        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18198    }
18199
18200    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18201        let cleared = self
18202            .display_map
18203            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18204        if cleared {
18205            cx.notify();
18206        }
18207    }
18208
18209    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18210        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18211            && self.focus_handle.is_focused(window)
18212    }
18213
18214    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18215        self.show_cursor_when_unfocused = is_enabled;
18216        cx.notify();
18217    }
18218
18219    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18220        cx.notify();
18221    }
18222
18223    fn on_debug_session_event(
18224        &mut self,
18225        _session: Entity<Session>,
18226        event: &SessionEvent,
18227        cx: &mut Context<Self>,
18228    ) {
18229        match event {
18230            SessionEvent::InvalidateInlineValue => {
18231                self.refresh_inline_values(cx);
18232            }
18233            _ => {}
18234        }
18235    }
18236
18237    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18238        let Some(project) = self.project.clone() else {
18239            return;
18240        };
18241
18242        if !self.inline_value_cache.enabled {
18243            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18244            self.splice_inlays(&inlays, Vec::new(), cx);
18245            return;
18246        }
18247
18248        let current_execution_position = self
18249            .highlighted_rows
18250            .get(&TypeId::of::<ActiveDebugLine>())
18251            .and_then(|lines| lines.last().map(|line| line.range.start));
18252
18253        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18254            let inline_values = editor
18255                .update(cx, |editor, cx| {
18256                    let Some(current_execution_position) = current_execution_position else {
18257                        return Some(Task::ready(Ok(Vec::new())));
18258                    };
18259
18260                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18261                        let snapshot = buffer.snapshot(cx);
18262
18263                        let excerpt = snapshot.excerpt_containing(
18264                            current_execution_position..current_execution_position,
18265                        )?;
18266
18267                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18268                    })?;
18269
18270                    let range =
18271                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18272
18273                    project.inline_values(buffer, range, cx)
18274                })
18275                .ok()
18276                .flatten()?
18277                .await
18278                .context("refreshing debugger inlays")
18279                .log_err()?;
18280
18281            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18282
18283            for (buffer_id, inline_value) in inline_values
18284                .into_iter()
18285                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18286            {
18287                buffer_inline_values
18288                    .entry(buffer_id)
18289                    .or_default()
18290                    .push(inline_value);
18291            }
18292
18293            editor
18294                .update(cx, |editor, cx| {
18295                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18296                    let mut new_inlays = Vec::default();
18297
18298                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18299                        let buffer_id = buffer_snapshot.remote_id();
18300                        buffer_inline_values
18301                            .get(&buffer_id)
18302                            .into_iter()
18303                            .flatten()
18304                            .for_each(|hint| {
18305                                let inlay = Inlay::debugger_hint(
18306                                    post_inc(&mut editor.next_inlay_id),
18307                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18308                                    hint.text(),
18309                                );
18310
18311                                new_inlays.push(inlay);
18312                            });
18313                    }
18314
18315                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18316                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18317
18318                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18319                })
18320                .ok()?;
18321            Some(())
18322        });
18323    }
18324
18325    fn on_buffer_event(
18326        &mut self,
18327        multibuffer: &Entity<MultiBuffer>,
18328        event: &multi_buffer::Event,
18329        window: &mut Window,
18330        cx: &mut Context<Self>,
18331    ) {
18332        match event {
18333            multi_buffer::Event::Edited {
18334                singleton_buffer_edited,
18335                edited_buffer: buffer_edited,
18336            } => {
18337                self.scrollbar_marker_state.dirty = true;
18338                self.active_indent_guides_state.dirty = true;
18339                self.refresh_active_diagnostics(cx);
18340                self.refresh_code_actions(window, cx);
18341                self.refresh_selected_text_highlights(true, window, cx);
18342                refresh_matching_bracket_highlights(self, window, cx);
18343                if self.has_active_inline_completion() {
18344                    self.update_visible_inline_completion(window, cx);
18345                }
18346                if let Some(buffer) = buffer_edited {
18347                    let buffer_id = buffer.read(cx).remote_id();
18348                    if !self.registered_buffers.contains_key(&buffer_id) {
18349                        if let Some(project) = self.project.as_ref() {
18350                            project.update(cx, |project, cx| {
18351                                self.registered_buffers.insert(
18352                                    buffer_id,
18353                                    project.register_buffer_with_language_servers(&buffer, cx),
18354                                );
18355                            })
18356                        }
18357                    }
18358                }
18359                cx.emit(EditorEvent::BufferEdited);
18360                cx.emit(SearchEvent::MatchesInvalidated);
18361                if *singleton_buffer_edited {
18362                    if let Some(project) = &self.project {
18363                        #[allow(clippy::mutable_key_type)]
18364                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18365                            multibuffer
18366                                .all_buffers()
18367                                .into_iter()
18368                                .filter_map(|buffer| {
18369                                    buffer.update(cx, |buffer, cx| {
18370                                        let language = buffer.language()?;
18371                                        let should_discard = project.update(cx, |project, cx| {
18372                                            project.is_local()
18373                                                && !project.has_language_servers_for(buffer, cx)
18374                                        });
18375                                        should_discard.not().then_some(language.clone())
18376                                    })
18377                                })
18378                                .collect::<HashSet<_>>()
18379                        });
18380                        if !languages_affected.is_empty() {
18381                            self.refresh_inlay_hints(
18382                                InlayHintRefreshReason::BufferEdited(languages_affected),
18383                                cx,
18384                            );
18385                        }
18386                    }
18387                }
18388
18389                let Some(project) = &self.project else { return };
18390                let (telemetry, is_via_ssh) = {
18391                    let project = project.read(cx);
18392                    let telemetry = project.client().telemetry().clone();
18393                    let is_via_ssh = project.is_via_ssh();
18394                    (telemetry, is_via_ssh)
18395                };
18396                refresh_linked_ranges(self, window, cx);
18397                telemetry.log_edit_event("editor", is_via_ssh);
18398            }
18399            multi_buffer::Event::ExcerptsAdded {
18400                buffer,
18401                predecessor,
18402                excerpts,
18403            } => {
18404                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18405                let buffer_id = buffer.read(cx).remote_id();
18406                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18407                    if let Some(project) = &self.project {
18408                        update_uncommitted_diff_for_buffer(
18409                            cx.entity(),
18410                            project,
18411                            [buffer.clone()],
18412                            self.buffer.clone(),
18413                            cx,
18414                        )
18415                        .detach();
18416                    }
18417                }
18418                cx.emit(EditorEvent::ExcerptsAdded {
18419                    buffer: buffer.clone(),
18420                    predecessor: *predecessor,
18421                    excerpts: excerpts.clone(),
18422                });
18423                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18424            }
18425            multi_buffer::Event::ExcerptsRemoved {
18426                ids,
18427                removed_buffer_ids,
18428            } => {
18429                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18430                let buffer = self.buffer.read(cx);
18431                self.registered_buffers
18432                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18433                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18434                cx.emit(EditorEvent::ExcerptsRemoved {
18435                    ids: ids.clone(),
18436                    removed_buffer_ids: removed_buffer_ids.clone(),
18437                })
18438            }
18439            multi_buffer::Event::ExcerptsEdited {
18440                excerpt_ids,
18441                buffer_ids,
18442            } => {
18443                self.display_map.update(cx, |map, cx| {
18444                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18445                });
18446                cx.emit(EditorEvent::ExcerptsEdited {
18447                    ids: excerpt_ids.clone(),
18448                })
18449            }
18450            multi_buffer::Event::ExcerptsExpanded { ids } => {
18451                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18452                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18453            }
18454            multi_buffer::Event::Reparsed(buffer_id) => {
18455                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18456                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18457
18458                cx.emit(EditorEvent::Reparsed(*buffer_id));
18459            }
18460            multi_buffer::Event::DiffHunksToggled => {
18461                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18462            }
18463            multi_buffer::Event::LanguageChanged(buffer_id) => {
18464                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18465                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18466                cx.emit(EditorEvent::Reparsed(*buffer_id));
18467                cx.notify();
18468            }
18469            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18470            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18471            multi_buffer::Event::FileHandleChanged
18472            | multi_buffer::Event::Reloaded
18473            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18474            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18475            multi_buffer::Event::DiagnosticsUpdated => {
18476                self.refresh_active_diagnostics(cx);
18477                self.refresh_inline_diagnostics(true, window, cx);
18478                self.scrollbar_marker_state.dirty = true;
18479                cx.notify();
18480            }
18481            _ => {}
18482        };
18483    }
18484
18485    pub fn start_temporary_diff_override(&mut self) {
18486        self.load_diff_task.take();
18487        self.temporary_diff_override = true;
18488    }
18489
18490    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18491        self.temporary_diff_override = false;
18492        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18493        self.buffer.update(cx, |buffer, cx| {
18494            buffer.set_all_diff_hunks_collapsed(cx);
18495        });
18496
18497        if let Some(project) = self.project.clone() {
18498            self.load_diff_task = Some(
18499                update_uncommitted_diff_for_buffer(
18500                    cx.entity(),
18501                    &project,
18502                    self.buffer.read(cx).all_buffers(),
18503                    self.buffer.clone(),
18504                    cx,
18505                )
18506                .shared(),
18507            );
18508        }
18509    }
18510
18511    fn on_display_map_changed(
18512        &mut self,
18513        _: Entity<DisplayMap>,
18514        _: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        cx.notify();
18518    }
18519
18520    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18521        let new_severity = if self.diagnostics_enabled() {
18522            EditorSettings::get_global(cx)
18523                .diagnostics_max_severity
18524                .unwrap_or(DiagnosticSeverity::Hint)
18525        } else {
18526            DiagnosticSeverity::Off
18527        };
18528        self.set_max_diagnostics_severity(new_severity, cx);
18529        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18530        self.update_edit_prediction_settings(cx);
18531        self.refresh_inline_completion(true, false, window, cx);
18532        self.refresh_inlay_hints(
18533            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18534                self.selections.newest_anchor().head(),
18535                &self.buffer.read(cx).snapshot(cx),
18536                cx,
18537            )),
18538            cx,
18539        );
18540
18541        let old_cursor_shape = self.cursor_shape;
18542
18543        {
18544            let editor_settings = EditorSettings::get_global(cx);
18545            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18546            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18547            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18548            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18549        }
18550
18551        if old_cursor_shape != self.cursor_shape {
18552            cx.emit(EditorEvent::CursorShapeChanged);
18553        }
18554
18555        let project_settings = ProjectSettings::get_global(cx);
18556        self.serialize_dirty_buffers =
18557            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18558
18559        if self.mode.is_full() {
18560            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18561            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18562            if self.show_inline_diagnostics != show_inline_diagnostics {
18563                self.show_inline_diagnostics = show_inline_diagnostics;
18564                self.refresh_inline_diagnostics(false, window, cx);
18565            }
18566
18567            if self.git_blame_inline_enabled != inline_blame_enabled {
18568                self.toggle_git_blame_inline_internal(false, window, cx);
18569            }
18570
18571            let minimap_settings = EditorSettings::get_global(cx).minimap;
18572            if self.minimap_visibility.settings_visibility() != minimap_settings.minimap_enabled() {
18573                self.set_minimap_visibility(
18574                    MinimapVisibility::for_mode(self.mode(), cx),
18575                    window,
18576                    cx,
18577                );
18578            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18579                minimap_entity.update(cx, |minimap_editor, cx| {
18580                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18581                })
18582            }
18583        }
18584
18585        cx.notify();
18586    }
18587
18588    pub fn set_searchable(&mut self, searchable: bool) {
18589        self.searchable = searchable;
18590    }
18591
18592    pub fn searchable(&self) -> bool {
18593        self.searchable
18594    }
18595
18596    fn open_proposed_changes_editor(
18597        &mut self,
18598        _: &OpenProposedChangesEditor,
18599        window: &mut Window,
18600        cx: &mut Context<Self>,
18601    ) {
18602        let Some(workspace) = self.workspace() else {
18603            cx.propagate();
18604            return;
18605        };
18606
18607        let selections = self.selections.all::<usize>(cx);
18608        let multi_buffer = self.buffer.read(cx);
18609        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18610        let mut new_selections_by_buffer = HashMap::default();
18611        for selection in selections {
18612            for (buffer, range, _) in
18613                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18614            {
18615                let mut range = range.to_point(buffer);
18616                range.start.column = 0;
18617                range.end.column = buffer.line_len(range.end.row);
18618                new_selections_by_buffer
18619                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18620                    .or_insert(Vec::new())
18621                    .push(range)
18622            }
18623        }
18624
18625        let proposed_changes_buffers = new_selections_by_buffer
18626            .into_iter()
18627            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18628            .collect::<Vec<_>>();
18629        let proposed_changes_editor = cx.new(|cx| {
18630            ProposedChangesEditor::new(
18631                "Proposed changes",
18632                proposed_changes_buffers,
18633                self.project.clone(),
18634                window,
18635                cx,
18636            )
18637        });
18638
18639        window.defer(cx, move |window, cx| {
18640            workspace.update(cx, |workspace, cx| {
18641                workspace.active_pane().update(cx, |pane, cx| {
18642                    pane.add_item(
18643                        Box::new(proposed_changes_editor),
18644                        true,
18645                        true,
18646                        None,
18647                        window,
18648                        cx,
18649                    );
18650                });
18651            });
18652        });
18653    }
18654
18655    pub fn open_excerpts_in_split(
18656        &mut self,
18657        _: &OpenExcerptsSplit,
18658        window: &mut Window,
18659        cx: &mut Context<Self>,
18660    ) {
18661        self.open_excerpts_common(None, true, window, cx)
18662    }
18663
18664    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18665        self.open_excerpts_common(None, false, window, cx)
18666    }
18667
18668    fn open_excerpts_common(
18669        &mut self,
18670        jump_data: Option<JumpData>,
18671        split: bool,
18672        window: &mut Window,
18673        cx: &mut Context<Self>,
18674    ) {
18675        let Some(workspace) = self.workspace() else {
18676            cx.propagate();
18677            return;
18678        };
18679
18680        if self.buffer.read(cx).is_singleton() {
18681            cx.propagate();
18682            return;
18683        }
18684
18685        let mut new_selections_by_buffer = HashMap::default();
18686        match &jump_data {
18687            Some(JumpData::MultiBufferPoint {
18688                excerpt_id,
18689                position,
18690                anchor,
18691                line_offset_from_top,
18692            }) => {
18693                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18694                if let Some(buffer) = multi_buffer_snapshot
18695                    .buffer_id_for_excerpt(*excerpt_id)
18696                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18697                {
18698                    let buffer_snapshot = buffer.read(cx).snapshot();
18699                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18700                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18701                    } else {
18702                        buffer_snapshot.clip_point(*position, Bias::Left)
18703                    };
18704                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18705                    new_selections_by_buffer.insert(
18706                        buffer,
18707                        (
18708                            vec![jump_to_offset..jump_to_offset],
18709                            Some(*line_offset_from_top),
18710                        ),
18711                    );
18712                }
18713            }
18714            Some(JumpData::MultiBufferRow {
18715                row,
18716                line_offset_from_top,
18717            }) => {
18718                let point = MultiBufferPoint::new(row.0, 0);
18719                if let Some((buffer, buffer_point, _)) =
18720                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18721                {
18722                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18723                    new_selections_by_buffer
18724                        .entry(buffer)
18725                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18726                        .0
18727                        .push(buffer_offset..buffer_offset)
18728                }
18729            }
18730            None => {
18731                let selections = self.selections.all::<usize>(cx);
18732                let multi_buffer = self.buffer.read(cx);
18733                for selection in selections {
18734                    for (snapshot, range, _, anchor) in multi_buffer
18735                        .snapshot(cx)
18736                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18737                    {
18738                        if let Some(anchor) = anchor {
18739                            // selection is in a deleted hunk
18740                            let Some(buffer_id) = anchor.buffer_id else {
18741                                continue;
18742                            };
18743                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18744                                continue;
18745                            };
18746                            let offset = text::ToOffset::to_offset(
18747                                &anchor.text_anchor,
18748                                &buffer_handle.read(cx).snapshot(),
18749                            );
18750                            let range = offset..offset;
18751                            new_selections_by_buffer
18752                                .entry(buffer_handle)
18753                                .or_insert((Vec::new(), None))
18754                                .0
18755                                .push(range)
18756                        } else {
18757                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18758                            else {
18759                                continue;
18760                            };
18761                            new_selections_by_buffer
18762                                .entry(buffer_handle)
18763                                .or_insert((Vec::new(), None))
18764                                .0
18765                                .push(range)
18766                        }
18767                    }
18768                }
18769            }
18770        }
18771
18772        new_selections_by_buffer
18773            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18774
18775        if new_selections_by_buffer.is_empty() {
18776            return;
18777        }
18778
18779        // We defer the pane interaction because we ourselves are a workspace item
18780        // and activating a new item causes the pane to call a method on us reentrantly,
18781        // which panics if we're on the stack.
18782        window.defer(cx, move |window, cx| {
18783            workspace.update(cx, |workspace, cx| {
18784                let pane = if split {
18785                    workspace.adjacent_pane(window, cx)
18786                } else {
18787                    workspace.active_pane().clone()
18788                };
18789
18790                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18791                    let editor = buffer
18792                        .read(cx)
18793                        .file()
18794                        .is_none()
18795                        .then(|| {
18796                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18797                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18798                            // Instead, we try to activate the existing editor in the pane first.
18799                            let (editor, pane_item_index) =
18800                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18801                                    let editor = item.downcast::<Editor>()?;
18802                                    let singleton_buffer =
18803                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18804                                    if singleton_buffer == buffer {
18805                                        Some((editor, i))
18806                                    } else {
18807                                        None
18808                                    }
18809                                })?;
18810                            pane.update(cx, |pane, cx| {
18811                                pane.activate_item(pane_item_index, true, true, window, cx)
18812                            });
18813                            Some(editor)
18814                        })
18815                        .flatten()
18816                        .unwrap_or_else(|| {
18817                            workspace.open_project_item::<Self>(
18818                                pane.clone(),
18819                                buffer,
18820                                true,
18821                                true,
18822                                window,
18823                                cx,
18824                            )
18825                        });
18826
18827                    editor.update(cx, |editor, cx| {
18828                        let autoscroll = match scroll_offset {
18829                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18830                            None => Autoscroll::newest(),
18831                        };
18832                        let nav_history = editor.nav_history.take();
18833                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18834                            s.select_ranges(ranges);
18835                        });
18836                        editor.nav_history = nav_history;
18837                    });
18838                }
18839            })
18840        });
18841    }
18842
18843    // For now, don't allow opening excerpts in buffers that aren't backed by
18844    // regular project files.
18845    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18846        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18847    }
18848
18849    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18850        let snapshot = self.buffer.read(cx).read(cx);
18851        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18852        Some(
18853            ranges
18854                .iter()
18855                .map(move |range| {
18856                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18857                })
18858                .collect(),
18859        )
18860    }
18861
18862    fn selection_replacement_ranges(
18863        &self,
18864        range: Range<OffsetUtf16>,
18865        cx: &mut App,
18866    ) -> Vec<Range<OffsetUtf16>> {
18867        let selections = self.selections.all::<OffsetUtf16>(cx);
18868        let newest_selection = selections
18869            .iter()
18870            .max_by_key(|selection| selection.id)
18871            .unwrap();
18872        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18873        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18874        let snapshot = self.buffer.read(cx).read(cx);
18875        selections
18876            .into_iter()
18877            .map(|mut selection| {
18878                selection.start.0 =
18879                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18880                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18881                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18882                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18883            })
18884            .collect()
18885    }
18886
18887    fn report_editor_event(
18888        &self,
18889        event_type: &'static str,
18890        file_extension: Option<String>,
18891        cx: &App,
18892    ) {
18893        if cfg!(any(test, feature = "test-support")) {
18894            return;
18895        }
18896
18897        let Some(project) = &self.project else { return };
18898
18899        // If None, we are in a file without an extension
18900        let file = self
18901            .buffer
18902            .read(cx)
18903            .as_singleton()
18904            .and_then(|b| b.read(cx).file());
18905        let file_extension = file_extension.or(file
18906            .as_ref()
18907            .and_then(|file| Path::new(file.file_name(cx)).extension())
18908            .and_then(|e| e.to_str())
18909            .map(|a| a.to_string()));
18910
18911        let vim_mode = vim_enabled(cx);
18912
18913        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18914        let copilot_enabled = edit_predictions_provider
18915            == language::language_settings::EditPredictionProvider::Copilot;
18916        let copilot_enabled_for_language = self
18917            .buffer
18918            .read(cx)
18919            .language_settings(cx)
18920            .show_edit_predictions;
18921
18922        let project = project.read(cx);
18923        telemetry::event!(
18924            event_type,
18925            file_extension,
18926            vim_mode,
18927            copilot_enabled,
18928            copilot_enabled_for_language,
18929            edit_predictions_provider,
18930            is_via_ssh = project.is_via_ssh(),
18931        );
18932    }
18933
18934    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18935    /// with each line being an array of {text, highlight} objects.
18936    fn copy_highlight_json(
18937        &mut self,
18938        _: &CopyHighlightJson,
18939        window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) {
18942        #[derive(Serialize)]
18943        struct Chunk<'a> {
18944            text: String,
18945            highlight: Option<&'a str>,
18946        }
18947
18948        let snapshot = self.buffer.read(cx).snapshot(cx);
18949        let range = self
18950            .selected_text_range(false, window, cx)
18951            .and_then(|selection| {
18952                if selection.range.is_empty() {
18953                    None
18954                } else {
18955                    Some(selection.range)
18956                }
18957            })
18958            .unwrap_or_else(|| 0..snapshot.len());
18959
18960        let chunks = snapshot.chunks(range, true);
18961        let mut lines = Vec::new();
18962        let mut line: VecDeque<Chunk> = VecDeque::new();
18963
18964        let Some(style) = self.style.as_ref() else {
18965            return;
18966        };
18967
18968        for chunk in chunks {
18969            let highlight = chunk
18970                .syntax_highlight_id
18971                .and_then(|id| id.name(&style.syntax));
18972            let mut chunk_lines = chunk.text.split('\n').peekable();
18973            while let Some(text) = chunk_lines.next() {
18974                let mut merged_with_last_token = false;
18975                if let Some(last_token) = line.back_mut() {
18976                    if last_token.highlight == highlight {
18977                        last_token.text.push_str(text);
18978                        merged_with_last_token = true;
18979                    }
18980                }
18981
18982                if !merged_with_last_token {
18983                    line.push_back(Chunk {
18984                        text: text.into(),
18985                        highlight,
18986                    });
18987                }
18988
18989                if chunk_lines.peek().is_some() {
18990                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18991                        line.pop_front();
18992                    }
18993                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18994                        line.pop_back();
18995                    }
18996
18997                    lines.push(mem::take(&mut line));
18998                }
18999            }
19000        }
19001
19002        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19003            return;
19004        };
19005        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19006    }
19007
19008    pub fn open_context_menu(
19009        &mut self,
19010        _: &OpenContextMenu,
19011        window: &mut Window,
19012        cx: &mut Context<Self>,
19013    ) {
19014        self.request_autoscroll(Autoscroll::newest(), cx);
19015        let position = self.selections.newest_display(cx).start;
19016        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19017    }
19018
19019    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19020        &self.inlay_hint_cache
19021    }
19022
19023    pub fn replay_insert_event(
19024        &mut self,
19025        text: &str,
19026        relative_utf16_range: Option<Range<isize>>,
19027        window: &mut Window,
19028        cx: &mut Context<Self>,
19029    ) {
19030        if !self.input_enabled {
19031            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19032            return;
19033        }
19034        if let Some(relative_utf16_range) = relative_utf16_range {
19035            let selections = self.selections.all::<OffsetUtf16>(cx);
19036            self.change_selections(None, window, cx, |s| {
19037                let new_ranges = selections.into_iter().map(|range| {
19038                    let start = OffsetUtf16(
19039                        range
19040                            .head()
19041                            .0
19042                            .saturating_add_signed(relative_utf16_range.start),
19043                    );
19044                    let end = OffsetUtf16(
19045                        range
19046                            .head()
19047                            .0
19048                            .saturating_add_signed(relative_utf16_range.end),
19049                    );
19050                    start..end
19051                });
19052                s.select_ranges(new_ranges);
19053            });
19054        }
19055
19056        self.handle_input(text, window, cx);
19057    }
19058
19059    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19060        let Some(provider) = self.semantics_provider.as_ref() else {
19061            return false;
19062        };
19063
19064        let mut supports = false;
19065        self.buffer().update(cx, |this, cx| {
19066            this.for_each_buffer(|buffer| {
19067                supports |= provider.supports_inlay_hints(buffer, cx);
19068            });
19069        });
19070
19071        supports
19072    }
19073
19074    pub fn is_focused(&self, window: &Window) -> bool {
19075        self.focus_handle.is_focused(window)
19076    }
19077
19078    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19079        cx.emit(EditorEvent::Focused);
19080
19081        if let Some(descendant) = self
19082            .last_focused_descendant
19083            .take()
19084            .and_then(|descendant| descendant.upgrade())
19085        {
19086            window.focus(&descendant);
19087        } else {
19088            if let Some(blame) = self.blame.as_ref() {
19089                blame.update(cx, GitBlame::focus)
19090            }
19091
19092            self.blink_manager.update(cx, BlinkManager::enable);
19093            self.show_cursor_names(window, cx);
19094            self.buffer.update(cx, |buffer, cx| {
19095                buffer.finalize_last_transaction(cx);
19096                if self.leader_id.is_none() {
19097                    buffer.set_active_selections(
19098                        &self.selections.disjoint_anchors(),
19099                        self.selections.line_mode,
19100                        self.cursor_shape,
19101                        cx,
19102                    );
19103                }
19104            });
19105        }
19106    }
19107
19108    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19109        cx.emit(EditorEvent::FocusedIn)
19110    }
19111
19112    fn handle_focus_out(
19113        &mut self,
19114        event: FocusOutEvent,
19115        _window: &mut Window,
19116        cx: &mut Context<Self>,
19117    ) {
19118        if event.blurred != self.focus_handle {
19119            self.last_focused_descendant = Some(event.blurred);
19120        }
19121        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19122    }
19123
19124    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19125        self.blink_manager.update(cx, BlinkManager::disable);
19126        self.buffer
19127            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19128
19129        if let Some(blame) = self.blame.as_ref() {
19130            blame.update(cx, GitBlame::blur)
19131        }
19132        if !self.hover_state.focused(window, cx) {
19133            hide_hover(self, cx);
19134        }
19135        if !self
19136            .context_menu
19137            .borrow()
19138            .as_ref()
19139            .is_some_and(|context_menu| context_menu.focused(window, cx))
19140        {
19141            self.hide_context_menu(window, cx);
19142        }
19143        self.discard_inline_completion(false, cx);
19144        cx.emit(EditorEvent::Blurred);
19145        cx.notify();
19146    }
19147
19148    pub fn register_action<A: Action>(
19149        &mut self,
19150        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19151    ) -> Subscription {
19152        let id = self.next_editor_action_id.post_inc();
19153        let listener = Arc::new(listener);
19154        self.editor_actions.borrow_mut().insert(
19155            id,
19156            Box::new(move |window, _| {
19157                let listener = listener.clone();
19158                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19159                    let action = action.downcast_ref().unwrap();
19160                    if phase == DispatchPhase::Bubble {
19161                        listener(action, window, cx)
19162                    }
19163                })
19164            }),
19165        );
19166
19167        let editor_actions = self.editor_actions.clone();
19168        Subscription::new(move || {
19169            editor_actions.borrow_mut().remove(&id);
19170        })
19171    }
19172
19173    pub fn file_header_size(&self) -> u32 {
19174        FILE_HEADER_HEIGHT
19175    }
19176
19177    pub fn restore(
19178        &mut self,
19179        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19180        window: &mut Window,
19181        cx: &mut Context<Self>,
19182    ) {
19183        let workspace = self.workspace();
19184        let project = self.project.as_ref();
19185        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19186            let mut tasks = Vec::new();
19187            for (buffer_id, changes) in revert_changes {
19188                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19189                    buffer.update(cx, |buffer, cx| {
19190                        buffer.edit(
19191                            changes
19192                                .into_iter()
19193                                .map(|(range, text)| (range, text.to_string())),
19194                            None,
19195                            cx,
19196                        );
19197                    });
19198
19199                    if let Some(project) =
19200                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19201                    {
19202                        project.update(cx, |project, cx| {
19203                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19204                        })
19205                    }
19206                }
19207            }
19208            tasks
19209        });
19210        cx.spawn_in(window, async move |_, cx| {
19211            for (buffer, task) in save_tasks {
19212                let result = task.await;
19213                if result.is_err() {
19214                    let Some(path) = buffer
19215                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19216                        .ok()
19217                    else {
19218                        continue;
19219                    };
19220                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19221                        let Some(task) = cx
19222                            .update_window_entity(&workspace, |workspace, window, cx| {
19223                                workspace
19224                                    .open_path_preview(path, None, false, false, false, window, cx)
19225                            })
19226                            .ok()
19227                        else {
19228                            continue;
19229                        };
19230                        task.await.log_err();
19231                    }
19232                }
19233            }
19234        })
19235        .detach();
19236        self.change_selections(None, window, cx, |selections| selections.refresh());
19237    }
19238
19239    pub fn to_pixel_point(
19240        &self,
19241        source: multi_buffer::Anchor,
19242        editor_snapshot: &EditorSnapshot,
19243        window: &mut Window,
19244    ) -> Option<gpui::Point<Pixels>> {
19245        let source_point = source.to_display_point(editor_snapshot);
19246        self.display_to_pixel_point(source_point, editor_snapshot, window)
19247    }
19248
19249    pub fn display_to_pixel_point(
19250        &self,
19251        source: DisplayPoint,
19252        editor_snapshot: &EditorSnapshot,
19253        window: &mut Window,
19254    ) -> Option<gpui::Point<Pixels>> {
19255        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19256        let text_layout_details = self.text_layout_details(window);
19257        let scroll_top = text_layout_details
19258            .scroll_anchor
19259            .scroll_position(editor_snapshot)
19260            .y;
19261
19262        if source.row().as_f32() < scroll_top.floor() {
19263            return None;
19264        }
19265        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19266        let source_y = line_height * (source.row().as_f32() - scroll_top);
19267        Some(gpui::Point::new(source_x, source_y))
19268    }
19269
19270    pub fn has_visible_completions_menu(&self) -> bool {
19271        !self.edit_prediction_preview_is_active()
19272            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19273                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19274            })
19275    }
19276
19277    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19278        if self.mode.is_minimap() {
19279            return;
19280        }
19281        self.addons
19282            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19283    }
19284
19285    pub fn unregister_addon<T: Addon>(&mut self) {
19286        self.addons.remove(&std::any::TypeId::of::<T>());
19287    }
19288
19289    pub fn addon<T: Addon>(&self) -> Option<&T> {
19290        let type_id = std::any::TypeId::of::<T>();
19291        self.addons
19292            .get(&type_id)
19293            .and_then(|item| item.to_any().downcast_ref::<T>())
19294    }
19295
19296    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19297        let type_id = std::any::TypeId::of::<T>();
19298        self.addons
19299            .get_mut(&type_id)
19300            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19301    }
19302
19303    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19304        let text_layout_details = self.text_layout_details(window);
19305        let style = &text_layout_details.editor_style;
19306        let font_id = window.text_system().resolve_font(&style.text.font());
19307        let font_size = style.text.font_size.to_pixels(window.rem_size());
19308        let line_height = style.text.line_height_in_pixels(window.rem_size());
19309        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19310
19311        gpui::Size::new(em_width, line_height)
19312    }
19313
19314    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19315        self.load_diff_task.clone()
19316    }
19317
19318    fn read_metadata_from_db(
19319        &mut self,
19320        item_id: u64,
19321        workspace_id: WorkspaceId,
19322        window: &mut Window,
19323        cx: &mut Context<Editor>,
19324    ) {
19325        if self.is_singleton(cx)
19326            && !self.mode.is_minimap()
19327            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19328        {
19329            let buffer_snapshot = OnceCell::new();
19330
19331            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19332                if !folds.is_empty() {
19333                    let snapshot =
19334                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19335                    self.fold_ranges(
19336                        folds
19337                            .into_iter()
19338                            .map(|(start, end)| {
19339                                snapshot.clip_offset(start, Bias::Left)
19340                                    ..snapshot.clip_offset(end, Bias::Right)
19341                            })
19342                            .collect(),
19343                        false,
19344                        window,
19345                        cx,
19346                    );
19347                }
19348            }
19349
19350            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19351                if !selections.is_empty() {
19352                    let snapshot =
19353                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19354                    self.change_selections(None, window, cx, |s| {
19355                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19356                            snapshot.clip_offset(start, Bias::Left)
19357                                ..snapshot.clip_offset(end, Bias::Right)
19358                        }));
19359                    });
19360                }
19361            };
19362        }
19363
19364        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19365    }
19366}
19367
19368fn vim_enabled(cx: &App) -> bool {
19369    cx.global::<SettingsStore>()
19370        .raw_user_settings()
19371        .get("vim_mode")
19372        == Some(&serde_json::Value::Bool(true))
19373}
19374
19375// Consider user intent and default settings
19376fn choose_completion_range(
19377    completion: &Completion,
19378    intent: CompletionIntent,
19379    buffer: &Entity<Buffer>,
19380    cx: &mut Context<Editor>,
19381) -> Range<usize> {
19382    fn should_replace(
19383        completion: &Completion,
19384        insert_range: &Range<text::Anchor>,
19385        intent: CompletionIntent,
19386        completion_mode_setting: LspInsertMode,
19387        buffer: &Buffer,
19388    ) -> bool {
19389        // specific actions take precedence over settings
19390        match intent {
19391            CompletionIntent::CompleteWithInsert => return false,
19392            CompletionIntent::CompleteWithReplace => return true,
19393            CompletionIntent::Complete | CompletionIntent::Compose => {}
19394        }
19395
19396        match completion_mode_setting {
19397            LspInsertMode::Insert => false,
19398            LspInsertMode::Replace => true,
19399            LspInsertMode::ReplaceSubsequence => {
19400                let mut text_to_replace = buffer.chars_for_range(
19401                    buffer.anchor_before(completion.replace_range.start)
19402                        ..buffer.anchor_after(completion.replace_range.end),
19403                );
19404                let mut completion_text = completion.new_text.chars();
19405
19406                // is `text_to_replace` a subsequence of `completion_text`
19407                text_to_replace
19408                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19409            }
19410            LspInsertMode::ReplaceSuffix => {
19411                let range_after_cursor = insert_range.end..completion.replace_range.end;
19412
19413                let text_after_cursor = buffer
19414                    .text_for_range(
19415                        buffer.anchor_before(range_after_cursor.start)
19416                            ..buffer.anchor_after(range_after_cursor.end),
19417                    )
19418                    .collect::<String>();
19419                completion.new_text.ends_with(&text_after_cursor)
19420            }
19421        }
19422    }
19423
19424    let buffer = buffer.read(cx);
19425
19426    if let CompletionSource::Lsp {
19427        insert_range: Some(insert_range),
19428        ..
19429    } = &completion.source
19430    {
19431        let completion_mode_setting =
19432            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19433                .completions
19434                .lsp_insert_mode;
19435
19436        if !should_replace(
19437            completion,
19438            &insert_range,
19439            intent,
19440            completion_mode_setting,
19441            buffer,
19442        ) {
19443            return insert_range.to_offset(buffer);
19444        }
19445    }
19446
19447    completion.replace_range.to_offset(buffer)
19448}
19449
19450fn insert_extra_newline_brackets(
19451    buffer: &MultiBufferSnapshot,
19452    range: Range<usize>,
19453    language: &language::LanguageScope,
19454) -> bool {
19455    let leading_whitespace_len = buffer
19456        .reversed_chars_at(range.start)
19457        .take_while(|c| c.is_whitespace() && *c != '\n')
19458        .map(|c| c.len_utf8())
19459        .sum::<usize>();
19460    let trailing_whitespace_len = buffer
19461        .chars_at(range.end)
19462        .take_while(|c| c.is_whitespace() && *c != '\n')
19463        .map(|c| c.len_utf8())
19464        .sum::<usize>();
19465    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19466
19467    language.brackets().any(|(pair, enabled)| {
19468        let pair_start = pair.start.trim_end();
19469        let pair_end = pair.end.trim_start();
19470
19471        enabled
19472            && pair.newline
19473            && buffer.contains_str_at(range.end, pair_end)
19474            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19475    })
19476}
19477
19478fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19479    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19480        [(buffer, range, _)] => (*buffer, range.clone()),
19481        _ => return false,
19482    };
19483    let pair = {
19484        let mut result: Option<BracketMatch> = None;
19485
19486        for pair in buffer
19487            .all_bracket_ranges(range.clone())
19488            .filter(move |pair| {
19489                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19490            })
19491        {
19492            let len = pair.close_range.end - pair.open_range.start;
19493
19494            if let Some(existing) = &result {
19495                let existing_len = existing.close_range.end - existing.open_range.start;
19496                if len > existing_len {
19497                    continue;
19498                }
19499            }
19500
19501            result = Some(pair);
19502        }
19503
19504        result
19505    };
19506    let Some(pair) = pair else {
19507        return false;
19508    };
19509    pair.newline_only
19510        && buffer
19511            .chars_for_range(pair.open_range.end..range.start)
19512            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19513            .all(|c| c.is_whitespace() && c != '\n')
19514}
19515
19516fn update_uncommitted_diff_for_buffer(
19517    editor: Entity<Editor>,
19518    project: &Entity<Project>,
19519    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19520    buffer: Entity<MultiBuffer>,
19521    cx: &mut App,
19522) -> Task<()> {
19523    let mut tasks = Vec::new();
19524    project.update(cx, |project, cx| {
19525        for buffer in buffers {
19526            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19527                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19528            }
19529        }
19530    });
19531    cx.spawn(async move |cx| {
19532        let diffs = future::join_all(tasks).await;
19533        if editor
19534            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19535            .unwrap_or(false)
19536        {
19537            return;
19538        }
19539
19540        buffer
19541            .update(cx, |buffer, cx| {
19542                for diff in diffs.into_iter().flatten() {
19543                    buffer.add_diff(diff, cx);
19544                }
19545            })
19546            .ok();
19547    })
19548}
19549
19550pub trait CollaborationHub {
19551    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19552    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19553    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19554}
19555
19556impl CollaborationHub for Entity<Project> {
19557    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19558        self.read(cx).collaborators()
19559    }
19560
19561    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19562        self.read(cx).user_store().read(cx).participant_indices()
19563    }
19564
19565    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19566        let this = self.read(cx);
19567        let user_ids = this.collaborators().values().map(|c| c.user_id);
19568        this.user_store().read(cx).participant_names(user_ids, cx)
19569    }
19570}
19571
19572pub trait SemanticsProvider {
19573    fn hover(
19574        &self,
19575        buffer: &Entity<Buffer>,
19576        position: text::Anchor,
19577        cx: &mut App,
19578    ) -> Option<Task<Vec<project::Hover>>>;
19579
19580    fn inline_values(
19581        &self,
19582        buffer_handle: Entity<Buffer>,
19583        range: Range<text::Anchor>,
19584        cx: &mut App,
19585    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19586
19587    fn inlay_hints(
19588        &self,
19589        buffer_handle: Entity<Buffer>,
19590        range: Range<text::Anchor>,
19591        cx: &mut App,
19592    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19593
19594    fn resolve_inlay_hint(
19595        &self,
19596        hint: InlayHint,
19597        buffer_handle: Entity<Buffer>,
19598        server_id: LanguageServerId,
19599        cx: &mut App,
19600    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19601
19602    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19603
19604    fn document_highlights(
19605        &self,
19606        buffer: &Entity<Buffer>,
19607        position: text::Anchor,
19608        cx: &mut App,
19609    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19610
19611    fn definitions(
19612        &self,
19613        buffer: &Entity<Buffer>,
19614        position: text::Anchor,
19615        kind: GotoDefinitionKind,
19616        cx: &mut App,
19617    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19618
19619    fn range_for_rename(
19620        &self,
19621        buffer: &Entity<Buffer>,
19622        position: text::Anchor,
19623        cx: &mut App,
19624    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19625
19626    fn perform_rename(
19627        &self,
19628        buffer: &Entity<Buffer>,
19629        position: text::Anchor,
19630        new_name: String,
19631        cx: &mut App,
19632    ) -> Option<Task<Result<ProjectTransaction>>>;
19633}
19634
19635pub trait CompletionProvider {
19636    fn completions(
19637        &self,
19638        excerpt_id: ExcerptId,
19639        buffer: &Entity<Buffer>,
19640        buffer_position: text::Anchor,
19641        trigger: CompletionContext,
19642        window: &mut Window,
19643        cx: &mut Context<Editor>,
19644    ) -> Task<Result<Option<Vec<Completion>>>>;
19645
19646    fn resolve_completions(
19647        &self,
19648        buffer: Entity<Buffer>,
19649        completion_indices: Vec<usize>,
19650        completions: Rc<RefCell<Box<[Completion]>>>,
19651        cx: &mut Context<Editor>,
19652    ) -> Task<Result<bool>>;
19653
19654    fn apply_additional_edits_for_completion(
19655        &self,
19656        _buffer: Entity<Buffer>,
19657        _completions: Rc<RefCell<Box<[Completion]>>>,
19658        _completion_index: usize,
19659        _push_to_history: bool,
19660        _cx: &mut Context<Editor>,
19661    ) -> Task<Result<Option<language::Transaction>>> {
19662        Task::ready(Ok(None))
19663    }
19664
19665    fn is_completion_trigger(
19666        &self,
19667        buffer: &Entity<Buffer>,
19668        position: language::Anchor,
19669        text: &str,
19670        trigger_in_words: bool,
19671        cx: &mut Context<Editor>,
19672    ) -> bool;
19673
19674    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
19675
19676    fn sort_completions(&self) -> bool {
19677        true
19678    }
19679
19680    fn filter_completions(&self) -> bool {
19681        true
19682    }
19683}
19684
19685pub trait CodeActionProvider {
19686    fn id(&self) -> Arc<str>;
19687
19688    fn code_actions(
19689        &self,
19690        buffer: &Entity<Buffer>,
19691        range: Range<text::Anchor>,
19692        window: &mut Window,
19693        cx: &mut App,
19694    ) -> Task<Result<Vec<CodeAction>>>;
19695
19696    fn apply_code_action(
19697        &self,
19698        buffer_handle: Entity<Buffer>,
19699        action: CodeAction,
19700        excerpt_id: ExcerptId,
19701        push_to_history: bool,
19702        window: &mut Window,
19703        cx: &mut App,
19704    ) -> Task<Result<ProjectTransaction>>;
19705}
19706
19707impl CodeActionProvider for Entity<Project> {
19708    fn id(&self) -> Arc<str> {
19709        "project".into()
19710    }
19711
19712    fn code_actions(
19713        &self,
19714        buffer: &Entity<Buffer>,
19715        range: Range<text::Anchor>,
19716        _window: &mut Window,
19717        cx: &mut App,
19718    ) -> Task<Result<Vec<CodeAction>>> {
19719        self.update(cx, |project, cx| {
19720            let code_lens = project.code_lens(buffer, range.clone(), cx);
19721            let code_actions = project.code_actions(buffer, range, None, cx);
19722            cx.background_spawn(async move {
19723                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19724                Ok(code_lens
19725                    .context("code lens fetch")?
19726                    .into_iter()
19727                    .chain(code_actions.context("code action fetch")?)
19728                    .collect())
19729            })
19730        })
19731    }
19732
19733    fn apply_code_action(
19734        &self,
19735        buffer_handle: Entity<Buffer>,
19736        action: CodeAction,
19737        _excerpt_id: ExcerptId,
19738        push_to_history: bool,
19739        _window: &mut Window,
19740        cx: &mut App,
19741    ) -> Task<Result<ProjectTransaction>> {
19742        self.update(cx, |project, cx| {
19743            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19744        })
19745    }
19746}
19747
19748fn snippet_completions(
19749    project: &Project,
19750    buffer: &Entity<Buffer>,
19751    buffer_position: text::Anchor,
19752    cx: &mut App,
19753) -> Task<Result<Vec<Completion>>> {
19754    let languages = buffer.read(cx).languages_at(buffer_position);
19755    let snippet_store = project.snippets().read(cx);
19756
19757    let scopes: Vec<_> = languages
19758        .iter()
19759        .filter_map(|language| {
19760            let language_name = language.lsp_id();
19761            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19762
19763            if snippets.is_empty() {
19764                None
19765            } else {
19766                Some((language.default_scope(), snippets))
19767            }
19768        })
19769        .collect();
19770
19771    if scopes.is_empty() {
19772        return Task::ready(Ok(vec![]));
19773    }
19774
19775    let snapshot = buffer.read(cx).text_snapshot();
19776    let chars: String = snapshot
19777        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19778        .collect();
19779    let executor = cx.background_executor().clone();
19780
19781    cx.background_spawn(async move {
19782        let mut all_results: Vec<Completion> = Vec::new();
19783        for (scope, snippets) in scopes.into_iter() {
19784            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19785            let mut last_word = chars
19786                .chars()
19787                .take_while(|c| classifier.is_word(*c))
19788                .collect::<String>();
19789            last_word = last_word.chars().rev().collect();
19790
19791            if last_word.is_empty() {
19792                return Ok(vec![]);
19793            }
19794
19795            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19796            let to_lsp = |point: &text::Anchor| {
19797                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19798                point_to_lsp(end)
19799            };
19800            let lsp_end = to_lsp(&buffer_position);
19801
19802            let candidates = snippets
19803                .iter()
19804                .enumerate()
19805                .flat_map(|(ix, snippet)| {
19806                    snippet
19807                        .prefix
19808                        .iter()
19809                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19810                })
19811                .collect::<Vec<StringMatchCandidate>>();
19812
19813            let mut matches = fuzzy::match_strings(
19814                &candidates,
19815                &last_word,
19816                last_word.chars().any(|c| c.is_uppercase()),
19817                100,
19818                &Default::default(),
19819                executor.clone(),
19820            )
19821            .await;
19822
19823            // Remove all candidates where the query's start does not match the start of any word in the candidate
19824            if let Some(query_start) = last_word.chars().next() {
19825                matches.retain(|string_match| {
19826                    split_words(&string_match.string).any(|word| {
19827                        // Check that the first codepoint of the word as lowercase matches the first
19828                        // codepoint of the query as lowercase
19829                        word.chars()
19830                            .flat_map(|codepoint| codepoint.to_lowercase())
19831                            .zip(query_start.to_lowercase())
19832                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19833                    })
19834                });
19835            }
19836
19837            let matched_strings = matches
19838                .into_iter()
19839                .map(|m| m.string)
19840                .collect::<HashSet<_>>();
19841
19842            let mut result: Vec<Completion> = snippets
19843                .iter()
19844                .filter_map(|snippet| {
19845                    let matching_prefix = snippet
19846                        .prefix
19847                        .iter()
19848                        .find(|prefix| matched_strings.contains(*prefix))?;
19849                    let start = as_offset - last_word.len();
19850                    let start = snapshot.anchor_before(start);
19851                    let range = start..buffer_position;
19852                    let lsp_start = to_lsp(&start);
19853                    let lsp_range = lsp::Range {
19854                        start: lsp_start,
19855                        end: lsp_end,
19856                    };
19857                    Some(Completion {
19858                        replace_range: range,
19859                        new_text: snippet.body.clone(),
19860                        source: CompletionSource::Lsp {
19861                            insert_range: None,
19862                            server_id: LanguageServerId(usize::MAX),
19863                            resolved: true,
19864                            lsp_completion: Box::new(lsp::CompletionItem {
19865                                label: snippet.prefix.first().unwrap().clone(),
19866                                kind: Some(CompletionItemKind::SNIPPET),
19867                                label_details: snippet.description.as_ref().map(|description| {
19868                                    lsp::CompletionItemLabelDetails {
19869                                        detail: Some(description.clone()),
19870                                        description: None,
19871                                    }
19872                                }),
19873                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19874                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19875                                    lsp::InsertReplaceEdit {
19876                                        new_text: snippet.body.clone(),
19877                                        insert: lsp_range,
19878                                        replace: lsp_range,
19879                                    },
19880                                )),
19881                                filter_text: Some(snippet.body.clone()),
19882                                sort_text: Some(char::MAX.to_string()),
19883                                ..lsp::CompletionItem::default()
19884                            }),
19885                            lsp_defaults: None,
19886                        },
19887                        label: CodeLabel {
19888                            text: matching_prefix.clone(),
19889                            runs: Vec::new(),
19890                            filter_range: 0..matching_prefix.len(),
19891                        },
19892                        icon_path: None,
19893                        documentation: Some(
19894                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
19895                                single_line: snippet.name.clone().into(),
19896                                plain_text: snippet
19897                                    .description
19898                                    .clone()
19899                                    .map(|description| description.into()),
19900                            },
19901                        ),
19902                        insert_text_mode: None,
19903                        confirm: None,
19904                    })
19905                })
19906                .collect();
19907
19908            all_results.append(&mut result);
19909        }
19910
19911        Ok(all_results)
19912    })
19913}
19914
19915impl CompletionProvider for Entity<Project> {
19916    fn completions(
19917        &self,
19918        _excerpt_id: ExcerptId,
19919        buffer: &Entity<Buffer>,
19920        buffer_position: text::Anchor,
19921        options: CompletionContext,
19922        _window: &mut Window,
19923        cx: &mut Context<Editor>,
19924    ) -> Task<Result<Option<Vec<Completion>>>> {
19925        self.update(cx, |project, cx| {
19926            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19927            let project_completions = project.completions(buffer, buffer_position, options, cx);
19928            cx.background_spawn(async move {
19929                let snippets_completions = snippets.await?;
19930                match project_completions.await? {
19931                    Some(mut completions) => {
19932                        completions.extend(snippets_completions);
19933                        Ok(Some(completions))
19934                    }
19935                    None => {
19936                        if snippets_completions.is_empty() {
19937                            Ok(None)
19938                        } else {
19939                            Ok(Some(snippets_completions))
19940                        }
19941                    }
19942                }
19943            })
19944        })
19945    }
19946
19947    fn resolve_completions(
19948        &self,
19949        buffer: Entity<Buffer>,
19950        completion_indices: Vec<usize>,
19951        completions: Rc<RefCell<Box<[Completion]>>>,
19952        cx: &mut Context<Editor>,
19953    ) -> Task<Result<bool>> {
19954        self.update(cx, |project, cx| {
19955            project.lsp_store().update(cx, |lsp_store, cx| {
19956                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19957            })
19958        })
19959    }
19960
19961    fn apply_additional_edits_for_completion(
19962        &self,
19963        buffer: Entity<Buffer>,
19964        completions: Rc<RefCell<Box<[Completion]>>>,
19965        completion_index: usize,
19966        push_to_history: bool,
19967        cx: &mut Context<Editor>,
19968    ) -> Task<Result<Option<language::Transaction>>> {
19969        self.update(cx, |project, cx| {
19970            project.lsp_store().update(cx, |lsp_store, cx| {
19971                lsp_store.apply_additional_edits_for_completion(
19972                    buffer,
19973                    completions,
19974                    completion_index,
19975                    push_to_history,
19976                    cx,
19977                )
19978            })
19979        })
19980    }
19981
19982    fn is_completion_trigger(
19983        &self,
19984        buffer: &Entity<Buffer>,
19985        position: language::Anchor,
19986        text: &str,
19987        trigger_in_words: bool,
19988        cx: &mut Context<Editor>,
19989    ) -> bool {
19990        let mut chars = text.chars();
19991        let char = if let Some(char) = chars.next() {
19992            char
19993        } else {
19994            return false;
19995        };
19996        if chars.next().is_some() {
19997            return false;
19998        }
19999
20000        let buffer = buffer.read(cx);
20001        let snapshot = buffer.snapshot();
20002        if !snapshot.settings_at(position, cx).show_completions_on_input {
20003            return false;
20004        }
20005        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20006        if trigger_in_words && classifier.is_word(char) {
20007            return true;
20008        }
20009
20010        buffer.completion_triggers().contains(text)
20011    }
20012}
20013
20014impl SemanticsProvider for Entity<Project> {
20015    fn hover(
20016        &self,
20017        buffer: &Entity<Buffer>,
20018        position: text::Anchor,
20019        cx: &mut App,
20020    ) -> Option<Task<Vec<project::Hover>>> {
20021        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20022    }
20023
20024    fn document_highlights(
20025        &self,
20026        buffer: &Entity<Buffer>,
20027        position: text::Anchor,
20028        cx: &mut App,
20029    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20030        Some(self.update(cx, |project, cx| {
20031            project.document_highlights(buffer, position, cx)
20032        }))
20033    }
20034
20035    fn definitions(
20036        &self,
20037        buffer: &Entity<Buffer>,
20038        position: text::Anchor,
20039        kind: GotoDefinitionKind,
20040        cx: &mut App,
20041    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20042        Some(self.update(cx, |project, cx| match kind {
20043            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20044            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20045            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20046            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20047        }))
20048    }
20049
20050    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20051        // TODO: make this work for remote projects
20052        self.update(cx, |project, cx| {
20053            if project
20054                .active_debug_session(cx)
20055                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20056            {
20057                return true;
20058            }
20059
20060            buffer.update(cx, |buffer, cx| {
20061                project.any_language_server_supports_inlay_hints(buffer, cx)
20062            })
20063        })
20064    }
20065
20066    fn inline_values(
20067        &self,
20068        buffer_handle: Entity<Buffer>,
20069
20070        range: Range<text::Anchor>,
20071        cx: &mut App,
20072    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20073        self.update(cx, |project, cx| {
20074            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20075
20076            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20077        })
20078    }
20079
20080    fn inlay_hints(
20081        &self,
20082        buffer_handle: Entity<Buffer>,
20083        range: Range<text::Anchor>,
20084        cx: &mut App,
20085    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20086        Some(self.update(cx, |project, cx| {
20087            project.inlay_hints(buffer_handle, range, cx)
20088        }))
20089    }
20090
20091    fn resolve_inlay_hint(
20092        &self,
20093        hint: InlayHint,
20094        buffer_handle: Entity<Buffer>,
20095        server_id: LanguageServerId,
20096        cx: &mut App,
20097    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20098        Some(self.update(cx, |project, cx| {
20099            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20100        }))
20101    }
20102
20103    fn range_for_rename(
20104        &self,
20105        buffer: &Entity<Buffer>,
20106        position: text::Anchor,
20107        cx: &mut App,
20108    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20109        Some(self.update(cx, |project, cx| {
20110            let buffer = buffer.clone();
20111            let task = project.prepare_rename(buffer.clone(), position, cx);
20112            cx.spawn(async move |_, cx| {
20113                Ok(match task.await? {
20114                    PrepareRenameResponse::Success(range) => Some(range),
20115                    PrepareRenameResponse::InvalidPosition => None,
20116                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20117                        // Fallback on using TreeSitter info to determine identifier range
20118                        buffer.update(cx, |buffer, _| {
20119                            let snapshot = buffer.snapshot();
20120                            let (range, kind) = snapshot.surrounding_word(position);
20121                            if kind != Some(CharKind::Word) {
20122                                return None;
20123                            }
20124                            Some(
20125                                snapshot.anchor_before(range.start)
20126                                    ..snapshot.anchor_after(range.end),
20127                            )
20128                        })?
20129                    }
20130                })
20131            })
20132        }))
20133    }
20134
20135    fn perform_rename(
20136        &self,
20137        buffer: &Entity<Buffer>,
20138        position: text::Anchor,
20139        new_name: String,
20140        cx: &mut App,
20141    ) -> Option<Task<Result<ProjectTransaction>>> {
20142        Some(self.update(cx, |project, cx| {
20143            project.perform_rename(buffer.clone(), position, new_name, cx)
20144        }))
20145    }
20146}
20147
20148fn inlay_hint_settings(
20149    location: Anchor,
20150    snapshot: &MultiBufferSnapshot,
20151    cx: &mut Context<Editor>,
20152) -> InlayHintSettings {
20153    let file = snapshot.file_at(location);
20154    let language = snapshot.language_at(location).map(|l| l.name());
20155    language_settings(language, file, cx).inlay_hints
20156}
20157
20158fn consume_contiguous_rows(
20159    contiguous_row_selections: &mut Vec<Selection<Point>>,
20160    selection: &Selection<Point>,
20161    display_map: &DisplaySnapshot,
20162    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20163) -> (MultiBufferRow, MultiBufferRow) {
20164    contiguous_row_selections.push(selection.clone());
20165    let start_row = MultiBufferRow(selection.start.row);
20166    let mut end_row = ending_row(selection, display_map);
20167
20168    while let Some(next_selection) = selections.peek() {
20169        if next_selection.start.row <= end_row.0 {
20170            end_row = ending_row(next_selection, display_map);
20171            contiguous_row_selections.push(selections.next().unwrap().clone());
20172        } else {
20173            break;
20174        }
20175    }
20176    (start_row, end_row)
20177}
20178
20179fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20180    if next_selection.end.column > 0 || next_selection.is_empty() {
20181        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20182    } else {
20183        MultiBufferRow(next_selection.end.row)
20184    }
20185}
20186
20187impl EditorSnapshot {
20188    pub fn remote_selections_in_range<'a>(
20189        &'a self,
20190        range: &'a Range<Anchor>,
20191        collaboration_hub: &dyn CollaborationHub,
20192        cx: &'a App,
20193    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20194        let participant_names = collaboration_hub.user_names(cx);
20195        let participant_indices = collaboration_hub.user_participant_indices(cx);
20196        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20197        let collaborators_by_replica_id = collaborators_by_peer_id
20198            .values()
20199            .map(|collaborator| (collaborator.replica_id, collaborator))
20200            .collect::<HashMap<_, _>>();
20201        self.buffer_snapshot
20202            .selections_in_range(range, false)
20203            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20204                if replica_id == AGENT_REPLICA_ID {
20205                    Some(RemoteSelection {
20206                        replica_id,
20207                        selection,
20208                        cursor_shape,
20209                        line_mode,
20210                        collaborator_id: CollaboratorId::Agent,
20211                        user_name: Some("Agent".into()),
20212                        color: cx.theme().players().agent(),
20213                    })
20214                } else {
20215                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20216                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20217                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20218                    Some(RemoteSelection {
20219                        replica_id,
20220                        selection,
20221                        cursor_shape,
20222                        line_mode,
20223                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20224                        user_name,
20225                        color: if let Some(index) = participant_index {
20226                            cx.theme().players().color_for_participant(index.0)
20227                        } else {
20228                            cx.theme().players().absent()
20229                        },
20230                    })
20231                }
20232            })
20233    }
20234
20235    pub fn hunks_for_ranges(
20236        &self,
20237        ranges: impl IntoIterator<Item = Range<Point>>,
20238    ) -> Vec<MultiBufferDiffHunk> {
20239        let mut hunks = Vec::new();
20240        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20241            HashMap::default();
20242        for query_range in ranges {
20243            let query_rows =
20244                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20245            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20246                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20247            ) {
20248                // Include deleted hunks that are adjacent to the query range, because
20249                // otherwise they would be missed.
20250                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20251                if hunk.status().is_deleted() {
20252                    intersects_range |= hunk.row_range.start == query_rows.end;
20253                    intersects_range |= hunk.row_range.end == query_rows.start;
20254                }
20255                if intersects_range {
20256                    if !processed_buffer_rows
20257                        .entry(hunk.buffer_id)
20258                        .or_default()
20259                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20260                    {
20261                        continue;
20262                    }
20263                    hunks.push(hunk);
20264                }
20265            }
20266        }
20267
20268        hunks
20269    }
20270
20271    fn display_diff_hunks_for_rows<'a>(
20272        &'a self,
20273        display_rows: Range<DisplayRow>,
20274        folded_buffers: &'a HashSet<BufferId>,
20275    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20276        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20277        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20278
20279        self.buffer_snapshot
20280            .diff_hunks_in_range(buffer_start..buffer_end)
20281            .filter_map(|hunk| {
20282                if folded_buffers.contains(&hunk.buffer_id) {
20283                    return None;
20284                }
20285
20286                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20287                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20288
20289                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20290                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20291
20292                let display_hunk = if hunk_display_start.column() != 0 {
20293                    DisplayDiffHunk::Folded {
20294                        display_row: hunk_display_start.row(),
20295                    }
20296                } else {
20297                    let mut end_row = hunk_display_end.row();
20298                    if hunk_display_end.column() > 0 {
20299                        end_row.0 += 1;
20300                    }
20301                    let is_created_file = hunk.is_created_file();
20302                    DisplayDiffHunk::Unfolded {
20303                        status: hunk.status(),
20304                        diff_base_byte_range: hunk.diff_base_byte_range,
20305                        display_row_range: hunk_display_start.row()..end_row,
20306                        multi_buffer_range: Anchor::range_in_buffer(
20307                            hunk.excerpt_id,
20308                            hunk.buffer_id,
20309                            hunk.buffer_range,
20310                        ),
20311                        is_created_file,
20312                    }
20313                };
20314
20315                Some(display_hunk)
20316            })
20317    }
20318
20319    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20320        self.display_snapshot.buffer_snapshot.language_at(position)
20321    }
20322
20323    pub fn is_focused(&self) -> bool {
20324        self.is_focused
20325    }
20326
20327    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20328        self.placeholder_text.as_ref()
20329    }
20330
20331    pub fn scroll_position(&self) -> gpui::Point<f32> {
20332        self.scroll_anchor.scroll_position(&self.display_snapshot)
20333    }
20334
20335    fn gutter_dimensions(
20336        &self,
20337        font_id: FontId,
20338        font_size: Pixels,
20339        max_line_number_width: Pixels,
20340        cx: &App,
20341    ) -> Option<GutterDimensions> {
20342        if !self.show_gutter {
20343            return None;
20344        }
20345
20346        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20347        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20348
20349        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20350            matches!(
20351                ProjectSettings::get_global(cx).git.git_gutter,
20352                Some(GitGutterSetting::TrackedFiles)
20353            )
20354        });
20355        let gutter_settings = EditorSettings::get_global(cx).gutter;
20356        let show_line_numbers = self
20357            .show_line_numbers
20358            .unwrap_or(gutter_settings.line_numbers);
20359        let line_gutter_width = if show_line_numbers {
20360            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20361            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20362            max_line_number_width.max(min_width_for_number_on_gutter)
20363        } else {
20364            0.0.into()
20365        };
20366
20367        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20368        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20369
20370        let git_blame_entries_width =
20371            self.git_blame_gutter_max_author_length
20372                .map(|max_author_length| {
20373                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20374                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20375
20376                    /// The number of characters to dedicate to gaps and margins.
20377                    const SPACING_WIDTH: usize = 4;
20378
20379                    let max_char_count = max_author_length.min(renderer.max_author_length())
20380                        + ::git::SHORT_SHA_LENGTH
20381                        + MAX_RELATIVE_TIMESTAMP.len()
20382                        + SPACING_WIDTH;
20383
20384                    em_advance * max_char_count
20385                });
20386
20387        let is_singleton = self.buffer_snapshot.is_singleton();
20388
20389        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20390        left_padding += if !is_singleton {
20391            em_width * 4.0
20392        } else if show_runnables || show_breakpoints {
20393            em_width * 3.0
20394        } else if show_git_gutter && show_line_numbers {
20395            em_width * 2.0
20396        } else if show_git_gutter || show_line_numbers {
20397            em_width
20398        } else {
20399            px(0.)
20400        };
20401
20402        let shows_folds = is_singleton && gutter_settings.folds;
20403
20404        let right_padding = if shows_folds && show_line_numbers {
20405            em_width * 4.0
20406        } else if shows_folds || (!is_singleton && show_line_numbers) {
20407            em_width * 3.0
20408        } else if show_line_numbers {
20409            em_width
20410        } else {
20411            px(0.)
20412        };
20413
20414        Some(GutterDimensions {
20415            left_padding,
20416            right_padding,
20417            width: line_gutter_width + left_padding + right_padding,
20418            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20419            git_blame_entries_width,
20420        })
20421    }
20422
20423    pub fn render_crease_toggle(
20424        &self,
20425        buffer_row: MultiBufferRow,
20426        row_contains_cursor: bool,
20427        editor: Entity<Editor>,
20428        window: &mut Window,
20429        cx: &mut App,
20430    ) -> Option<AnyElement> {
20431        let folded = self.is_line_folded(buffer_row);
20432        let mut is_foldable = false;
20433
20434        if let Some(crease) = self
20435            .crease_snapshot
20436            .query_row(buffer_row, &self.buffer_snapshot)
20437        {
20438            is_foldable = true;
20439            match crease {
20440                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20441                    if let Some(render_toggle) = render_toggle {
20442                        let toggle_callback =
20443                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20444                                if folded {
20445                                    editor.update(cx, |editor, cx| {
20446                                        editor.fold_at(buffer_row, window, cx)
20447                                    });
20448                                } else {
20449                                    editor.update(cx, |editor, cx| {
20450                                        editor.unfold_at(buffer_row, window, cx)
20451                                    });
20452                                }
20453                            });
20454                        return Some((render_toggle)(
20455                            buffer_row,
20456                            folded,
20457                            toggle_callback,
20458                            window,
20459                            cx,
20460                        ));
20461                    }
20462                }
20463            }
20464        }
20465
20466        is_foldable |= self.starts_indent(buffer_row);
20467
20468        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20469            Some(
20470                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20471                    .toggle_state(folded)
20472                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20473                        if folded {
20474                            this.unfold_at(buffer_row, window, cx);
20475                        } else {
20476                            this.fold_at(buffer_row, window, cx);
20477                        }
20478                    }))
20479                    .into_any_element(),
20480            )
20481        } else {
20482            None
20483        }
20484    }
20485
20486    pub fn render_crease_trailer(
20487        &self,
20488        buffer_row: MultiBufferRow,
20489        window: &mut Window,
20490        cx: &mut App,
20491    ) -> Option<AnyElement> {
20492        let folded = self.is_line_folded(buffer_row);
20493        if let Crease::Inline { render_trailer, .. } = self
20494            .crease_snapshot
20495            .query_row(buffer_row, &self.buffer_snapshot)?
20496        {
20497            let render_trailer = render_trailer.as_ref()?;
20498            Some(render_trailer(buffer_row, folded, window, cx))
20499        } else {
20500            None
20501        }
20502    }
20503}
20504
20505impl Deref for EditorSnapshot {
20506    type Target = DisplaySnapshot;
20507
20508    fn deref(&self) -> &Self::Target {
20509        &self.display_snapshot
20510    }
20511}
20512
20513#[derive(Clone, Debug, PartialEq, Eq)]
20514pub enum EditorEvent {
20515    InputIgnored {
20516        text: Arc<str>,
20517    },
20518    InputHandled {
20519        utf16_range_to_replace: Option<Range<isize>>,
20520        text: Arc<str>,
20521    },
20522    ExcerptsAdded {
20523        buffer: Entity<Buffer>,
20524        predecessor: ExcerptId,
20525        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20526    },
20527    ExcerptsRemoved {
20528        ids: Vec<ExcerptId>,
20529        removed_buffer_ids: Vec<BufferId>,
20530    },
20531    BufferFoldToggled {
20532        ids: Vec<ExcerptId>,
20533        folded: bool,
20534    },
20535    ExcerptsEdited {
20536        ids: Vec<ExcerptId>,
20537    },
20538    ExcerptsExpanded {
20539        ids: Vec<ExcerptId>,
20540    },
20541    BufferEdited,
20542    Edited {
20543        transaction_id: clock::Lamport,
20544    },
20545    Reparsed(BufferId),
20546    Focused,
20547    FocusedIn,
20548    Blurred,
20549    DirtyChanged,
20550    Saved,
20551    TitleChanged,
20552    DiffBaseChanged,
20553    SelectionsChanged {
20554        local: bool,
20555    },
20556    ScrollPositionChanged {
20557        local: bool,
20558        autoscroll: bool,
20559    },
20560    Closed,
20561    TransactionUndone {
20562        transaction_id: clock::Lamport,
20563    },
20564    TransactionBegun {
20565        transaction_id: clock::Lamport,
20566    },
20567    Reloaded,
20568    CursorShapeChanged,
20569    PushedToNavHistory {
20570        anchor: Anchor,
20571        is_deactivate: bool,
20572    },
20573}
20574
20575impl EventEmitter<EditorEvent> for Editor {}
20576
20577impl Focusable for Editor {
20578    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20579        self.focus_handle.clone()
20580    }
20581}
20582
20583impl Render for Editor {
20584    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20585        let settings = ThemeSettings::get_global(cx);
20586
20587        let mut text_style = match self.mode {
20588            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20589                color: cx.theme().colors().editor_foreground,
20590                font_family: settings.ui_font.family.clone(),
20591                font_features: settings.ui_font.features.clone(),
20592                font_fallbacks: settings.ui_font.fallbacks.clone(),
20593                font_size: rems(0.875).into(),
20594                font_weight: settings.ui_font.weight,
20595                line_height: relative(settings.buffer_line_height.value()),
20596                ..Default::default()
20597            },
20598            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20599                color: cx.theme().colors().editor_foreground,
20600                font_family: settings.buffer_font.family.clone(),
20601                font_features: settings.buffer_font.features.clone(),
20602                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20603                font_size: settings.buffer_font_size(cx).into(),
20604                font_weight: settings.buffer_font.weight,
20605                line_height: relative(settings.buffer_line_height.value()),
20606                ..Default::default()
20607            },
20608        };
20609        if let Some(text_style_refinement) = &self.text_style_refinement {
20610            text_style.refine(text_style_refinement)
20611        }
20612
20613        let background = match self.mode {
20614            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20615            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20616            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20617            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20618        };
20619
20620        EditorElement::new(
20621            &cx.entity(),
20622            EditorStyle {
20623                background,
20624                local_player: cx.theme().players().local(),
20625                text: text_style,
20626                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20627                syntax: cx.theme().syntax().clone(),
20628                status: cx.theme().status().clone(),
20629                inlay_hints_style: make_inlay_hints_style(cx),
20630                inline_completion_styles: make_suggestion_styles(cx),
20631                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20632                show_underlines: !self.mode.is_minimap(),
20633            },
20634        )
20635    }
20636}
20637
20638impl EntityInputHandler for Editor {
20639    fn text_for_range(
20640        &mut self,
20641        range_utf16: Range<usize>,
20642        adjusted_range: &mut Option<Range<usize>>,
20643        _: &mut Window,
20644        cx: &mut Context<Self>,
20645    ) -> Option<String> {
20646        let snapshot = self.buffer.read(cx).read(cx);
20647        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20648        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20649        if (start.0..end.0) != range_utf16 {
20650            adjusted_range.replace(start.0..end.0);
20651        }
20652        Some(snapshot.text_for_range(start..end).collect())
20653    }
20654
20655    fn selected_text_range(
20656        &mut self,
20657        ignore_disabled_input: bool,
20658        _: &mut Window,
20659        cx: &mut Context<Self>,
20660    ) -> Option<UTF16Selection> {
20661        // Prevent the IME menu from appearing when holding down an alphabetic key
20662        // while input is disabled.
20663        if !ignore_disabled_input && !self.input_enabled {
20664            return None;
20665        }
20666
20667        let selection = self.selections.newest::<OffsetUtf16>(cx);
20668        let range = selection.range();
20669
20670        Some(UTF16Selection {
20671            range: range.start.0..range.end.0,
20672            reversed: selection.reversed,
20673        })
20674    }
20675
20676    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20677        let snapshot = self.buffer.read(cx).read(cx);
20678        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20679        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20680    }
20681
20682    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20683        self.clear_highlights::<InputComposition>(cx);
20684        self.ime_transaction.take();
20685    }
20686
20687    fn replace_text_in_range(
20688        &mut self,
20689        range_utf16: Option<Range<usize>>,
20690        text: &str,
20691        window: &mut Window,
20692        cx: &mut Context<Self>,
20693    ) {
20694        if !self.input_enabled {
20695            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20696            return;
20697        }
20698
20699        self.transact(window, cx, |this, window, cx| {
20700            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20701                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20702                Some(this.selection_replacement_ranges(range_utf16, cx))
20703            } else {
20704                this.marked_text_ranges(cx)
20705            };
20706
20707            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20708                let newest_selection_id = this.selections.newest_anchor().id;
20709                this.selections
20710                    .all::<OffsetUtf16>(cx)
20711                    .iter()
20712                    .zip(ranges_to_replace.iter())
20713                    .find_map(|(selection, range)| {
20714                        if selection.id == newest_selection_id {
20715                            Some(
20716                                (range.start.0 as isize - selection.head().0 as isize)
20717                                    ..(range.end.0 as isize - selection.head().0 as isize),
20718                            )
20719                        } else {
20720                            None
20721                        }
20722                    })
20723            });
20724
20725            cx.emit(EditorEvent::InputHandled {
20726                utf16_range_to_replace: range_to_replace,
20727                text: text.into(),
20728            });
20729
20730            if let Some(new_selected_ranges) = new_selected_ranges {
20731                this.change_selections(None, window, cx, |selections| {
20732                    selections.select_ranges(new_selected_ranges)
20733                });
20734                this.backspace(&Default::default(), window, cx);
20735            }
20736
20737            this.handle_input(text, window, cx);
20738        });
20739
20740        if let Some(transaction) = self.ime_transaction {
20741            self.buffer.update(cx, |buffer, cx| {
20742                buffer.group_until_transaction(transaction, cx);
20743            });
20744        }
20745
20746        self.unmark_text(window, cx);
20747    }
20748
20749    fn replace_and_mark_text_in_range(
20750        &mut self,
20751        range_utf16: Option<Range<usize>>,
20752        text: &str,
20753        new_selected_range_utf16: Option<Range<usize>>,
20754        window: &mut Window,
20755        cx: &mut Context<Self>,
20756    ) {
20757        if !self.input_enabled {
20758            return;
20759        }
20760
20761        let transaction = self.transact(window, cx, |this, window, cx| {
20762            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20763                let snapshot = this.buffer.read(cx).read(cx);
20764                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20765                    for marked_range in &mut marked_ranges {
20766                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20767                        marked_range.start.0 += relative_range_utf16.start;
20768                        marked_range.start =
20769                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20770                        marked_range.end =
20771                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20772                    }
20773                }
20774                Some(marked_ranges)
20775            } else if let Some(range_utf16) = range_utf16 {
20776                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20777                Some(this.selection_replacement_ranges(range_utf16, cx))
20778            } else {
20779                None
20780            };
20781
20782            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20783                let newest_selection_id = this.selections.newest_anchor().id;
20784                this.selections
20785                    .all::<OffsetUtf16>(cx)
20786                    .iter()
20787                    .zip(ranges_to_replace.iter())
20788                    .find_map(|(selection, range)| {
20789                        if selection.id == newest_selection_id {
20790                            Some(
20791                                (range.start.0 as isize - selection.head().0 as isize)
20792                                    ..(range.end.0 as isize - selection.head().0 as isize),
20793                            )
20794                        } else {
20795                            None
20796                        }
20797                    })
20798            });
20799
20800            cx.emit(EditorEvent::InputHandled {
20801                utf16_range_to_replace: range_to_replace,
20802                text: text.into(),
20803            });
20804
20805            if let Some(ranges) = ranges_to_replace {
20806                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20807            }
20808
20809            let marked_ranges = {
20810                let snapshot = this.buffer.read(cx).read(cx);
20811                this.selections
20812                    .disjoint_anchors()
20813                    .iter()
20814                    .map(|selection| {
20815                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20816                    })
20817                    .collect::<Vec<_>>()
20818            };
20819
20820            if text.is_empty() {
20821                this.unmark_text(window, cx);
20822            } else {
20823                this.highlight_text::<InputComposition>(
20824                    marked_ranges.clone(),
20825                    HighlightStyle {
20826                        underline: Some(UnderlineStyle {
20827                            thickness: px(1.),
20828                            color: None,
20829                            wavy: false,
20830                        }),
20831                        ..Default::default()
20832                    },
20833                    cx,
20834                );
20835            }
20836
20837            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20838            let use_autoclose = this.use_autoclose;
20839            let use_auto_surround = this.use_auto_surround;
20840            this.set_use_autoclose(false);
20841            this.set_use_auto_surround(false);
20842            this.handle_input(text, window, cx);
20843            this.set_use_autoclose(use_autoclose);
20844            this.set_use_auto_surround(use_auto_surround);
20845
20846            if let Some(new_selected_range) = new_selected_range_utf16 {
20847                let snapshot = this.buffer.read(cx).read(cx);
20848                let new_selected_ranges = marked_ranges
20849                    .into_iter()
20850                    .map(|marked_range| {
20851                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20852                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20853                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20854                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20855                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20856                    })
20857                    .collect::<Vec<_>>();
20858
20859                drop(snapshot);
20860                this.change_selections(None, window, cx, |selections| {
20861                    selections.select_ranges(new_selected_ranges)
20862                });
20863            }
20864        });
20865
20866        self.ime_transaction = self.ime_transaction.or(transaction);
20867        if let Some(transaction) = self.ime_transaction {
20868            self.buffer.update(cx, |buffer, cx| {
20869                buffer.group_until_transaction(transaction, cx);
20870            });
20871        }
20872
20873        if self.text_highlights::<InputComposition>(cx).is_none() {
20874            self.ime_transaction.take();
20875        }
20876    }
20877
20878    fn bounds_for_range(
20879        &mut self,
20880        range_utf16: Range<usize>,
20881        element_bounds: gpui::Bounds<Pixels>,
20882        window: &mut Window,
20883        cx: &mut Context<Self>,
20884    ) -> Option<gpui::Bounds<Pixels>> {
20885        let text_layout_details = self.text_layout_details(window);
20886        let gpui::Size {
20887            width: em_width,
20888            height: line_height,
20889        } = self.character_size(window);
20890
20891        let snapshot = self.snapshot(window, cx);
20892        let scroll_position = snapshot.scroll_position();
20893        let scroll_left = scroll_position.x * em_width;
20894
20895        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20896        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20897            + self.gutter_dimensions.width
20898            + self.gutter_dimensions.margin;
20899        let y = line_height * (start.row().as_f32() - scroll_position.y);
20900
20901        Some(Bounds {
20902            origin: element_bounds.origin + point(x, y),
20903            size: size(em_width, line_height),
20904        })
20905    }
20906
20907    fn character_index_for_point(
20908        &mut self,
20909        point: gpui::Point<Pixels>,
20910        _window: &mut Window,
20911        _cx: &mut Context<Self>,
20912    ) -> Option<usize> {
20913        let position_map = self.last_position_map.as_ref()?;
20914        if !position_map.text_hitbox.contains(&point) {
20915            return None;
20916        }
20917        let display_point = position_map.point_for_position(point).previous_valid;
20918        let anchor = position_map
20919            .snapshot
20920            .display_point_to_anchor(display_point, Bias::Left);
20921        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20922        Some(utf16_offset.0)
20923    }
20924}
20925
20926trait SelectionExt {
20927    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20928    fn spanned_rows(
20929        &self,
20930        include_end_if_at_line_start: bool,
20931        map: &DisplaySnapshot,
20932    ) -> Range<MultiBufferRow>;
20933}
20934
20935impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20936    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20937        let start = self
20938            .start
20939            .to_point(&map.buffer_snapshot)
20940            .to_display_point(map);
20941        let end = self
20942            .end
20943            .to_point(&map.buffer_snapshot)
20944            .to_display_point(map);
20945        if self.reversed {
20946            end..start
20947        } else {
20948            start..end
20949        }
20950    }
20951
20952    fn spanned_rows(
20953        &self,
20954        include_end_if_at_line_start: bool,
20955        map: &DisplaySnapshot,
20956    ) -> Range<MultiBufferRow> {
20957        let start = self.start.to_point(&map.buffer_snapshot);
20958        let mut end = self.end.to_point(&map.buffer_snapshot);
20959        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20960            end.row -= 1;
20961        }
20962
20963        let buffer_start = map.prev_line_boundary(start).0;
20964        let buffer_end = map.next_line_boundary(end).0;
20965        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20966    }
20967}
20968
20969impl<T: InvalidationRegion> InvalidationStack<T> {
20970    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20971    where
20972        S: Clone + ToOffset,
20973    {
20974        while let Some(region) = self.last() {
20975            let all_selections_inside_invalidation_ranges =
20976                if selections.len() == region.ranges().len() {
20977                    selections
20978                        .iter()
20979                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20980                        .all(|(selection, invalidation_range)| {
20981                            let head = selection.head().to_offset(buffer);
20982                            invalidation_range.start <= head && invalidation_range.end >= head
20983                        })
20984                } else {
20985                    false
20986                };
20987
20988            if all_selections_inside_invalidation_ranges {
20989                break;
20990            } else {
20991                self.pop();
20992            }
20993        }
20994    }
20995}
20996
20997impl<T> Default for InvalidationStack<T> {
20998    fn default() -> Self {
20999        Self(Default::default())
21000    }
21001}
21002
21003impl<T> Deref for InvalidationStack<T> {
21004    type Target = Vec<T>;
21005
21006    fn deref(&self) -> &Self::Target {
21007        &self.0
21008    }
21009}
21010
21011impl<T> DerefMut for InvalidationStack<T> {
21012    fn deref_mut(&mut self) -> &mut Self::Target {
21013        &mut self.0
21014    }
21015}
21016
21017impl InvalidationRegion for SnippetState {
21018    fn ranges(&self) -> &[Range<Anchor>] {
21019        &self.ranges[self.active_index]
21020    }
21021}
21022
21023fn inline_completion_edit_text(
21024    current_snapshot: &BufferSnapshot,
21025    edits: &[(Range<Anchor>, String)],
21026    edit_preview: &EditPreview,
21027    include_deletions: bool,
21028    cx: &App,
21029) -> HighlightedText {
21030    let edits = edits
21031        .iter()
21032        .map(|(anchor, text)| {
21033            (
21034                anchor.start.text_anchor..anchor.end.text_anchor,
21035                text.clone(),
21036            )
21037        })
21038        .collect::<Vec<_>>();
21039
21040    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21041}
21042
21043pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21044    match severity {
21045        lsp::DiagnosticSeverity::ERROR => colors.error,
21046        lsp::DiagnosticSeverity::WARNING => colors.warning,
21047        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21048        lsp::DiagnosticSeverity::HINT => colors.info,
21049        _ => colors.ignored,
21050    }
21051}
21052
21053pub fn styled_runs_for_code_label<'a>(
21054    label: &'a CodeLabel,
21055    syntax_theme: &'a theme::SyntaxTheme,
21056) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21057    let fade_out = HighlightStyle {
21058        fade_out: Some(0.35),
21059        ..Default::default()
21060    };
21061
21062    let mut prev_end = label.filter_range.end;
21063    label
21064        .runs
21065        .iter()
21066        .enumerate()
21067        .flat_map(move |(ix, (range, highlight_id))| {
21068            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21069                style
21070            } else {
21071                return Default::default();
21072            };
21073            let mut muted_style = style;
21074            muted_style.highlight(fade_out);
21075
21076            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21077            if range.start >= label.filter_range.end {
21078                if range.start > prev_end {
21079                    runs.push((prev_end..range.start, fade_out));
21080                }
21081                runs.push((range.clone(), muted_style));
21082            } else if range.end <= label.filter_range.end {
21083                runs.push((range.clone(), style));
21084            } else {
21085                runs.push((range.start..label.filter_range.end, style));
21086                runs.push((label.filter_range.end..range.end, muted_style));
21087            }
21088            prev_end = cmp::max(prev_end, range.end);
21089
21090            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21091                runs.push((prev_end..label.text.len(), fade_out));
21092            }
21093
21094            runs
21095        })
21096}
21097
21098pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21099    let mut prev_index = 0;
21100    let mut prev_codepoint: Option<char> = None;
21101    text.char_indices()
21102        .chain([(text.len(), '\0')])
21103        .filter_map(move |(index, codepoint)| {
21104            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21105            let is_boundary = index == text.len()
21106                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21107                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21108            if is_boundary {
21109                let chunk = &text[prev_index..index];
21110                prev_index = index;
21111                Some(chunk)
21112            } else {
21113                None
21114            }
21115        })
21116}
21117
21118pub trait RangeToAnchorExt: Sized {
21119    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21120
21121    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21122        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21123        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21124    }
21125}
21126
21127impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21128    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21129        let start_offset = self.start.to_offset(snapshot);
21130        let end_offset = self.end.to_offset(snapshot);
21131        if start_offset == end_offset {
21132            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21133        } else {
21134            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21135        }
21136    }
21137}
21138
21139pub trait RowExt {
21140    fn as_f32(&self) -> f32;
21141
21142    fn next_row(&self) -> Self;
21143
21144    fn previous_row(&self) -> Self;
21145
21146    fn minus(&self, other: Self) -> u32;
21147}
21148
21149impl RowExt for DisplayRow {
21150    fn as_f32(&self) -> f32 {
21151        self.0 as f32
21152    }
21153
21154    fn next_row(&self) -> Self {
21155        Self(self.0 + 1)
21156    }
21157
21158    fn previous_row(&self) -> Self {
21159        Self(self.0.saturating_sub(1))
21160    }
21161
21162    fn minus(&self, other: Self) -> u32 {
21163        self.0 - other.0
21164    }
21165}
21166
21167impl RowExt for MultiBufferRow {
21168    fn as_f32(&self) -> f32 {
21169        self.0 as f32
21170    }
21171
21172    fn next_row(&self) -> Self {
21173        Self(self.0 + 1)
21174    }
21175
21176    fn previous_row(&self) -> Self {
21177        Self(self.0.saturating_sub(1))
21178    }
21179
21180    fn minus(&self, other: Self) -> u32 {
21181        self.0 - other.0
21182    }
21183}
21184
21185trait RowRangeExt {
21186    type Row;
21187
21188    fn len(&self) -> usize;
21189
21190    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21191}
21192
21193impl RowRangeExt for Range<MultiBufferRow> {
21194    type Row = MultiBufferRow;
21195
21196    fn len(&self) -> usize {
21197        (self.end.0 - self.start.0) as usize
21198    }
21199
21200    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21201        (self.start.0..self.end.0).map(MultiBufferRow)
21202    }
21203}
21204
21205impl RowRangeExt for Range<DisplayRow> {
21206    type Row = DisplayRow;
21207
21208    fn len(&self) -> usize {
21209        (self.end.0 - self.start.0) as usize
21210    }
21211
21212    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21213        (self.start.0..self.end.0).map(DisplayRow)
21214    }
21215}
21216
21217/// If select range has more than one line, we
21218/// just point the cursor to range.start.
21219fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21220    if range.start.row == range.end.row {
21221        range
21222    } else {
21223        range.start..range.start
21224    }
21225}
21226pub struct KillRing(ClipboardItem);
21227impl Global for KillRing {}
21228
21229const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21230
21231enum BreakpointPromptEditAction {
21232    Log,
21233    Condition,
21234    HitCondition,
21235}
21236
21237struct BreakpointPromptEditor {
21238    pub(crate) prompt: Entity<Editor>,
21239    editor: WeakEntity<Editor>,
21240    breakpoint_anchor: Anchor,
21241    breakpoint: Breakpoint,
21242    edit_action: BreakpointPromptEditAction,
21243    block_ids: HashSet<CustomBlockId>,
21244    editor_margins: Arc<Mutex<EditorMargins>>,
21245    _subscriptions: Vec<Subscription>,
21246}
21247
21248impl BreakpointPromptEditor {
21249    const MAX_LINES: u8 = 4;
21250
21251    fn new(
21252        editor: WeakEntity<Editor>,
21253        breakpoint_anchor: Anchor,
21254        breakpoint: Breakpoint,
21255        edit_action: BreakpointPromptEditAction,
21256        window: &mut Window,
21257        cx: &mut Context<Self>,
21258    ) -> Self {
21259        let base_text = match edit_action {
21260            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21261            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21262            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21263        }
21264        .map(|msg| msg.to_string())
21265        .unwrap_or_default();
21266
21267        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21268        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21269
21270        let prompt = cx.new(|cx| {
21271            let mut prompt = Editor::new(
21272                EditorMode::AutoHeight {
21273                    max_lines: Self::MAX_LINES as usize,
21274                },
21275                buffer,
21276                None,
21277                window,
21278                cx,
21279            );
21280            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21281            prompt.set_show_cursor_when_unfocused(false, cx);
21282            prompt.set_placeholder_text(
21283                match edit_action {
21284                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21285                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21286                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21287                },
21288                cx,
21289            );
21290
21291            prompt
21292        });
21293
21294        Self {
21295            prompt,
21296            editor,
21297            breakpoint_anchor,
21298            breakpoint,
21299            edit_action,
21300            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21301            block_ids: Default::default(),
21302            _subscriptions: vec![],
21303        }
21304    }
21305
21306    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21307        self.block_ids.extend(block_ids)
21308    }
21309
21310    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21311        if let Some(editor) = self.editor.upgrade() {
21312            let message = self
21313                .prompt
21314                .read(cx)
21315                .buffer
21316                .read(cx)
21317                .as_singleton()
21318                .expect("A multi buffer in breakpoint prompt isn't possible")
21319                .read(cx)
21320                .as_rope()
21321                .to_string();
21322
21323            editor.update(cx, |editor, cx| {
21324                editor.edit_breakpoint_at_anchor(
21325                    self.breakpoint_anchor,
21326                    self.breakpoint.clone(),
21327                    match self.edit_action {
21328                        BreakpointPromptEditAction::Log => {
21329                            BreakpointEditAction::EditLogMessage(message.into())
21330                        }
21331                        BreakpointPromptEditAction::Condition => {
21332                            BreakpointEditAction::EditCondition(message.into())
21333                        }
21334                        BreakpointPromptEditAction::HitCondition => {
21335                            BreakpointEditAction::EditHitCondition(message.into())
21336                        }
21337                    },
21338                    cx,
21339                );
21340
21341                editor.remove_blocks(self.block_ids.clone(), None, cx);
21342                cx.focus_self(window);
21343            });
21344        }
21345    }
21346
21347    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21348        self.editor
21349            .update(cx, |editor, cx| {
21350                editor.remove_blocks(self.block_ids.clone(), None, cx);
21351                window.focus(&editor.focus_handle);
21352            })
21353            .log_err();
21354    }
21355
21356    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21357        let settings = ThemeSettings::get_global(cx);
21358        let text_style = TextStyle {
21359            color: if self.prompt.read(cx).read_only(cx) {
21360                cx.theme().colors().text_disabled
21361            } else {
21362                cx.theme().colors().text
21363            },
21364            font_family: settings.buffer_font.family.clone(),
21365            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21366            font_size: settings.buffer_font_size(cx).into(),
21367            font_weight: settings.buffer_font.weight,
21368            line_height: relative(settings.buffer_line_height.value()),
21369            ..Default::default()
21370        };
21371        EditorElement::new(
21372            &self.prompt,
21373            EditorStyle {
21374                background: cx.theme().colors().editor_background,
21375                local_player: cx.theme().players().local(),
21376                text: text_style,
21377                ..Default::default()
21378            },
21379        )
21380    }
21381}
21382
21383impl Render for BreakpointPromptEditor {
21384    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21385        let editor_margins = *self.editor_margins.lock();
21386        let gutter_dimensions = editor_margins.gutter;
21387        h_flex()
21388            .key_context("Editor")
21389            .bg(cx.theme().colors().editor_background)
21390            .border_y_1()
21391            .border_color(cx.theme().status().info_border)
21392            .size_full()
21393            .py(window.line_height() / 2.5)
21394            .on_action(cx.listener(Self::confirm))
21395            .on_action(cx.listener(Self::cancel))
21396            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21397            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21398    }
21399}
21400
21401impl Focusable for BreakpointPromptEditor {
21402    fn focus_handle(&self, cx: &App) -> FocusHandle {
21403        self.prompt.focus_handle(cx)
21404    }
21405}
21406
21407fn all_edits_insertions_or_deletions(
21408    edits: &Vec<(Range<Anchor>, String)>,
21409    snapshot: &MultiBufferSnapshot,
21410) -> bool {
21411    let mut all_insertions = true;
21412    let mut all_deletions = true;
21413
21414    for (range, new_text) in edits.iter() {
21415        let range_is_empty = range.to_offset(&snapshot).is_empty();
21416        let text_is_empty = new_text.is_empty();
21417
21418        if range_is_empty != text_is_empty {
21419            if range_is_empty {
21420                all_deletions = false;
21421            } else {
21422                all_insertions = false;
21423            }
21424        } else {
21425            return false;
21426        }
21427
21428        if !all_insertions && !all_deletions {
21429            return false;
21430        }
21431    }
21432    all_insertions || all_deletions
21433}
21434
21435struct MissingEditPredictionKeybindingTooltip;
21436
21437impl Render for MissingEditPredictionKeybindingTooltip {
21438    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21439        ui::tooltip_container(window, cx, |container, _, cx| {
21440            container
21441                .flex_shrink_0()
21442                .max_w_80()
21443                .min_h(rems_from_px(124.))
21444                .justify_between()
21445                .child(
21446                    v_flex()
21447                        .flex_1()
21448                        .text_ui_sm(cx)
21449                        .child(Label::new("Conflict with Accept Keybinding"))
21450                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21451                )
21452                .child(
21453                    h_flex()
21454                        .pb_1()
21455                        .gap_1()
21456                        .items_end()
21457                        .w_full()
21458                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21459                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21460                        }))
21461                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21462                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21463                        })),
21464                )
21465        })
21466    }
21467}
21468
21469#[derive(Debug, Clone, Copy, PartialEq)]
21470pub struct LineHighlight {
21471    pub background: Background,
21472    pub border: Option<gpui::Hsla>,
21473    pub include_gutter: bool,
21474    pub type_id: Option<TypeId>,
21475}
21476
21477fn render_diff_hunk_controls(
21478    row: u32,
21479    status: &DiffHunkStatus,
21480    hunk_range: Range<Anchor>,
21481    is_created_file: bool,
21482    line_height: Pixels,
21483    editor: &Entity<Editor>,
21484    _window: &mut Window,
21485    cx: &mut App,
21486) -> AnyElement {
21487    h_flex()
21488        .h(line_height)
21489        .mr_1()
21490        .gap_1()
21491        .px_0p5()
21492        .pb_1()
21493        .border_x_1()
21494        .border_b_1()
21495        .border_color(cx.theme().colors().border_variant)
21496        .rounded_b_lg()
21497        .bg(cx.theme().colors().editor_background)
21498        .gap_1()
21499        .occlude()
21500        .shadow_md()
21501        .child(if status.has_secondary_hunk() {
21502            Button::new(("stage", row as u64), "Stage")
21503                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21504                .tooltip({
21505                    let focus_handle = editor.focus_handle(cx);
21506                    move |window, cx| {
21507                        Tooltip::for_action_in(
21508                            "Stage Hunk",
21509                            &::git::ToggleStaged,
21510                            &focus_handle,
21511                            window,
21512                            cx,
21513                        )
21514                    }
21515                })
21516                .on_click({
21517                    let editor = editor.clone();
21518                    move |_event, _window, cx| {
21519                        editor.update(cx, |editor, cx| {
21520                            editor.stage_or_unstage_diff_hunks(
21521                                true,
21522                                vec![hunk_range.start..hunk_range.start],
21523                                cx,
21524                            );
21525                        });
21526                    }
21527                })
21528        } else {
21529            Button::new(("unstage", row as u64), "Unstage")
21530                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21531                .tooltip({
21532                    let focus_handle = editor.focus_handle(cx);
21533                    move |window, cx| {
21534                        Tooltip::for_action_in(
21535                            "Unstage Hunk",
21536                            &::git::ToggleStaged,
21537                            &focus_handle,
21538                            window,
21539                            cx,
21540                        )
21541                    }
21542                })
21543                .on_click({
21544                    let editor = editor.clone();
21545                    move |_event, _window, cx| {
21546                        editor.update(cx, |editor, cx| {
21547                            editor.stage_or_unstage_diff_hunks(
21548                                false,
21549                                vec![hunk_range.start..hunk_range.start],
21550                                cx,
21551                            );
21552                        });
21553                    }
21554                })
21555        })
21556        .child(
21557            Button::new(("restore", row as u64), "Restore")
21558                .tooltip({
21559                    let focus_handle = editor.focus_handle(cx);
21560                    move |window, cx| {
21561                        Tooltip::for_action_in(
21562                            "Restore Hunk",
21563                            &::git::Restore,
21564                            &focus_handle,
21565                            window,
21566                            cx,
21567                        )
21568                    }
21569                })
21570                .on_click({
21571                    let editor = editor.clone();
21572                    move |_event, window, cx| {
21573                        editor.update(cx, |editor, cx| {
21574                            let snapshot = editor.snapshot(window, cx);
21575                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21576                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21577                        });
21578                    }
21579                })
21580                .disabled(is_created_file),
21581        )
21582        .when(
21583            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21584            |el| {
21585                el.child(
21586                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21587                        .shape(IconButtonShape::Square)
21588                        .icon_size(IconSize::Small)
21589                        // .disabled(!has_multiple_hunks)
21590                        .tooltip({
21591                            let focus_handle = editor.focus_handle(cx);
21592                            move |window, cx| {
21593                                Tooltip::for_action_in(
21594                                    "Next Hunk",
21595                                    &GoToHunk,
21596                                    &focus_handle,
21597                                    window,
21598                                    cx,
21599                                )
21600                            }
21601                        })
21602                        .on_click({
21603                            let editor = editor.clone();
21604                            move |_event, window, cx| {
21605                                editor.update(cx, |editor, cx| {
21606                                    let snapshot = editor.snapshot(window, cx);
21607                                    let position =
21608                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21609                                    editor.go_to_hunk_before_or_after_position(
21610                                        &snapshot,
21611                                        position,
21612                                        Direction::Next,
21613                                        window,
21614                                        cx,
21615                                    );
21616                                    editor.expand_selected_diff_hunks(cx);
21617                                });
21618                            }
21619                        }),
21620                )
21621                .child(
21622                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21623                        .shape(IconButtonShape::Square)
21624                        .icon_size(IconSize::Small)
21625                        // .disabled(!has_multiple_hunks)
21626                        .tooltip({
21627                            let focus_handle = editor.focus_handle(cx);
21628                            move |window, cx| {
21629                                Tooltip::for_action_in(
21630                                    "Previous Hunk",
21631                                    &GoToPreviousHunk,
21632                                    &focus_handle,
21633                                    window,
21634                                    cx,
21635                                )
21636                            }
21637                        })
21638                        .on_click({
21639                            let editor = editor.clone();
21640                            move |_event, window, cx| {
21641                                editor.update(cx, |editor, cx| {
21642                                    let snapshot = editor.snapshot(window, cx);
21643                                    let point =
21644                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21645                                    editor.go_to_hunk_before_or_after_position(
21646                                        &snapshot,
21647                                        point,
21648                                        Direction::Prev,
21649                                        window,
21650                                        cx,
21651                                    );
21652                                    editor.expand_selected_diff_hunks(cx);
21653                                });
21654                            }
21655                        }),
21656                )
21657            },
21658        )
21659        .into_any_element()
21660}