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, ScrollbarAxes,
   67    SearchSettings, 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: ScrollbarAxes,
  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: ScrollbarAxes {
 1805                horizontal: full_mode,
 1806                vertical: full_mode,
 1807            },
 1808            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1809            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1810            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1811            show_gutter: mode.is_full(),
 1812            show_line_numbers: None,
 1813            use_relative_line_numbers: None,
 1814            disable_expand_excerpt_buttons: false,
 1815            show_git_diff_gutter: None,
 1816            show_code_actions: None,
 1817            show_runnables: None,
 1818            show_breakpoints: None,
 1819            show_wrap_guides: None,
 1820            show_indent_guides,
 1821            placeholder_text: None,
 1822            highlight_order: 0,
 1823            highlighted_rows: HashMap::default(),
 1824            background_highlights: TreeMap::default(),
 1825            gutter_highlights: TreeMap::default(),
 1826            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1827            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1828            nav_history: None,
 1829            context_menu: RefCell::new(None),
 1830            context_menu_options: None,
 1831            mouse_context_menu: None,
 1832            completion_tasks: Vec::new(),
 1833            inline_blame_popover: None,
 1834            signature_help_state: SignatureHelpState::default(),
 1835            auto_signature_help: None,
 1836            find_all_references_task_sources: Vec::new(),
 1837            next_completion_id: 0,
 1838            next_inlay_id: 0,
 1839            code_action_providers,
 1840            available_code_actions: None,
 1841            code_actions_task: None,
 1842            quick_selection_highlight_task: None,
 1843            debounced_selection_highlight_task: None,
 1844            document_highlights_task: None,
 1845            linked_editing_range_task: None,
 1846            pending_rename: None,
 1847            searchable: true,
 1848            cursor_shape: EditorSettings::get_global(cx)
 1849                .cursor_shape
 1850                .unwrap_or_default(),
 1851            current_line_highlight: None,
 1852            autoindent_mode: Some(AutoindentMode::EachLine),
 1853            collapse_matches: false,
 1854            workspace: None,
 1855            input_enabled: true,
 1856            use_modal_editing: mode.is_full(),
 1857            read_only: mode.is_minimap(),
 1858            use_autoclose: true,
 1859            use_auto_surround: true,
 1860            auto_replace_emoji_shortcode: false,
 1861            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1862            leader_id: None,
 1863            remote_id: None,
 1864            hover_state: HoverState::default(),
 1865            pending_mouse_down: None,
 1866            hovered_link_state: None,
 1867            edit_prediction_provider: None,
 1868            active_inline_completion: None,
 1869            stale_inline_completion_in_menu: None,
 1870            edit_prediction_preview: EditPredictionPreview::Inactive {
 1871                released_too_fast: false,
 1872            },
 1873            inline_diagnostics_enabled: mode.is_full(),
 1874            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1875            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1876
 1877            gutter_hovered: false,
 1878            pixel_position_of_newest_cursor: None,
 1879            last_bounds: None,
 1880            last_position_map: None,
 1881            expect_bounds_change: None,
 1882            gutter_dimensions: GutterDimensions::default(),
 1883            style: None,
 1884            show_cursor_names: false,
 1885            hovered_cursors: HashMap::default(),
 1886            next_editor_action_id: EditorActionId::default(),
 1887            editor_actions: Rc::default(),
 1888            inline_completions_hidden_for_vim_mode: false,
 1889            show_inline_completions_override: None,
 1890            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1891            edit_prediction_settings: EditPredictionSettings::Disabled,
 1892            edit_prediction_indent_conflict: false,
 1893            edit_prediction_requires_modifier_in_indent_conflict: true,
 1894            custom_context_menu: None,
 1895            show_git_blame_gutter: false,
 1896            show_git_blame_inline: false,
 1897            show_selection_menu: None,
 1898            show_git_blame_inline_delay_task: None,
 1899            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1900            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1901            serialize_dirty_buffers: !mode.is_minimap()
 1902                && ProjectSettings::get_global(cx)
 1903                    .session
 1904                    .restore_unsaved_buffers,
 1905            blame: None,
 1906            blame_subscription: None,
 1907            tasks: BTreeMap::default(),
 1908
 1909            breakpoint_store,
 1910            gutter_breakpoint_indicator: (None, None),
 1911            _subscriptions: vec![
 1912                cx.observe(&buffer, Self::on_buffer_changed),
 1913                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1914                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1915                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1916                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1917                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1918                cx.observe_window_activation(window, |editor, window, cx| {
 1919                    let active = window.is_window_active();
 1920                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1921                        if active {
 1922                            blink_manager.enable(cx);
 1923                        } else {
 1924                            blink_manager.disable(cx);
 1925                        }
 1926                    });
 1927                    if active {
 1928                        editor.show_mouse_cursor();
 1929                    }
 1930                }),
 1931            ],
 1932            tasks_update_task: None,
 1933            linked_edit_ranges: Default::default(),
 1934            in_project_search: false,
 1935            previous_search_ranges: None,
 1936            breadcrumb_header: None,
 1937            focused_block: None,
 1938            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1939            addons: HashMap::default(),
 1940            registered_buffers: HashMap::default(),
 1941            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1942            selection_mark_mode: false,
 1943            toggle_fold_multiple_buffers: Task::ready(()),
 1944            serialize_selections: Task::ready(()),
 1945            serialize_folds: Task::ready(()),
 1946            text_style_refinement: None,
 1947            load_diff_task: load_uncommitted_diff,
 1948            temporary_diff_override: false,
 1949            mouse_cursor_hidden: false,
 1950            minimap: None,
 1951            hide_mouse_mode: EditorSettings::get_global(cx)
 1952                .hide_mouse
 1953                .unwrap_or_default(),
 1954            change_list: ChangeList::new(),
 1955            mode,
 1956        };
 1957        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1958            this._subscriptions
 1959                .push(cx.observe(breakpoints, |_, _, cx| {
 1960                    cx.notify();
 1961                }));
 1962        }
 1963        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1964        this._subscriptions.extend(project_subscriptions);
 1965
 1966        this._subscriptions.push(cx.subscribe_in(
 1967            &cx.entity(),
 1968            window,
 1969            |editor, _, e: &EditorEvent, window, cx| match e {
 1970                EditorEvent::ScrollPositionChanged { local, .. } => {
 1971                    if *local {
 1972                        let new_anchor = editor.scroll_manager.anchor();
 1973                        let snapshot = editor.snapshot(window, cx);
 1974                        editor.update_restoration_data(cx, move |data| {
 1975                            data.scroll_position = (
 1976                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1977                                new_anchor.offset,
 1978                            );
 1979                        });
 1980                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1981                        editor.inline_blame_popover.take();
 1982                    }
 1983                }
 1984                EditorEvent::Edited { .. } => {
 1985                    if !vim_enabled(cx) {
 1986                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1987                        let pop_state = editor
 1988                            .change_list
 1989                            .last()
 1990                            .map(|previous| {
 1991                                previous.len() == selections.len()
 1992                                    && previous.iter().enumerate().all(|(ix, p)| {
 1993                                        p.to_display_point(&map).row()
 1994                                            == selections[ix].head().row()
 1995                                    })
 1996                            })
 1997                            .unwrap_or(false);
 1998                        let new_positions = selections
 1999                            .into_iter()
 2000                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2001                            .collect();
 2002                        editor
 2003                            .change_list
 2004                            .push_to_change_list(pop_state, new_positions);
 2005                    }
 2006                }
 2007                _ => (),
 2008            },
 2009        ));
 2010
 2011        if let Some(dap_store) = this
 2012            .project
 2013            .as_ref()
 2014            .map(|project| project.read(cx).dap_store())
 2015        {
 2016            let weak_editor = cx.weak_entity();
 2017
 2018            this._subscriptions
 2019                .push(
 2020                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2021                        let session_entity = cx.entity();
 2022                        weak_editor
 2023                            .update(cx, |editor, cx| {
 2024                                editor._subscriptions.push(
 2025                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2026                                );
 2027                            })
 2028                            .ok();
 2029                    }),
 2030                );
 2031
 2032            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2033                this._subscriptions
 2034                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2035            }
 2036        }
 2037
 2038        this.end_selection(window, cx);
 2039        this.scroll_manager.show_scrollbars(window, cx);
 2040        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2041
 2042        if full_mode {
 2043            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2044            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2045
 2046            if this.git_blame_inline_enabled {
 2047                this.start_git_blame_inline(false, window, cx);
 2048            }
 2049
 2050            this.go_to_active_debug_line(window, cx);
 2051
 2052            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2053                if let Some(project) = this.project.as_ref() {
 2054                    let handle = project.update(cx, |project, cx| {
 2055                        project.register_buffer_with_language_servers(&buffer, cx)
 2056                    });
 2057                    this.registered_buffers
 2058                        .insert(buffer.read(cx).remote_id(), handle);
 2059                }
 2060            }
 2061
 2062            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2063        }
 2064
 2065        this.report_editor_event("Editor Opened", None, cx);
 2066        this
 2067    }
 2068
 2069    pub fn deploy_mouse_context_menu(
 2070        &mut self,
 2071        position: gpui::Point<Pixels>,
 2072        context_menu: Entity<ContextMenu>,
 2073        window: &mut Window,
 2074        cx: &mut Context<Self>,
 2075    ) {
 2076        self.mouse_context_menu = Some(MouseContextMenu::new(
 2077            self,
 2078            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2079            context_menu,
 2080            window,
 2081            cx,
 2082        ));
 2083    }
 2084
 2085    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2086        self.mouse_context_menu
 2087            .as_ref()
 2088            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2089    }
 2090
 2091    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2092        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2093    }
 2094
 2095    fn key_context_internal(
 2096        &self,
 2097        has_active_edit_prediction: bool,
 2098        window: &Window,
 2099        cx: &App,
 2100    ) -> KeyContext {
 2101        let mut key_context = KeyContext::new_with_defaults();
 2102        key_context.add("Editor");
 2103        let mode = match self.mode {
 2104            EditorMode::SingleLine { .. } => "single_line",
 2105            EditorMode::AutoHeight { .. } => "auto_height",
 2106            EditorMode::Minimap { .. } => "minimap",
 2107            EditorMode::Full { .. } => "full",
 2108        };
 2109
 2110        if EditorSettings::jupyter_enabled(cx) {
 2111            key_context.add("jupyter");
 2112        }
 2113
 2114        key_context.set("mode", mode);
 2115        if self.pending_rename.is_some() {
 2116            key_context.add("renaming");
 2117        }
 2118
 2119        match self.context_menu.borrow().as_ref() {
 2120            Some(CodeContextMenu::Completions(_)) => {
 2121                key_context.add("menu");
 2122                key_context.add("showing_completions");
 2123            }
 2124            Some(CodeContextMenu::CodeActions(_)) => {
 2125                key_context.add("menu");
 2126                key_context.add("showing_code_actions")
 2127            }
 2128            None => {}
 2129        }
 2130
 2131        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2132        if !self.focus_handle(cx).contains_focused(window, cx)
 2133            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2134        {
 2135            for addon in self.addons.values() {
 2136                addon.extend_key_context(&mut key_context, cx)
 2137            }
 2138        }
 2139
 2140        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2141            if let Some(extension) = singleton_buffer
 2142                .read(cx)
 2143                .file()
 2144                .and_then(|file| file.path().extension()?.to_str())
 2145            {
 2146                key_context.set("extension", extension.to_string());
 2147            }
 2148        } else {
 2149            key_context.add("multibuffer");
 2150        }
 2151
 2152        if has_active_edit_prediction {
 2153            if self.edit_prediction_in_conflict() {
 2154                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2155            } else {
 2156                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2157                key_context.add("copilot_suggestion");
 2158            }
 2159        }
 2160
 2161        if self.selection_mark_mode {
 2162            key_context.add("selection_mode");
 2163        }
 2164
 2165        key_context
 2166    }
 2167
 2168    fn show_mouse_cursor(&mut self) {
 2169        self.mouse_cursor_hidden = false;
 2170    }
 2171
 2172    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2173        self.mouse_cursor_hidden = match origin {
 2174            HideMouseCursorOrigin::TypingAction => {
 2175                matches!(
 2176                    self.hide_mouse_mode,
 2177                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2178                )
 2179            }
 2180            HideMouseCursorOrigin::MovementAction => {
 2181                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2182            }
 2183        };
 2184    }
 2185
 2186    pub fn edit_prediction_in_conflict(&self) -> bool {
 2187        if !self.show_edit_predictions_in_menu() {
 2188            return false;
 2189        }
 2190
 2191        let showing_completions = self
 2192            .context_menu
 2193            .borrow()
 2194            .as_ref()
 2195            .map_or(false, |context| {
 2196                matches!(context, CodeContextMenu::Completions(_))
 2197            });
 2198
 2199        showing_completions
 2200            || self.edit_prediction_requires_modifier()
 2201            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2202            // bindings to insert tab characters.
 2203            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2204    }
 2205
 2206    pub fn accept_edit_prediction_keybind(
 2207        &self,
 2208        window: &Window,
 2209        cx: &App,
 2210    ) -> AcceptEditPredictionBinding {
 2211        let key_context = self.key_context_internal(true, window, cx);
 2212        let in_conflict = self.edit_prediction_in_conflict();
 2213
 2214        AcceptEditPredictionBinding(
 2215            window
 2216                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2217                .into_iter()
 2218                .filter(|binding| {
 2219                    !in_conflict
 2220                        || binding
 2221                            .keystrokes()
 2222                            .first()
 2223                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2224                })
 2225                .rev()
 2226                .min_by_key(|binding| {
 2227                    binding
 2228                        .keystrokes()
 2229                        .first()
 2230                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2231                }),
 2232        )
 2233    }
 2234
 2235    pub fn new_file(
 2236        workspace: &mut Workspace,
 2237        _: &workspace::NewFile,
 2238        window: &mut Window,
 2239        cx: &mut Context<Workspace>,
 2240    ) {
 2241        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2242            "Failed to create buffer",
 2243            window,
 2244            cx,
 2245            |e, _, _| match e.error_code() {
 2246                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2247                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2248                e.error_tag("required").unwrap_or("the latest version")
 2249            )),
 2250                _ => None,
 2251            },
 2252        );
 2253    }
 2254
 2255    pub fn new_in_workspace(
 2256        workspace: &mut Workspace,
 2257        window: &mut Window,
 2258        cx: &mut Context<Workspace>,
 2259    ) -> Task<Result<Entity<Editor>>> {
 2260        let project = workspace.project().clone();
 2261        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2262
 2263        cx.spawn_in(window, async move |workspace, cx| {
 2264            let buffer = create.await?;
 2265            workspace.update_in(cx, |workspace, window, cx| {
 2266                let editor =
 2267                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2268                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2269                editor
 2270            })
 2271        })
 2272    }
 2273
 2274    fn new_file_vertical(
 2275        workspace: &mut Workspace,
 2276        _: &workspace::NewFileSplitVertical,
 2277        window: &mut Window,
 2278        cx: &mut Context<Workspace>,
 2279    ) {
 2280        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2281    }
 2282
 2283    fn new_file_horizontal(
 2284        workspace: &mut Workspace,
 2285        _: &workspace::NewFileSplitHorizontal,
 2286        window: &mut Window,
 2287        cx: &mut Context<Workspace>,
 2288    ) {
 2289        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2290    }
 2291
 2292    fn new_file_in_direction(
 2293        workspace: &mut Workspace,
 2294        direction: SplitDirection,
 2295        window: &mut Window,
 2296        cx: &mut Context<Workspace>,
 2297    ) {
 2298        let project = workspace.project().clone();
 2299        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2300
 2301        cx.spawn_in(window, async move |workspace, cx| {
 2302            let buffer = create.await?;
 2303            workspace.update_in(cx, move |workspace, window, cx| {
 2304                workspace.split_item(
 2305                    direction,
 2306                    Box::new(
 2307                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2308                    ),
 2309                    window,
 2310                    cx,
 2311                )
 2312            })?;
 2313            anyhow::Ok(())
 2314        })
 2315        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2316            match e.error_code() {
 2317                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2318                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2319                e.error_tag("required").unwrap_or("the latest version")
 2320            )),
 2321                _ => None,
 2322            }
 2323        });
 2324    }
 2325
 2326    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2327        self.leader_id
 2328    }
 2329
 2330    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2331        &self.buffer
 2332    }
 2333
 2334    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2335        self.workspace.as_ref()?.0.upgrade()
 2336    }
 2337
 2338    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2339        self.buffer().read(cx).title(cx)
 2340    }
 2341
 2342    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2343        let git_blame_gutter_max_author_length = self
 2344            .render_git_blame_gutter(cx)
 2345            .then(|| {
 2346                if let Some(blame) = self.blame.as_ref() {
 2347                    let max_author_length =
 2348                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2349                    Some(max_author_length)
 2350                } else {
 2351                    None
 2352                }
 2353            })
 2354            .flatten();
 2355
 2356        EditorSnapshot {
 2357            mode: self.mode.clone(),
 2358            show_gutter: self.show_gutter,
 2359            show_line_numbers: self.show_line_numbers,
 2360            show_git_diff_gutter: self.show_git_diff_gutter,
 2361            show_code_actions: self.show_code_actions,
 2362            show_runnables: self.show_runnables,
 2363            show_breakpoints: self.show_breakpoints,
 2364            git_blame_gutter_max_author_length,
 2365            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2366            scroll_anchor: self.scroll_manager.anchor(),
 2367            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2368            placeholder_text: self.placeholder_text.clone(),
 2369            is_focused: self.focus_handle.is_focused(window),
 2370            current_line_highlight: self
 2371                .current_line_highlight
 2372                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2373            gutter_hovered: self.gutter_hovered,
 2374        }
 2375    }
 2376
 2377    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2378        self.buffer.read(cx).language_at(point, cx)
 2379    }
 2380
 2381    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2382        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2383    }
 2384
 2385    pub fn active_excerpt(
 2386        &self,
 2387        cx: &App,
 2388    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2389        self.buffer
 2390            .read(cx)
 2391            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2392    }
 2393
 2394    pub fn mode(&self) -> &EditorMode {
 2395        &self.mode
 2396    }
 2397
 2398    pub fn set_mode(&mut self, mode: EditorMode) {
 2399        self.mode = mode;
 2400    }
 2401
 2402    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2403        self.collaboration_hub.as_deref()
 2404    }
 2405
 2406    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2407        self.collaboration_hub = Some(hub);
 2408    }
 2409
 2410    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2411        self.in_project_search = in_project_search;
 2412    }
 2413
 2414    pub fn set_custom_context_menu(
 2415        &mut self,
 2416        f: impl 'static
 2417        + Fn(
 2418            &mut Self,
 2419            DisplayPoint,
 2420            &mut Window,
 2421            &mut Context<Self>,
 2422        ) -> Option<Entity<ui::ContextMenu>>,
 2423    ) {
 2424        self.custom_context_menu = Some(Box::new(f))
 2425    }
 2426
 2427    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2428        self.completion_provider = provider;
 2429    }
 2430
 2431    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2432        self.semantics_provider.clone()
 2433    }
 2434
 2435    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2436        self.semantics_provider = provider;
 2437    }
 2438
 2439    pub fn set_edit_prediction_provider<T>(
 2440        &mut self,
 2441        provider: Option<Entity<T>>,
 2442        window: &mut Window,
 2443        cx: &mut Context<Self>,
 2444    ) where
 2445        T: EditPredictionProvider,
 2446    {
 2447        self.edit_prediction_provider =
 2448            provider.map(|provider| RegisteredInlineCompletionProvider {
 2449                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2450                    if this.focus_handle.is_focused(window) {
 2451                        this.update_visible_inline_completion(window, cx);
 2452                    }
 2453                }),
 2454                provider: Arc::new(provider),
 2455            });
 2456        self.update_edit_prediction_settings(cx);
 2457        self.refresh_inline_completion(false, false, window, cx);
 2458    }
 2459
 2460    pub fn placeholder_text(&self) -> Option<&str> {
 2461        self.placeholder_text.as_deref()
 2462    }
 2463
 2464    pub fn set_placeholder_text(
 2465        &mut self,
 2466        placeholder_text: impl Into<Arc<str>>,
 2467        cx: &mut Context<Self>,
 2468    ) {
 2469        let placeholder_text = Some(placeholder_text.into());
 2470        if self.placeholder_text != placeholder_text {
 2471            self.placeholder_text = placeholder_text;
 2472            cx.notify();
 2473        }
 2474    }
 2475
 2476    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2477        self.cursor_shape = cursor_shape;
 2478
 2479        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2480        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2481
 2482        cx.notify();
 2483    }
 2484
 2485    pub fn set_current_line_highlight(
 2486        &mut self,
 2487        current_line_highlight: Option<CurrentLineHighlight>,
 2488    ) {
 2489        self.current_line_highlight = current_line_highlight;
 2490    }
 2491
 2492    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2493        self.collapse_matches = collapse_matches;
 2494    }
 2495
 2496    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2497        let buffers = self.buffer.read(cx).all_buffers();
 2498        let Some(project) = self.project.as_ref() else {
 2499            return;
 2500        };
 2501        project.update(cx, |project, cx| {
 2502            for buffer in buffers {
 2503                self.registered_buffers
 2504                    .entry(buffer.read(cx).remote_id())
 2505                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2506            }
 2507        })
 2508    }
 2509
 2510    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2511        if self.collapse_matches {
 2512            return range.start..range.start;
 2513        }
 2514        range.clone()
 2515    }
 2516
 2517    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2518        if self.display_map.read(cx).clip_at_line_ends != clip {
 2519            self.display_map
 2520                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2521        }
 2522    }
 2523
 2524    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2525        self.input_enabled = input_enabled;
 2526    }
 2527
 2528    pub fn set_inline_completions_hidden_for_vim_mode(
 2529        &mut self,
 2530        hidden: bool,
 2531        window: &mut Window,
 2532        cx: &mut Context<Self>,
 2533    ) {
 2534        if hidden != self.inline_completions_hidden_for_vim_mode {
 2535            self.inline_completions_hidden_for_vim_mode = hidden;
 2536            if hidden {
 2537                self.update_visible_inline_completion(window, cx);
 2538            } else {
 2539                self.refresh_inline_completion(true, false, window, cx);
 2540            }
 2541        }
 2542    }
 2543
 2544    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2545        self.menu_inline_completions_policy = value;
 2546    }
 2547
 2548    pub fn set_autoindent(&mut self, autoindent: bool) {
 2549        if autoindent {
 2550            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2551        } else {
 2552            self.autoindent_mode = None;
 2553        }
 2554    }
 2555
 2556    pub fn read_only(&self, cx: &App) -> bool {
 2557        self.read_only || self.buffer.read(cx).read_only()
 2558    }
 2559
 2560    pub fn set_read_only(&mut self, read_only: bool) {
 2561        self.read_only = read_only;
 2562    }
 2563
 2564    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2565        self.use_autoclose = autoclose;
 2566    }
 2567
 2568    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2569        self.use_auto_surround = auto_surround;
 2570    }
 2571
 2572    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2573        self.auto_replace_emoji_shortcode = auto_replace;
 2574    }
 2575
 2576    pub fn toggle_edit_predictions(
 2577        &mut self,
 2578        _: &ToggleEditPrediction,
 2579        window: &mut Window,
 2580        cx: &mut Context<Self>,
 2581    ) {
 2582        if self.show_inline_completions_override.is_some() {
 2583            self.set_show_edit_predictions(None, window, cx);
 2584        } else {
 2585            let show_edit_predictions = !self.edit_predictions_enabled();
 2586            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2587        }
 2588    }
 2589
 2590    pub fn set_show_edit_predictions(
 2591        &mut self,
 2592        show_edit_predictions: Option<bool>,
 2593        window: &mut Window,
 2594        cx: &mut Context<Self>,
 2595    ) {
 2596        self.show_inline_completions_override = show_edit_predictions;
 2597        self.update_edit_prediction_settings(cx);
 2598
 2599        if let Some(false) = show_edit_predictions {
 2600            self.discard_inline_completion(false, cx);
 2601        } else {
 2602            self.refresh_inline_completion(false, true, window, cx);
 2603        }
 2604    }
 2605
 2606    fn inline_completions_disabled_in_scope(
 2607        &self,
 2608        buffer: &Entity<Buffer>,
 2609        buffer_position: language::Anchor,
 2610        cx: &App,
 2611    ) -> bool {
 2612        let snapshot = buffer.read(cx).snapshot();
 2613        let settings = snapshot.settings_at(buffer_position, cx);
 2614
 2615        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2616            return false;
 2617        };
 2618
 2619        scope.override_name().map_or(false, |scope_name| {
 2620            settings
 2621                .edit_predictions_disabled_in
 2622                .iter()
 2623                .any(|s| s == scope_name)
 2624        })
 2625    }
 2626
 2627    pub fn set_use_modal_editing(&mut self, to: bool) {
 2628        self.use_modal_editing = to;
 2629    }
 2630
 2631    pub fn use_modal_editing(&self) -> bool {
 2632        self.use_modal_editing
 2633    }
 2634
 2635    fn selections_did_change(
 2636        &mut self,
 2637        local: bool,
 2638        old_cursor_position: &Anchor,
 2639        show_completions: bool,
 2640        window: &mut Window,
 2641        cx: &mut Context<Self>,
 2642    ) {
 2643        window.invalidate_character_coordinates();
 2644
 2645        // Copy selections to primary selection buffer
 2646        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2647        if local {
 2648            let selections = self.selections.all::<usize>(cx);
 2649            let buffer_handle = self.buffer.read(cx).read(cx);
 2650
 2651            let mut text = String::new();
 2652            for (index, selection) in selections.iter().enumerate() {
 2653                let text_for_selection = buffer_handle
 2654                    .text_for_range(selection.start..selection.end)
 2655                    .collect::<String>();
 2656
 2657                text.push_str(&text_for_selection);
 2658                if index != selections.len() - 1 {
 2659                    text.push('\n');
 2660                }
 2661            }
 2662
 2663            if !text.is_empty() {
 2664                cx.write_to_primary(ClipboardItem::new_string(text));
 2665            }
 2666        }
 2667
 2668        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2669            self.buffer.update(cx, |buffer, cx| {
 2670                buffer.set_active_selections(
 2671                    &self.selections.disjoint_anchors(),
 2672                    self.selections.line_mode,
 2673                    self.cursor_shape,
 2674                    cx,
 2675                )
 2676            });
 2677        }
 2678        let display_map = self
 2679            .display_map
 2680            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2681        let buffer = &display_map.buffer_snapshot;
 2682        self.add_selections_state = None;
 2683        self.select_next_state = None;
 2684        self.select_prev_state = None;
 2685        self.select_syntax_node_history.try_clear();
 2686        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2687        self.snippet_stack
 2688            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2689        self.take_rename(false, window, cx);
 2690
 2691        let new_cursor_position = self.selections.newest_anchor().head();
 2692
 2693        self.push_to_nav_history(
 2694            *old_cursor_position,
 2695            Some(new_cursor_position.to_point(buffer)),
 2696            false,
 2697            cx,
 2698        );
 2699
 2700        if local {
 2701            let new_cursor_position = self.selections.newest_anchor().head();
 2702            let mut context_menu = self.context_menu.borrow_mut();
 2703            let completion_menu = match context_menu.as_ref() {
 2704                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2705                _ => {
 2706                    *context_menu = None;
 2707                    None
 2708                }
 2709            };
 2710            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2711                if !self.registered_buffers.contains_key(&buffer_id) {
 2712                    if let Some(project) = self.project.as_ref() {
 2713                        project.update(cx, |project, cx| {
 2714                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2715                                return;
 2716                            };
 2717                            self.registered_buffers.insert(
 2718                                buffer_id,
 2719                                project.register_buffer_with_language_servers(&buffer, cx),
 2720                            );
 2721                        })
 2722                    }
 2723                }
 2724            }
 2725
 2726            if let Some(completion_menu) = completion_menu {
 2727                let cursor_position = new_cursor_position.to_offset(buffer);
 2728                let (word_range, kind) =
 2729                    buffer.surrounding_word(completion_menu.initial_position, true);
 2730                if kind == Some(CharKind::Word)
 2731                    && word_range.to_inclusive().contains(&cursor_position)
 2732                {
 2733                    let mut completion_menu = completion_menu.clone();
 2734                    drop(context_menu);
 2735
 2736                    let query = Self::completion_query(buffer, cursor_position);
 2737                    let completion_provider = self.completion_provider.clone();
 2738                    cx.spawn_in(window, async move |this, cx| {
 2739                        completion_menu
 2740                            .filter(query.as_deref(), completion_provider, this.clone(), cx)
 2741                            .await;
 2742
 2743                        this.update(cx, |this, cx| {
 2744                            let mut context_menu = this.context_menu.borrow_mut();
 2745                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2746                            else {
 2747                                return;
 2748                            };
 2749
 2750                            if menu.id > completion_menu.id {
 2751                                return;
 2752                            }
 2753
 2754                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2755                            drop(context_menu);
 2756                            cx.notify();
 2757                        })
 2758                    })
 2759                    .detach();
 2760
 2761                    if show_completions {
 2762                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2763                    }
 2764                } else {
 2765                    drop(context_menu);
 2766                    self.hide_context_menu(window, cx);
 2767                }
 2768            } else {
 2769                drop(context_menu);
 2770            }
 2771
 2772            hide_hover(self, cx);
 2773
 2774            if old_cursor_position.to_display_point(&display_map).row()
 2775                != new_cursor_position.to_display_point(&display_map).row()
 2776            {
 2777                self.available_code_actions.take();
 2778            }
 2779            self.refresh_code_actions(window, cx);
 2780            self.refresh_document_highlights(cx);
 2781            self.refresh_selected_text_highlights(false, window, cx);
 2782            refresh_matching_bracket_highlights(self, window, cx);
 2783            self.update_visible_inline_completion(window, cx);
 2784            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2785            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2786            self.inline_blame_popover.take();
 2787            if self.git_blame_inline_enabled {
 2788                self.start_inline_blame_timer(window, cx);
 2789            }
 2790        }
 2791
 2792        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2793        cx.emit(EditorEvent::SelectionsChanged { local });
 2794
 2795        let selections = &self.selections.disjoint;
 2796        if selections.len() == 1 {
 2797            cx.emit(SearchEvent::ActiveMatchChanged)
 2798        }
 2799        if local {
 2800            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2801                let inmemory_selections = selections
 2802                    .iter()
 2803                    .map(|s| {
 2804                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2805                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2806                    })
 2807                    .collect();
 2808                self.update_restoration_data(cx, |data| {
 2809                    data.selections = inmemory_selections;
 2810                });
 2811
 2812                if WorkspaceSettings::get(None, cx).restore_on_startup
 2813                    != RestoreOnStartupBehavior::None
 2814                {
 2815                    if let Some(workspace_id) =
 2816                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2817                    {
 2818                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2819                        let selections = selections.clone();
 2820                        let background_executor = cx.background_executor().clone();
 2821                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2822                        self.serialize_selections = cx.background_spawn(async move {
 2823                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2824                    let db_selections = selections
 2825                        .iter()
 2826                        .map(|selection| {
 2827                            (
 2828                                selection.start.to_offset(&snapshot),
 2829                                selection.end.to_offset(&snapshot),
 2830                            )
 2831                        })
 2832                        .collect();
 2833
 2834                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2835                        .await
 2836                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2837                        .log_err();
 2838                });
 2839                    }
 2840                }
 2841            }
 2842        }
 2843
 2844        cx.notify();
 2845    }
 2846
 2847    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2848        use text::ToOffset as _;
 2849        use text::ToPoint as _;
 2850
 2851        if self.mode.is_minimap()
 2852            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2853        {
 2854            return;
 2855        }
 2856
 2857        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2858            return;
 2859        };
 2860
 2861        let snapshot = singleton.read(cx).snapshot();
 2862        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2863            let display_snapshot = display_map.snapshot(cx);
 2864
 2865            display_snapshot
 2866                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2867                .map(|fold| {
 2868                    fold.range.start.text_anchor.to_point(&snapshot)
 2869                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2870                })
 2871                .collect()
 2872        });
 2873        self.update_restoration_data(cx, |data| {
 2874            data.folds = inmemory_folds;
 2875        });
 2876
 2877        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2878            return;
 2879        };
 2880        let background_executor = cx.background_executor().clone();
 2881        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2882        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2883            display_map
 2884                .snapshot(cx)
 2885                .folds_in_range(0..snapshot.len())
 2886                .map(|fold| {
 2887                    (
 2888                        fold.range.start.text_anchor.to_offset(&snapshot),
 2889                        fold.range.end.text_anchor.to_offset(&snapshot),
 2890                    )
 2891                })
 2892                .collect()
 2893        });
 2894        self.serialize_folds = cx.background_spawn(async move {
 2895            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2896            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2897                .await
 2898                .with_context(|| {
 2899                    format!(
 2900                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2901                    )
 2902                })
 2903                .log_err();
 2904        });
 2905    }
 2906
 2907    pub fn sync_selections(
 2908        &mut self,
 2909        other: Entity<Editor>,
 2910        cx: &mut Context<Self>,
 2911    ) -> gpui::Subscription {
 2912        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2913        self.selections.change_with(cx, |selections| {
 2914            selections.select_anchors(other_selections);
 2915        });
 2916
 2917        let other_subscription =
 2918            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2919                EditorEvent::SelectionsChanged { local: true } => {
 2920                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2921                    if other_selections.is_empty() {
 2922                        return;
 2923                    }
 2924                    this.selections.change_with(cx, |selections| {
 2925                        selections.select_anchors(other_selections);
 2926                    });
 2927                }
 2928                _ => {}
 2929            });
 2930
 2931        let this_subscription =
 2932            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2933                EditorEvent::SelectionsChanged { local: true } => {
 2934                    let these_selections = this.selections.disjoint.to_vec();
 2935                    if these_selections.is_empty() {
 2936                        return;
 2937                    }
 2938                    other.update(cx, |other_editor, cx| {
 2939                        other_editor.selections.change_with(cx, |selections| {
 2940                            selections.select_anchors(these_selections);
 2941                        })
 2942                    });
 2943                }
 2944                _ => {}
 2945            });
 2946
 2947        Subscription::join(other_subscription, this_subscription)
 2948    }
 2949
 2950    pub fn change_selections<R>(
 2951        &mut self,
 2952        autoscroll: Option<Autoscroll>,
 2953        window: &mut Window,
 2954        cx: &mut Context<Self>,
 2955        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2956    ) -> R {
 2957        self.change_selections_inner(autoscroll, true, window, cx, change)
 2958    }
 2959
 2960    fn change_selections_inner<R>(
 2961        &mut self,
 2962        autoscroll: Option<Autoscroll>,
 2963        request_completions: bool,
 2964        window: &mut Window,
 2965        cx: &mut Context<Self>,
 2966        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2967    ) -> R {
 2968        let old_cursor_position = self.selections.newest_anchor().head();
 2969        self.push_to_selection_history();
 2970
 2971        let (changed, result) = self.selections.change_with(cx, change);
 2972
 2973        if changed {
 2974            if let Some(autoscroll) = autoscroll {
 2975                self.request_autoscroll(autoscroll, cx);
 2976            }
 2977            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2978
 2979            if self.should_open_signature_help_automatically(
 2980                &old_cursor_position,
 2981                self.signature_help_state.backspace_pressed(),
 2982                cx,
 2983            ) {
 2984                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2985            }
 2986            self.signature_help_state.set_backspace_pressed(false);
 2987        }
 2988
 2989        result
 2990    }
 2991
 2992    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2993    where
 2994        I: IntoIterator<Item = (Range<S>, T)>,
 2995        S: ToOffset,
 2996        T: Into<Arc<str>>,
 2997    {
 2998        if self.read_only(cx) {
 2999            return;
 3000        }
 3001
 3002        self.buffer
 3003            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3004    }
 3005
 3006    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3007    where
 3008        I: IntoIterator<Item = (Range<S>, T)>,
 3009        S: ToOffset,
 3010        T: Into<Arc<str>>,
 3011    {
 3012        if self.read_only(cx) {
 3013            return;
 3014        }
 3015
 3016        self.buffer.update(cx, |buffer, cx| {
 3017            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3018        });
 3019    }
 3020
 3021    pub fn edit_with_block_indent<I, S, T>(
 3022        &mut self,
 3023        edits: I,
 3024        original_indent_columns: Vec<Option<u32>>,
 3025        cx: &mut Context<Self>,
 3026    ) where
 3027        I: IntoIterator<Item = (Range<S>, T)>,
 3028        S: ToOffset,
 3029        T: Into<Arc<str>>,
 3030    {
 3031        if self.read_only(cx) {
 3032            return;
 3033        }
 3034
 3035        self.buffer.update(cx, |buffer, cx| {
 3036            buffer.edit(
 3037                edits,
 3038                Some(AutoindentMode::Block {
 3039                    original_indent_columns,
 3040                }),
 3041                cx,
 3042            )
 3043        });
 3044    }
 3045
 3046    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3047        self.hide_context_menu(window, cx);
 3048
 3049        match phase {
 3050            SelectPhase::Begin {
 3051                position,
 3052                add,
 3053                click_count,
 3054            } => self.begin_selection(position, add, click_count, window, cx),
 3055            SelectPhase::BeginColumnar {
 3056                position,
 3057                goal_column,
 3058                reset,
 3059            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3060            SelectPhase::Extend {
 3061                position,
 3062                click_count,
 3063            } => self.extend_selection(position, click_count, window, cx),
 3064            SelectPhase::Update {
 3065                position,
 3066                goal_column,
 3067                scroll_delta,
 3068            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3069            SelectPhase::End => self.end_selection(window, cx),
 3070        }
 3071    }
 3072
 3073    fn extend_selection(
 3074        &mut self,
 3075        position: DisplayPoint,
 3076        click_count: usize,
 3077        window: &mut Window,
 3078        cx: &mut Context<Self>,
 3079    ) {
 3080        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3081        let tail = self.selections.newest::<usize>(cx).tail();
 3082        self.begin_selection(position, false, click_count, window, cx);
 3083
 3084        let position = position.to_offset(&display_map, Bias::Left);
 3085        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3086
 3087        let mut pending_selection = self
 3088            .selections
 3089            .pending_anchor()
 3090            .expect("extend_selection not called with pending selection");
 3091        if position >= tail {
 3092            pending_selection.start = tail_anchor;
 3093        } else {
 3094            pending_selection.end = tail_anchor;
 3095            pending_selection.reversed = true;
 3096        }
 3097
 3098        let mut pending_mode = self.selections.pending_mode().unwrap();
 3099        match &mut pending_mode {
 3100            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3101            _ => {}
 3102        }
 3103
 3104        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3105
 3106        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3107            s.set_pending(pending_selection, pending_mode)
 3108        });
 3109    }
 3110
 3111    fn begin_selection(
 3112        &mut self,
 3113        position: DisplayPoint,
 3114        add: bool,
 3115        click_count: usize,
 3116        window: &mut Window,
 3117        cx: &mut Context<Self>,
 3118    ) {
 3119        if !self.focus_handle.is_focused(window) {
 3120            self.last_focused_descendant = None;
 3121            window.focus(&self.focus_handle);
 3122        }
 3123
 3124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3125        let buffer = &display_map.buffer_snapshot;
 3126        let position = display_map.clip_point(position, Bias::Left);
 3127
 3128        let start;
 3129        let end;
 3130        let mode;
 3131        let mut auto_scroll;
 3132        match click_count {
 3133            1 => {
 3134                start = buffer.anchor_before(position.to_point(&display_map));
 3135                end = start;
 3136                mode = SelectMode::Character;
 3137                auto_scroll = true;
 3138            }
 3139            2 => {
 3140                let range = movement::surrounding_word(&display_map, position);
 3141                start = buffer.anchor_before(range.start.to_point(&display_map));
 3142                end = buffer.anchor_before(range.end.to_point(&display_map));
 3143                mode = SelectMode::Word(start..end);
 3144                auto_scroll = true;
 3145            }
 3146            3 => {
 3147                let position = display_map
 3148                    .clip_point(position, Bias::Left)
 3149                    .to_point(&display_map);
 3150                let line_start = display_map.prev_line_boundary(position).0;
 3151                let next_line_start = buffer.clip_point(
 3152                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3153                    Bias::Left,
 3154                );
 3155                start = buffer.anchor_before(line_start);
 3156                end = buffer.anchor_before(next_line_start);
 3157                mode = SelectMode::Line(start..end);
 3158                auto_scroll = true;
 3159            }
 3160            _ => {
 3161                start = buffer.anchor_before(0);
 3162                end = buffer.anchor_before(buffer.len());
 3163                mode = SelectMode::All;
 3164                auto_scroll = false;
 3165            }
 3166        }
 3167        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3168
 3169        let point_to_delete: Option<usize> = {
 3170            let selected_points: Vec<Selection<Point>> =
 3171                self.selections.disjoint_in_range(start..end, cx);
 3172
 3173            if !add || click_count > 1 {
 3174                None
 3175            } else if !selected_points.is_empty() {
 3176                Some(selected_points[0].id)
 3177            } else {
 3178                let clicked_point_already_selected =
 3179                    self.selections.disjoint.iter().find(|selection| {
 3180                        selection.start.to_point(buffer) == start.to_point(buffer)
 3181                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3182                    });
 3183
 3184                clicked_point_already_selected.map(|selection| selection.id)
 3185            }
 3186        };
 3187
 3188        let selections_count = self.selections.count();
 3189
 3190        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3191            if let Some(point_to_delete) = point_to_delete {
 3192                s.delete(point_to_delete);
 3193
 3194                if selections_count == 1 {
 3195                    s.set_pending_anchor_range(start..end, mode);
 3196                }
 3197            } else {
 3198                if !add {
 3199                    s.clear_disjoint();
 3200                }
 3201
 3202                s.set_pending_anchor_range(start..end, mode);
 3203            }
 3204        });
 3205    }
 3206
 3207    fn begin_columnar_selection(
 3208        &mut self,
 3209        position: DisplayPoint,
 3210        goal_column: u32,
 3211        reset: bool,
 3212        window: &mut Window,
 3213        cx: &mut Context<Self>,
 3214    ) {
 3215        if !self.focus_handle.is_focused(window) {
 3216            self.last_focused_descendant = None;
 3217            window.focus(&self.focus_handle);
 3218        }
 3219
 3220        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3221
 3222        if reset {
 3223            let pointer_position = display_map
 3224                .buffer_snapshot
 3225                .anchor_before(position.to_point(&display_map));
 3226
 3227            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3228                s.clear_disjoint();
 3229                s.set_pending_anchor_range(
 3230                    pointer_position..pointer_position,
 3231                    SelectMode::Character,
 3232                );
 3233            });
 3234        }
 3235
 3236        let tail = self.selections.newest::<Point>(cx).tail();
 3237        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3238
 3239        if !reset {
 3240            self.select_columns(
 3241                tail.to_display_point(&display_map),
 3242                position,
 3243                goal_column,
 3244                &display_map,
 3245                window,
 3246                cx,
 3247            );
 3248        }
 3249    }
 3250
 3251    fn update_selection(
 3252        &mut self,
 3253        position: DisplayPoint,
 3254        goal_column: u32,
 3255        scroll_delta: gpui::Point<f32>,
 3256        window: &mut Window,
 3257        cx: &mut Context<Self>,
 3258    ) {
 3259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3260
 3261        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3262            let tail = tail.to_display_point(&display_map);
 3263            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3264        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3265            let buffer = self.buffer.read(cx).snapshot(cx);
 3266            let head;
 3267            let tail;
 3268            let mode = self.selections.pending_mode().unwrap();
 3269            match &mode {
 3270                SelectMode::Character => {
 3271                    head = position.to_point(&display_map);
 3272                    tail = pending.tail().to_point(&buffer);
 3273                }
 3274                SelectMode::Word(original_range) => {
 3275                    let original_display_range = original_range.start.to_display_point(&display_map)
 3276                        ..original_range.end.to_display_point(&display_map);
 3277                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3278                        ..original_display_range.end.to_point(&display_map);
 3279                    if movement::is_inside_word(&display_map, position)
 3280                        || original_display_range.contains(&position)
 3281                    {
 3282                        let word_range = movement::surrounding_word(&display_map, position);
 3283                        if word_range.start < original_display_range.start {
 3284                            head = word_range.start.to_point(&display_map);
 3285                        } else {
 3286                            head = word_range.end.to_point(&display_map);
 3287                        }
 3288                    } else {
 3289                        head = position.to_point(&display_map);
 3290                    }
 3291
 3292                    if head <= original_buffer_range.start {
 3293                        tail = original_buffer_range.end;
 3294                    } else {
 3295                        tail = original_buffer_range.start;
 3296                    }
 3297                }
 3298                SelectMode::Line(original_range) => {
 3299                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3300
 3301                    let position = display_map
 3302                        .clip_point(position, Bias::Left)
 3303                        .to_point(&display_map);
 3304                    let line_start = display_map.prev_line_boundary(position).0;
 3305                    let next_line_start = buffer.clip_point(
 3306                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3307                        Bias::Left,
 3308                    );
 3309
 3310                    if line_start < original_range.start {
 3311                        head = line_start
 3312                    } else {
 3313                        head = next_line_start
 3314                    }
 3315
 3316                    if head <= original_range.start {
 3317                        tail = original_range.end;
 3318                    } else {
 3319                        tail = original_range.start;
 3320                    }
 3321                }
 3322                SelectMode::All => {
 3323                    return;
 3324                }
 3325            };
 3326
 3327            if head < tail {
 3328                pending.start = buffer.anchor_before(head);
 3329                pending.end = buffer.anchor_before(tail);
 3330                pending.reversed = true;
 3331            } else {
 3332                pending.start = buffer.anchor_before(tail);
 3333                pending.end = buffer.anchor_before(head);
 3334                pending.reversed = false;
 3335            }
 3336
 3337            self.change_selections(None, window, cx, |s| {
 3338                s.set_pending(pending, mode);
 3339            });
 3340        } else {
 3341            log::error!("update_selection dispatched with no pending selection");
 3342            return;
 3343        }
 3344
 3345        self.apply_scroll_delta(scroll_delta, window, cx);
 3346        cx.notify();
 3347    }
 3348
 3349    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3350        self.columnar_selection_tail.take();
 3351        if self.selections.pending_anchor().is_some() {
 3352            let selections = self.selections.all::<usize>(cx);
 3353            self.change_selections(None, window, cx, |s| {
 3354                s.select(selections);
 3355                s.clear_pending();
 3356            });
 3357        }
 3358    }
 3359
 3360    fn select_columns(
 3361        &mut self,
 3362        tail: DisplayPoint,
 3363        head: DisplayPoint,
 3364        goal_column: u32,
 3365        display_map: &DisplaySnapshot,
 3366        window: &mut Window,
 3367        cx: &mut Context<Self>,
 3368    ) {
 3369        let start_row = cmp::min(tail.row(), head.row());
 3370        let end_row = cmp::max(tail.row(), head.row());
 3371        let start_column = cmp::min(tail.column(), goal_column);
 3372        let end_column = cmp::max(tail.column(), goal_column);
 3373        let reversed = start_column < tail.column();
 3374
 3375        let selection_ranges = (start_row.0..=end_row.0)
 3376            .map(DisplayRow)
 3377            .filter_map(|row| {
 3378                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3379                    let start = display_map
 3380                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3381                        .to_point(display_map);
 3382                    let end = display_map
 3383                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3384                        .to_point(display_map);
 3385                    if reversed {
 3386                        Some(end..start)
 3387                    } else {
 3388                        Some(start..end)
 3389                    }
 3390                } else {
 3391                    None
 3392                }
 3393            })
 3394            .collect::<Vec<_>>();
 3395
 3396        self.change_selections(None, window, cx, |s| {
 3397            s.select_ranges(selection_ranges);
 3398        });
 3399        cx.notify();
 3400    }
 3401
 3402    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3403        self.selections
 3404            .all_adjusted(cx)
 3405            .iter()
 3406            .any(|selection| !selection.is_empty())
 3407    }
 3408
 3409    pub fn has_pending_nonempty_selection(&self) -> bool {
 3410        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3411            Some(Selection { start, end, .. }) => start != end,
 3412            None => false,
 3413        };
 3414
 3415        pending_nonempty_selection
 3416            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3417    }
 3418
 3419    pub fn has_pending_selection(&self) -> bool {
 3420        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3421    }
 3422
 3423    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3424        self.selection_mark_mode = false;
 3425
 3426        if self.clear_expanded_diff_hunks(cx) {
 3427            cx.notify();
 3428            return;
 3429        }
 3430        if self.dismiss_menus_and_popups(true, window, cx) {
 3431            return;
 3432        }
 3433
 3434        if self.mode.is_full()
 3435            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3436        {
 3437            return;
 3438        }
 3439
 3440        cx.propagate();
 3441    }
 3442
 3443    pub fn dismiss_menus_and_popups(
 3444        &mut self,
 3445        is_user_requested: bool,
 3446        window: &mut Window,
 3447        cx: &mut Context<Self>,
 3448    ) -> bool {
 3449        if self.take_rename(false, window, cx).is_some() {
 3450            return true;
 3451        }
 3452
 3453        if hide_hover(self, cx) {
 3454            return true;
 3455        }
 3456
 3457        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3458            return true;
 3459        }
 3460
 3461        if self.hide_context_menu(window, cx).is_some() {
 3462            return true;
 3463        }
 3464
 3465        if self.mouse_context_menu.take().is_some() {
 3466            return true;
 3467        }
 3468
 3469        if is_user_requested && self.discard_inline_completion(true, cx) {
 3470            return true;
 3471        }
 3472
 3473        if self.snippet_stack.pop().is_some() {
 3474            return true;
 3475        }
 3476
 3477        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3478            self.dismiss_diagnostics(cx);
 3479            return true;
 3480        }
 3481
 3482        false
 3483    }
 3484
 3485    fn linked_editing_ranges_for(
 3486        &self,
 3487        selection: Range<text::Anchor>,
 3488        cx: &App,
 3489    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3490        if self.linked_edit_ranges.is_empty() {
 3491            return None;
 3492        }
 3493        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3494            selection.end.buffer_id.and_then(|end_buffer_id| {
 3495                if selection.start.buffer_id != Some(end_buffer_id) {
 3496                    return None;
 3497                }
 3498                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3499                let snapshot = buffer.read(cx).snapshot();
 3500                self.linked_edit_ranges
 3501                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3502                    .map(|ranges| (ranges, snapshot, buffer))
 3503            })?;
 3504        use text::ToOffset as TO;
 3505        // find offset from the start of current range to current cursor position
 3506        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3507
 3508        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3509        let start_difference = start_offset - start_byte_offset;
 3510        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3511        let end_difference = end_offset - start_byte_offset;
 3512        // Current range has associated linked ranges.
 3513        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3514        for range in linked_ranges.iter() {
 3515            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3516            let end_offset = start_offset + end_difference;
 3517            let start_offset = start_offset + start_difference;
 3518            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3519                continue;
 3520            }
 3521            if self.selections.disjoint_anchor_ranges().any(|s| {
 3522                if s.start.buffer_id != selection.start.buffer_id
 3523                    || s.end.buffer_id != selection.end.buffer_id
 3524                {
 3525                    return false;
 3526                }
 3527                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3528                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3529            }) {
 3530                continue;
 3531            }
 3532            let start = buffer_snapshot.anchor_after(start_offset);
 3533            let end = buffer_snapshot.anchor_after(end_offset);
 3534            linked_edits
 3535                .entry(buffer.clone())
 3536                .or_default()
 3537                .push(start..end);
 3538        }
 3539        Some(linked_edits)
 3540    }
 3541
 3542    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3543        let text: Arc<str> = text.into();
 3544
 3545        if self.read_only(cx) {
 3546            return;
 3547        }
 3548
 3549        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3550
 3551        let selections = self.selections.all_adjusted(cx);
 3552        let mut bracket_inserted = false;
 3553        let mut edits = Vec::new();
 3554        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3555        let mut new_selections = Vec::with_capacity(selections.len());
 3556        let mut new_autoclose_regions = Vec::new();
 3557        let snapshot = self.buffer.read(cx).read(cx);
 3558        let mut clear_linked_edit_ranges = false;
 3559
 3560        for (selection, autoclose_region) in
 3561            self.selections_with_autoclose_regions(selections, &snapshot)
 3562        {
 3563            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3564                // Determine if the inserted text matches the opening or closing
 3565                // bracket of any of this language's bracket pairs.
 3566                let mut bracket_pair = None;
 3567                let mut is_bracket_pair_start = false;
 3568                let mut is_bracket_pair_end = false;
 3569                if !text.is_empty() {
 3570                    let mut bracket_pair_matching_end = None;
 3571                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3572                    //  and they are removing the character that triggered IME popup.
 3573                    for (pair, enabled) in scope.brackets() {
 3574                        if !pair.close && !pair.surround {
 3575                            continue;
 3576                        }
 3577
 3578                        if enabled && pair.start.ends_with(text.as_ref()) {
 3579                            let prefix_len = pair.start.len() - text.len();
 3580                            let preceding_text_matches_prefix = prefix_len == 0
 3581                                || (selection.start.column >= (prefix_len as u32)
 3582                                    && snapshot.contains_str_at(
 3583                                        Point::new(
 3584                                            selection.start.row,
 3585                                            selection.start.column - (prefix_len as u32),
 3586                                        ),
 3587                                        &pair.start[..prefix_len],
 3588                                    ));
 3589                            if preceding_text_matches_prefix {
 3590                                bracket_pair = Some(pair.clone());
 3591                                is_bracket_pair_start = true;
 3592                                break;
 3593                            }
 3594                        }
 3595                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3596                        {
 3597                            // take first bracket pair matching end, but don't break in case a later bracket
 3598                            // pair matches start
 3599                            bracket_pair_matching_end = Some(pair.clone());
 3600                        }
 3601                    }
 3602                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3603                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3604                        is_bracket_pair_end = true;
 3605                    }
 3606                }
 3607
 3608                if let Some(bracket_pair) = bracket_pair {
 3609                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3610                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3611                    let auto_surround =
 3612                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3613                    if selection.is_empty() {
 3614                        if is_bracket_pair_start {
 3615                            // If the inserted text is a suffix of an opening bracket and the
 3616                            // selection is preceded by the rest of the opening bracket, then
 3617                            // insert the closing bracket.
 3618                            let following_text_allows_autoclose = snapshot
 3619                                .chars_at(selection.start)
 3620                                .next()
 3621                                .map_or(true, |c| scope.should_autoclose_before(c));
 3622
 3623                            let preceding_text_allows_autoclose = selection.start.column == 0
 3624                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3625                                    true,
 3626                                    |c| {
 3627                                        bracket_pair.start != bracket_pair.end
 3628                                            || !snapshot
 3629                                                .char_classifier_at(selection.start)
 3630                                                .is_word(c)
 3631                                    },
 3632                                );
 3633
 3634                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3635                                && bracket_pair.start.len() == 1
 3636                            {
 3637                                let target = bracket_pair.start.chars().next().unwrap();
 3638                                let current_line_count = snapshot
 3639                                    .reversed_chars_at(selection.start)
 3640                                    .take_while(|&c| c != '\n')
 3641                                    .filter(|&c| c == target)
 3642                                    .count();
 3643                                current_line_count % 2 == 1
 3644                            } else {
 3645                                false
 3646                            };
 3647
 3648                            if autoclose
 3649                                && bracket_pair.close
 3650                                && following_text_allows_autoclose
 3651                                && preceding_text_allows_autoclose
 3652                                && !is_closing_quote
 3653                            {
 3654                                let anchor = snapshot.anchor_before(selection.end);
 3655                                new_selections.push((selection.map(|_| anchor), text.len()));
 3656                                new_autoclose_regions.push((
 3657                                    anchor,
 3658                                    text.len(),
 3659                                    selection.id,
 3660                                    bracket_pair.clone(),
 3661                                ));
 3662                                edits.push((
 3663                                    selection.range(),
 3664                                    format!("{}{}", text, bracket_pair.end).into(),
 3665                                ));
 3666                                bracket_inserted = true;
 3667                                continue;
 3668                            }
 3669                        }
 3670
 3671                        if let Some(region) = autoclose_region {
 3672                            // If the selection is followed by an auto-inserted closing bracket,
 3673                            // then don't insert that closing bracket again; just move the selection
 3674                            // past the closing bracket.
 3675                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3676                                && text.as_ref() == region.pair.end.as_str();
 3677                            if should_skip {
 3678                                let anchor = snapshot.anchor_after(selection.end);
 3679                                new_selections
 3680                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3681                                continue;
 3682                            }
 3683                        }
 3684
 3685                        let always_treat_brackets_as_autoclosed = snapshot
 3686                            .language_settings_at(selection.start, cx)
 3687                            .always_treat_brackets_as_autoclosed;
 3688                        if always_treat_brackets_as_autoclosed
 3689                            && is_bracket_pair_end
 3690                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3691                        {
 3692                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3693                            // and the inserted text is a closing bracket and the selection is followed
 3694                            // by the closing bracket then move the selection past the closing bracket.
 3695                            let anchor = snapshot.anchor_after(selection.end);
 3696                            new_selections.push((selection.map(|_| anchor), text.len()));
 3697                            continue;
 3698                        }
 3699                    }
 3700                    // If an opening bracket is 1 character long and is typed while
 3701                    // text is selected, then surround that text with the bracket pair.
 3702                    else if auto_surround
 3703                        && bracket_pair.surround
 3704                        && is_bracket_pair_start
 3705                        && bracket_pair.start.chars().count() == 1
 3706                    {
 3707                        edits.push((selection.start..selection.start, text.clone()));
 3708                        edits.push((
 3709                            selection.end..selection.end,
 3710                            bracket_pair.end.as_str().into(),
 3711                        ));
 3712                        bracket_inserted = true;
 3713                        new_selections.push((
 3714                            Selection {
 3715                                id: selection.id,
 3716                                start: snapshot.anchor_after(selection.start),
 3717                                end: snapshot.anchor_before(selection.end),
 3718                                reversed: selection.reversed,
 3719                                goal: selection.goal,
 3720                            },
 3721                            0,
 3722                        ));
 3723                        continue;
 3724                    }
 3725                }
 3726            }
 3727
 3728            if self.auto_replace_emoji_shortcode
 3729                && selection.is_empty()
 3730                && text.as_ref().ends_with(':')
 3731            {
 3732                if let Some(possible_emoji_short_code) =
 3733                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3734                {
 3735                    if !possible_emoji_short_code.is_empty() {
 3736                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3737                            let emoji_shortcode_start = Point::new(
 3738                                selection.start.row,
 3739                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3740                            );
 3741
 3742                            // Remove shortcode from buffer
 3743                            edits.push((
 3744                                emoji_shortcode_start..selection.start,
 3745                                "".to_string().into(),
 3746                            ));
 3747                            new_selections.push((
 3748                                Selection {
 3749                                    id: selection.id,
 3750                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3751                                    end: snapshot.anchor_before(selection.start),
 3752                                    reversed: selection.reversed,
 3753                                    goal: selection.goal,
 3754                                },
 3755                                0,
 3756                            ));
 3757
 3758                            // Insert emoji
 3759                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3760                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3761                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3762
 3763                            continue;
 3764                        }
 3765                    }
 3766                }
 3767            }
 3768
 3769            // If not handling any auto-close operation, then just replace the selected
 3770            // text with the given input and move the selection to the end of the
 3771            // newly inserted text.
 3772            let anchor = snapshot.anchor_after(selection.end);
 3773            if !self.linked_edit_ranges.is_empty() {
 3774                let start_anchor = snapshot.anchor_before(selection.start);
 3775
 3776                let is_word_char = text.chars().next().map_or(true, |char| {
 3777                    let classifier = snapshot
 3778                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3779                        .ignore_punctuation(true);
 3780                    classifier.is_word(char)
 3781                });
 3782
 3783                if is_word_char {
 3784                    if let Some(ranges) = self
 3785                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3786                    {
 3787                        for (buffer, edits) in ranges {
 3788                            linked_edits
 3789                                .entry(buffer.clone())
 3790                                .or_default()
 3791                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3792                        }
 3793                    }
 3794                } else {
 3795                    clear_linked_edit_ranges = true;
 3796                }
 3797            }
 3798
 3799            new_selections.push((selection.map(|_| anchor), 0));
 3800            edits.push((selection.start..selection.end, text.clone()));
 3801        }
 3802
 3803        drop(snapshot);
 3804
 3805        self.transact(window, cx, |this, window, cx| {
 3806            if clear_linked_edit_ranges {
 3807                this.linked_edit_ranges.clear();
 3808            }
 3809            let initial_buffer_versions =
 3810                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3811
 3812            this.buffer.update(cx, |buffer, cx| {
 3813                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3814            });
 3815            for (buffer, edits) in linked_edits {
 3816                buffer.update(cx, |buffer, cx| {
 3817                    let snapshot = buffer.snapshot();
 3818                    let edits = edits
 3819                        .into_iter()
 3820                        .map(|(range, text)| {
 3821                            use text::ToPoint as TP;
 3822                            let end_point = TP::to_point(&range.end, &snapshot);
 3823                            let start_point = TP::to_point(&range.start, &snapshot);
 3824                            (start_point..end_point, text)
 3825                        })
 3826                        .sorted_by_key(|(range, _)| range.start);
 3827                    buffer.edit(edits, None, cx);
 3828                })
 3829            }
 3830            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3831            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3832            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3833            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3834                .zip(new_selection_deltas)
 3835                .map(|(selection, delta)| Selection {
 3836                    id: selection.id,
 3837                    start: selection.start + delta,
 3838                    end: selection.end + delta,
 3839                    reversed: selection.reversed,
 3840                    goal: SelectionGoal::None,
 3841                })
 3842                .collect::<Vec<_>>();
 3843
 3844            let mut i = 0;
 3845            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3846                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3847                let start = map.buffer_snapshot.anchor_before(position);
 3848                let end = map.buffer_snapshot.anchor_after(position);
 3849                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3850                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3851                        Ordering::Less => i += 1,
 3852                        Ordering::Greater => break,
 3853                        Ordering::Equal => {
 3854                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3855                                Ordering::Less => i += 1,
 3856                                Ordering::Equal => break,
 3857                                Ordering::Greater => break,
 3858                            }
 3859                        }
 3860                    }
 3861                }
 3862                this.autoclose_regions.insert(
 3863                    i,
 3864                    AutocloseRegion {
 3865                        selection_id,
 3866                        range: start..end,
 3867                        pair,
 3868                    },
 3869                );
 3870            }
 3871
 3872            let had_active_inline_completion = this.has_active_inline_completion();
 3873            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3874                s.select(new_selections)
 3875            });
 3876
 3877            if !bracket_inserted {
 3878                if let Some(on_type_format_task) =
 3879                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3880                {
 3881                    on_type_format_task.detach_and_log_err(cx);
 3882                }
 3883            }
 3884
 3885            let editor_settings = EditorSettings::get_global(cx);
 3886            if bracket_inserted
 3887                && (editor_settings.auto_signature_help
 3888                    || editor_settings.show_signature_help_after_edits)
 3889            {
 3890                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3891            }
 3892
 3893            let trigger_in_words =
 3894                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3895            if this.hard_wrap.is_some() {
 3896                let latest: Range<Point> = this.selections.newest(cx).range();
 3897                if latest.is_empty()
 3898                    && this
 3899                        .buffer()
 3900                        .read(cx)
 3901                        .snapshot(cx)
 3902                        .line_len(MultiBufferRow(latest.start.row))
 3903                        == latest.start.column
 3904                {
 3905                    this.rewrap_impl(
 3906                        RewrapOptions {
 3907                            override_language_settings: true,
 3908                            preserve_existing_whitespace: true,
 3909                        },
 3910                        cx,
 3911                    )
 3912                }
 3913            }
 3914            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3915            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3916            this.refresh_inline_completion(true, false, window, cx);
 3917            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3918        });
 3919    }
 3920
 3921    fn find_possible_emoji_shortcode_at_position(
 3922        snapshot: &MultiBufferSnapshot,
 3923        position: Point,
 3924    ) -> Option<String> {
 3925        let mut chars = Vec::new();
 3926        let mut found_colon = false;
 3927        for char in snapshot.reversed_chars_at(position).take(100) {
 3928            // Found a possible emoji shortcode in the middle of the buffer
 3929            if found_colon {
 3930                if char.is_whitespace() {
 3931                    chars.reverse();
 3932                    return Some(chars.iter().collect());
 3933                }
 3934                // If the previous character is not a whitespace, we are in the middle of a word
 3935                // and we only want to complete the shortcode if the word is made up of other emojis
 3936                let mut containing_word = String::new();
 3937                for ch in snapshot
 3938                    .reversed_chars_at(position)
 3939                    .skip(chars.len() + 1)
 3940                    .take(100)
 3941                {
 3942                    if ch.is_whitespace() {
 3943                        break;
 3944                    }
 3945                    containing_word.push(ch);
 3946                }
 3947                let containing_word = containing_word.chars().rev().collect::<String>();
 3948                if util::word_consists_of_emojis(containing_word.as_str()) {
 3949                    chars.reverse();
 3950                    return Some(chars.iter().collect());
 3951                }
 3952            }
 3953
 3954            if char.is_whitespace() || !char.is_ascii() {
 3955                return None;
 3956            }
 3957            if char == ':' {
 3958                found_colon = true;
 3959            } else {
 3960                chars.push(char);
 3961            }
 3962        }
 3963        // Found a possible emoji shortcode at the beginning of the buffer
 3964        chars.reverse();
 3965        Some(chars.iter().collect())
 3966    }
 3967
 3968    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3969        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3970        self.transact(window, cx, |this, window, cx| {
 3971            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3972                let selections = this.selections.all::<usize>(cx);
 3973                let multi_buffer = this.buffer.read(cx);
 3974                let buffer = multi_buffer.snapshot(cx);
 3975                selections
 3976                    .iter()
 3977                    .map(|selection| {
 3978                        let start_point = selection.start.to_point(&buffer);
 3979                        let mut existing_indent =
 3980                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3981                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3982                        let start = selection.start;
 3983                        let end = selection.end;
 3984                        let selection_is_empty = start == end;
 3985                        let language_scope = buffer.language_scope_at(start);
 3986                        let (
 3987                            comment_delimiter,
 3988                            doc_delimiter,
 3989                            insert_extra_newline,
 3990                            indent_on_newline,
 3991                            indent_on_extra_newline,
 3992                        ) = if let Some(language) = &language_scope {
 3993                            let mut insert_extra_newline =
 3994                                insert_extra_newline_brackets(&buffer, start..end, language)
 3995                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3996
 3997                            // Comment extension on newline is allowed only for cursor selections
 3998                            let comment_delimiter = maybe!({
 3999                                if !selection_is_empty {
 4000                                    return None;
 4001                                }
 4002
 4003                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4004                                    return None;
 4005                                }
 4006
 4007                                let delimiters = language.line_comment_prefixes();
 4008                                let max_len_of_delimiter =
 4009                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4010                                let (snapshot, range) =
 4011                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4012
 4013                                let num_of_whitespaces = snapshot
 4014                                    .chars_for_range(range.clone())
 4015                                    .take_while(|c| c.is_whitespace())
 4016                                    .count();
 4017                                let comment_candidate = snapshot
 4018                                    .chars_for_range(range)
 4019                                    .skip(num_of_whitespaces)
 4020                                    .take(max_len_of_delimiter)
 4021                                    .collect::<String>();
 4022                                let (delimiter, trimmed_len) = delimiters
 4023                                    .iter()
 4024                                    .filter_map(|delimiter| {
 4025                                        let prefix = delimiter.trim_end();
 4026                                        if comment_candidate.starts_with(prefix) {
 4027                                            Some((delimiter, prefix.len()))
 4028                                        } else {
 4029                                            None
 4030                                        }
 4031                                    })
 4032                                    .max_by_key(|(_, len)| *len)?;
 4033
 4034                                let cursor_is_placed_after_comment_marker =
 4035                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4036                                if cursor_is_placed_after_comment_marker {
 4037                                    Some(delimiter.clone())
 4038                                } else {
 4039                                    None
 4040                                }
 4041                            });
 4042
 4043                            let mut indent_on_newline = IndentSize::spaces(0);
 4044                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4045
 4046                            let doc_delimiter = maybe!({
 4047                                if !selection_is_empty {
 4048                                    return None;
 4049                                }
 4050
 4051                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4052                                    return None;
 4053                                }
 4054
 4055                                let DocumentationConfig {
 4056                                    start: start_tag,
 4057                                    end: end_tag,
 4058                                    prefix: delimiter,
 4059                                    tab_size: len,
 4060                                } = language.documentation()?;
 4061
 4062                                let is_within_block_comment = buffer
 4063                                    .language_scope_at(start_point)
 4064                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4065                                if !is_within_block_comment {
 4066                                    return None;
 4067                                }
 4068
 4069                                let (snapshot, range) =
 4070                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4071
 4072                                let num_of_whitespaces = snapshot
 4073                                    .chars_for_range(range.clone())
 4074                                    .take_while(|c| c.is_whitespace())
 4075                                    .count();
 4076
 4077                                // 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.
 4078                                let column = start_point.column;
 4079                                let cursor_is_after_start_tag = {
 4080                                    let start_tag_len = start_tag.len();
 4081                                    let start_tag_line = snapshot
 4082                                        .chars_for_range(range.clone())
 4083                                        .skip(num_of_whitespaces)
 4084                                        .take(start_tag_len)
 4085                                        .collect::<String>();
 4086                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4087                                        num_of_whitespaces + start_tag_len <= column as usize
 4088                                    } else {
 4089                                        false
 4090                                    }
 4091                                };
 4092
 4093                                let cursor_is_after_delimiter = {
 4094                                    let delimiter_trim = delimiter.trim_end();
 4095                                    let delimiter_line = snapshot
 4096                                        .chars_for_range(range.clone())
 4097                                        .skip(num_of_whitespaces)
 4098                                        .take(delimiter_trim.len())
 4099                                        .collect::<String>();
 4100                                    if delimiter_line.starts_with(delimiter_trim) {
 4101                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4102                                    } else {
 4103                                        false
 4104                                    }
 4105                                };
 4106
 4107                                let cursor_is_before_end_tag_if_exists = {
 4108                                    let mut char_position = 0u32;
 4109                                    let mut end_tag_offset = None;
 4110
 4111                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4112                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4113                                            let chars_before_match =
 4114                                                chunk[..byte_pos].chars().count() as u32;
 4115                                            end_tag_offset =
 4116                                                Some(char_position + chars_before_match);
 4117                                            break 'outer;
 4118                                        }
 4119                                        char_position += chunk.chars().count() as u32;
 4120                                    }
 4121
 4122                                    if let Some(end_tag_offset) = end_tag_offset {
 4123                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4124                                        if cursor_is_after_start_tag {
 4125                                            if cursor_is_before_end_tag {
 4126                                                insert_extra_newline = true;
 4127                                            }
 4128                                            let cursor_is_at_start_of_end_tag =
 4129                                                column == end_tag_offset;
 4130                                            if cursor_is_at_start_of_end_tag {
 4131                                                indent_on_extra_newline.len = (*len).into();
 4132                                            }
 4133                                        }
 4134                                        cursor_is_before_end_tag
 4135                                    } else {
 4136                                        true
 4137                                    }
 4138                                };
 4139
 4140                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4141                                    && cursor_is_before_end_tag_if_exists
 4142                                {
 4143                                    if cursor_is_after_start_tag {
 4144                                        indent_on_newline.len = (*len).into();
 4145                                    }
 4146                                    Some(delimiter.clone())
 4147                                } else {
 4148                                    None
 4149                                }
 4150                            });
 4151
 4152                            (
 4153                                comment_delimiter,
 4154                                doc_delimiter,
 4155                                insert_extra_newline,
 4156                                indent_on_newline,
 4157                                indent_on_extra_newline,
 4158                            )
 4159                        } else {
 4160                            (
 4161                                None,
 4162                                None,
 4163                                false,
 4164                                IndentSize::default(),
 4165                                IndentSize::default(),
 4166                            )
 4167                        };
 4168
 4169                        let prevent_auto_indent = doc_delimiter.is_some();
 4170                        let delimiter = comment_delimiter.or(doc_delimiter);
 4171
 4172                        let capacity_for_delimiter =
 4173                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4174                        let mut new_text = String::with_capacity(
 4175                            1 + capacity_for_delimiter
 4176                                + existing_indent.len as usize
 4177                                + indent_on_newline.len as usize
 4178                                + indent_on_extra_newline.len as usize,
 4179                        );
 4180                        new_text.push('\n');
 4181                        new_text.extend(existing_indent.chars());
 4182                        new_text.extend(indent_on_newline.chars());
 4183
 4184                        if let Some(delimiter) = &delimiter {
 4185                            new_text.push_str(delimiter);
 4186                        }
 4187
 4188                        if insert_extra_newline {
 4189                            new_text.push('\n');
 4190                            new_text.extend(existing_indent.chars());
 4191                            new_text.extend(indent_on_extra_newline.chars());
 4192                        }
 4193
 4194                        let anchor = buffer.anchor_after(end);
 4195                        let new_selection = selection.map(|_| anchor);
 4196                        (
 4197                            ((start..end, new_text), prevent_auto_indent),
 4198                            (insert_extra_newline, new_selection),
 4199                        )
 4200                    })
 4201                    .unzip()
 4202            };
 4203
 4204            let mut auto_indent_edits = Vec::new();
 4205            let mut edits = Vec::new();
 4206            for (edit, prevent_auto_indent) in edits_with_flags {
 4207                if prevent_auto_indent {
 4208                    edits.push(edit);
 4209                } else {
 4210                    auto_indent_edits.push(edit);
 4211                }
 4212            }
 4213            if !edits.is_empty() {
 4214                this.edit(edits, cx);
 4215            }
 4216            if !auto_indent_edits.is_empty() {
 4217                this.edit_with_autoindent(auto_indent_edits, cx);
 4218            }
 4219
 4220            let buffer = this.buffer.read(cx).snapshot(cx);
 4221            let new_selections = selection_info
 4222                .into_iter()
 4223                .map(|(extra_newline_inserted, new_selection)| {
 4224                    let mut cursor = new_selection.end.to_point(&buffer);
 4225                    if extra_newline_inserted {
 4226                        cursor.row -= 1;
 4227                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4228                    }
 4229                    new_selection.map(|_| cursor)
 4230                })
 4231                .collect();
 4232
 4233            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4234                s.select(new_selections)
 4235            });
 4236            this.refresh_inline_completion(true, false, window, cx);
 4237        });
 4238    }
 4239
 4240    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4241        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4242
 4243        let buffer = self.buffer.read(cx);
 4244        let snapshot = buffer.snapshot(cx);
 4245
 4246        let mut edits = Vec::new();
 4247        let mut rows = Vec::new();
 4248
 4249        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4250            let cursor = selection.head();
 4251            let row = cursor.row;
 4252
 4253            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4254
 4255            let newline = "\n".to_string();
 4256            edits.push((start_of_line..start_of_line, newline));
 4257
 4258            rows.push(row + rows_inserted as u32);
 4259        }
 4260
 4261        self.transact(window, cx, |editor, window, cx| {
 4262            editor.edit(edits, cx);
 4263
 4264            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4265                let mut index = 0;
 4266                s.move_cursors_with(|map, _, _| {
 4267                    let row = rows[index];
 4268                    index += 1;
 4269
 4270                    let point = Point::new(row, 0);
 4271                    let boundary = map.next_line_boundary(point).1;
 4272                    let clipped = map.clip_point(boundary, Bias::Left);
 4273
 4274                    (clipped, SelectionGoal::None)
 4275                });
 4276            });
 4277
 4278            let mut indent_edits = Vec::new();
 4279            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4280            for row in rows {
 4281                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4282                for (row, indent) in indents {
 4283                    if indent.len == 0 {
 4284                        continue;
 4285                    }
 4286
 4287                    let text = match indent.kind {
 4288                        IndentKind::Space => " ".repeat(indent.len as usize),
 4289                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4290                    };
 4291                    let point = Point::new(row.0, 0);
 4292                    indent_edits.push((point..point, text));
 4293                }
 4294            }
 4295            editor.edit(indent_edits, cx);
 4296        });
 4297    }
 4298
 4299    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4300        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4301
 4302        let buffer = self.buffer.read(cx);
 4303        let snapshot = buffer.snapshot(cx);
 4304
 4305        let mut edits = Vec::new();
 4306        let mut rows = Vec::new();
 4307        let mut rows_inserted = 0;
 4308
 4309        for selection in self.selections.all_adjusted(cx) {
 4310            let cursor = selection.head();
 4311            let row = cursor.row;
 4312
 4313            let point = Point::new(row + 1, 0);
 4314            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4315
 4316            let newline = "\n".to_string();
 4317            edits.push((start_of_line..start_of_line, newline));
 4318
 4319            rows_inserted += 1;
 4320            rows.push(row + rows_inserted);
 4321        }
 4322
 4323        self.transact(window, cx, |editor, window, cx| {
 4324            editor.edit(edits, cx);
 4325
 4326            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4327                let mut index = 0;
 4328                s.move_cursors_with(|map, _, _| {
 4329                    let row = rows[index];
 4330                    index += 1;
 4331
 4332                    let point = Point::new(row, 0);
 4333                    let boundary = map.next_line_boundary(point).1;
 4334                    let clipped = map.clip_point(boundary, Bias::Left);
 4335
 4336                    (clipped, SelectionGoal::None)
 4337                });
 4338            });
 4339
 4340            let mut indent_edits = Vec::new();
 4341            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4342            for row in rows {
 4343                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4344                for (row, indent) in indents {
 4345                    if indent.len == 0 {
 4346                        continue;
 4347                    }
 4348
 4349                    let text = match indent.kind {
 4350                        IndentKind::Space => " ".repeat(indent.len as usize),
 4351                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4352                    };
 4353                    let point = Point::new(row.0, 0);
 4354                    indent_edits.push((point..point, text));
 4355                }
 4356            }
 4357            editor.edit(indent_edits, cx);
 4358        });
 4359    }
 4360
 4361    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4362        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4363            original_indent_columns: Vec::new(),
 4364        });
 4365        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4366    }
 4367
 4368    fn insert_with_autoindent_mode(
 4369        &mut self,
 4370        text: &str,
 4371        autoindent_mode: Option<AutoindentMode>,
 4372        window: &mut Window,
 4373        cx: &mut Context<Self>,
 4374    ) {
 4375        if self.read_only(cx) {
 4376            return;
 4377        }
 4378
 4379        let text: Arc<str> = text.into();
 4380        self.transact(window, cx, |this, window, cx| {
 4381            let old_selections = this.selections.all_adjusted(cx);
 4382            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4383                let anchors = {
 4384                    let snapshot = buffer.read(cx);
 4385                    old_selections
 4386                        .iter()
 4387                        .map(|s| {
 4388                            let anchor = snapshot.anchor_after(s.head());
 4389                            s.map(|_| anchor)
 4390                        })
 4391                        .collect::<Vec<_>>()
 4392                };
 4393                buffer.edit(
 4394                    old_selections
 4395                        .iter()
 4396                        .map(|s| (s.start..s.end, text.clone())),
 4397                    autoindent_mode,
 4398                    cx,
 4399                );
 4400                anchors
 4401            });
 4402
 4403            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4404                s.select_anchors(selection_anchors);
 4405            });
 4406
 4407            cx.notify();
 4408        });
 4409    }
 4410
 4411    fn trigger_completion_on_input(
 4412        &mut self,
 4413        text: &str,
 4414        trigger_in_words: bool,
 4415        window: &mut Window,
 4416        cx: &mut Context<Self>,
 4417    ) {
 4418        let ignore_completion_provider = self
 4419            .context_menu
 4420            .borrow()
 4421            .as_ref()
 4422            .map(|menu| match menu {
 4423                CodeContextMenu::Completions(completions_menu) => {
 4424                    completions_menu.ignore_completion_provider
 4425                }
 4426                CodeContextMenu::CodeActions(_) => false,
 4427            })
 4428            .unwrap_or(false);
 4429
 4430        if ignore_completion_provider {
 4431            self.show_word_completions(&ShowWordCompletions, window, cx);
 4432        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4433            self.show_completions(
 4434                &ShowCompletions {
 4435                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4436                },
 4437                window,
 4438                cx,
 4439            );
 4440        } else {
 4441            self.hide_context_menu(window, cx);
 4442        }
 4443    }
 4444
 4445    fn is_completion_trigger(
 4446        &self,
 4447        text: &str,
 4448        trigger_in_words: bool,
 4449        cx: &mut Context<Self>,
 4450    ) -> bool {
 4451        let position = self.selections.newest_anchor().head();
 4452        let multibuffer = self.buffer.read(cx);
 4453        let Some(buffer) = position
 4454            .buffer_id
 4455            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4456        else {
 4457            return false;
 4458        };
 4459
 4460        if let Some(completion_provider) = &self.completion_provider {
 4461            completion_provider.is_completion_trigger(
 4462                &buffer,
 4463                position.text_anchor,
 4464                text,
 4465                trigger_in_words,
 4466                cx,
 4467            )
 4468        } else {
 4469            false
 4470        }
 4471    }
 4472
 4473    /// If any empty selections is touching the start of its innermost containing autoclose
 4474    /// region, expand it to select the brackets.
 4475    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4476        let selections = self.selections.all::<usize>(cx);
 4477        let buffer = self.buffer.read(cx).read(cx);
 4478        let new_selections = self
 4479            .selections_with_autoclose_regions(selections, &buffer)
 4480            .map(|(mut selection, region)| {
 4481                if !selection.is_empty() {
 4482                    return selection;
 4483                }
 4484
 4485                if let Some(region) = region {
 4486                    let mut range = region.range.to_offset(&buffer);
 4487                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4488                        range.start -= region.pair.start.len();
 4489                        if buffer.contains_str_at(range.start, &region.pair.start)
 4490                            && buffer.contains_str_at(range.end, &region.pair.end)
 4491                        {
 4492                            range.end += region.pair.end.len();
 4493                            selection.start = range.start;
 4494                            selection.end = range.end;
 4495
 4496                            return selection;
 4497                        }
 4498                    }
 4499                }
 4500
 4501                let always_treat_brackets_as_autoclosed = buffer
 4502                    .language_settings_at(selection.start, cx)
 4503                    .always_treat_brackets_as_autoclosed;
 4504
 4505                if !always_treat_brackets_as_autoclosed {
 4506                    return selection;
 4507                }
 4508
 4509                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4510                    for (pair, enabled) in scope.brackets() {
 4511                        if !enabled || !pair.close {
 4512                            continue;
 4513                        }
 4514
 4515                        if buffer.contains_str_at(selection.start, &pair.end) {
 4516                            let pair_start_len = pair.start.len();
 4517                            if buffer.contains_str_at(
 4518                                selection.start.saturating_sub(pair_start_len),
 4519                                &pair.start,
 4520                            ) {
 4521                                selection.start -= pair_start_len;
 4522                                selection.end += pair.end.len();
 4523
 4524                                return selection;
 4525                            }
 4526                        }
 4527                    }
 4528                }
 4529
 4530                selection
 4531            })
 4532            .collect();
 4533
 4534        drop(buffer);
 4535        self.change_selections(None, window, cx, |selections| {
 4536            selections.select(new_selections)
 4537        });
 4538    }
 4539
 4540    /// Iterate the given selections, and for each one, find the smallest surrounding
 4541    /// autoclose region. This uses the ordering of the selections and the autoclose
 4542    /// regions to avoid repeated comparisons.
 4543    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4544        &'a self,
 4545        selections: impl IntoIterator<Item = Selection<D>>,
 4546        buffer: &'a MultiBufferSnapshot,
 4547    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4548        let mut i = 0;
 4549        let mut regions = self.autoclose_regions.as_slice();
 4550        selections.into_iter().map(move |selection| {
 4551            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4552
 4553            let mut enclosing = None;
 4554            while let Some(pair_state) = regions.get(i) {
 4555                if pair_state.range.end.to_offset(buffer) < range.start {
 4556                    regions = &regions[i + 1..];
 4557                    i = 0;
 4558                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4559                    break;
 4560                } else {
 4561                    if pair_state.selection_id == selection.id {
 4562                        enclosing = Some(pair_state);
 4563                    }
 4564                    i += 1;
 4565                }
 4566            }
 4567
 4568            (selection, enclosing)
 4569        })
 4570    }
 4571
 4572    /// Remove any autoclose regions that no longer contain their selection.
 4573    fn invalidate_autoclose_regions(
 4574        &mut self,
 4575        mut selections: &[Selection<Anchor>],
 4576        buffer: &MultiBufferSnapshot,
 4577    ) {
 4578        self.autoclose_regions.retain(|state| {
 4579            let mut i = 0;
 4580            while let Some(selection) = selections.get(i) {
 4581                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4582                    selections = &selections[1..];
 4583                    continue;
 4584                }
 4585                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4586                    break;
 4587                }
 4588                if selection.id == state.selection_id {
 4589                    return true;
 4590                } else {
 4591                    i += 1;
 4592                }
 4593            }
 4594            false
 4595        });
 4596    }
 4597
 4598    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4599        let offset = position.to_offset(buffer);
 4600        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4601        if offset > word_range.start && kind == Some(CharKind::Word) {
 4602            Some(
 4603                buffer
 4604                    .text_for_range(word_range.start..offset)
 4605                    .collect::<String>(),
 4606            )
 4607        } else {
 4608            None
 4609        }
 4610    }
 4611
 4612    pub fn toggle_inline_values(
 4613        &mut self,
 4614        _: &ToggleInlineValues,
 4615        _: &mut Window,
 4616        cx: &mut Context<Self>,
 4617    ) {
 4618        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4619
 4620        self.refresh_inline_values(cx);
 4621    }
 4622
 4623    pub fn toggle_inlay_hints(
 4624        &mut self,
 4625        _: &ToggleInlayHints,
 4626        _: &mut Window,
 4627        cx: &mut Context<Self>,
 4628    ) {
 4629        self.refresh_inlay_hints(
 4630            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4631            cx,
 4632        );
 4633    }
 4634
 4635    pub fn inlay_hints_enabled(&self) -> bool {
 4636        self.inlay_hint_cache.enabled
 4637    }
 4638
 4639    pub fn inline_values_enabled(&self) -> bool {
 4640        self.inline_value_cache.enabled
 4641    }
 4642
 4643    #[cfg(any(test, feature = "test-support"))]
 4644    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4645        self.display_map
 4646            .read(cx)
 4647            .current_inlays()
 4648            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4649            .cloned()
 4650            .collect()
 4651    }
 4652
 4653    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4654        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4655            return;
 4656        }
 4657
 4658        let reason_description = reason.description();
 4659        let ignore_debounce = matches!(
 4660            reason,
 4661            InlayHintRefreshReason::SettingsChange(_)
 4662                | InlayHintRefreshReason::Toggle(_)
 4663                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4664                | InlayHintRefreshReason::ModifiersChanged(_)
 4665        );
 4666        let (invalidate_cache, required_languages) = match reason {
 4667            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4668                match self.inlay_hint_cache.modifiers_override(enabled) {
 4669                    Some(enabled) => {
 4670                        if enabled {
 4671                            (InvalidationStrategy::RefreshRequested, None)
 4672                        } else {
 4673                            self.splice_inlays(
 4674                                &self
 4675                                    .visible_inlay_hints(cx)
 4676                                    .iter()
 4677                                    .map(|inlay| inlay.id)
 4678                                    .collect::<Vec<InlayId>>(),
 4679                                Vec::new(),
 4680                                cx,
 4681                            );
 4682                            return;
 4683                        }
 4684                    }
 4685                    None => return,
 4686                }
 4687            }
 4688            InlayHintRefreshReason::Toggle(enabled) => {
 4689                if self.inlay_hint_cache.toggle(enabled) {
 4690                    if enabled {
 4691                        (InvalidationStrategy::RefreshRequested, None)
 4692                    } else {
 4693                        self.splice_inlays(
 4694                            &self
 4695                                .visible_inlay_hints(cx)
 4696                                .iter()
 4697                                .map(|inlay| inlay.id)
 4698                                .collect::<Vec<InlayId>>(),
 4699                            Vec::new(),
 4700                            cx,
 4701                        );
 4702                        return;
 4703                    }
 4704                } else {
 4705                    return;
 4706                }
 4707            }
 4708            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4709                match self.inlay_hint_cache.update_settings(
 4710                    &self.buffer,
 4711                    new_settings,
 4712                    self.visible_inlay_hints(cx),
 4713                    cx,
 4714                ) {
 4715                    ControlFlow::Break(Some(InlaySplice {
 4716                        to_remove,
 4717                        to_insert,
 4718                    })) => {
 4719                        self.splice_inlays(&to_remove, to_insert, cx);
 4720                        return;
 4721                    }
 4722                    ControlFlow::Break(None) => return,
 4723                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4724                }
 4725            }
 4726            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4727                if let Some(InlaySplice {
 4728                    to_remove,
 4729                    to_insert,
 4730                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4731                {
 4732                    self.splice_inlays(&to_remove, to_insert, cx);
 4733                }
 4734                self.display_map.update(cx, |display_map, _| {
 4735                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4736                });
 4737                return;
 4738            }
 4739            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4740            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4741                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4742            }
 4743            InlayHintRefreshReason::RefreshRequested => {
 4744                (InvalidationStrategy::RefreshRequested, None)
 4745            }
 4746        };
 4747
 4748        if let Some(InlaySplice {
 4749            to_remove,
 4750            to_insert,
 4751        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4752            reason_description,
 4753            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4754            invalidate_cache,
 4755            ignore_debounce,
 4756            cx,
 4757        ) {
 4758            self.splice_inlays(&to_remove, to_insert, cx);
 4759        }
 4760    }
 4761
 4762    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4763        self.display_map
 4764            .read(cx)
 4765            .current_inlays()
 4766            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4767            .cloned()
 4768            .collect()
 4769    }
 4770
 4771    pub fn excerpts_for_inlay_hints_query(
 4772        &self,
 4773        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4774        cx: &mut Context<Editor>,
 4775    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4776        let Some(project) = self.project.as_ref() else {
 4777            return HashMap::default();
 4778        };
 4779        let project = project.read(cx);
 4780        let multi_buffer = self.buffer().read(cx);
 4781        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4782        let multi_buffer_visible_start = self
 4783            .scroll_manager
 4784            .anchor()
 4785            .anchor
 4786            .to_point(&multi_buffer_snapshot);
 4787        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4788            multi_buffer_visible_start
 4789                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4790            Bias::Left,
 4791        );
 4792        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4793        multi_buffer_snapshot
 4794            .range_to_buffer_ranges(multi_buffer_visible_range)
 4795            .into_iter()
 4796            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4797            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4798                let buffer_file = project::File::from_dyn(buffer.file())?;
 4799                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4800                let worktree_entry = buffer_worktree
 4801                    .read(cx)
 4802                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4803                if worktree_entry.is_ignored {
 4804                    return None;
 4805                }
 4806
 4807                let language = buffer.language()?;
 4808                if let Some(restrict_to_languages) = restrict_to_languages {
 4809                    if !restrict_to_languages.contains(language) {
 4810                        return None;
 4811                    }
 4812                }
 4813                Some((
 4814                    excerpt_id,
 4815                    (
 4816                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4817                        buffer.version().clone(),
 4818                        excerpt_visible_range,
 4819                    ),
 4820                ))
 4821            })
 4822            .collect()
 4823    }
 4824
 4825    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4826        TextLayoutDetails {
 4827            text_system: window.text_system().clone(),
 4828            editor_style: self.style.clone().unwrap(),
 4829            rem_size: window.rem_size(),
 4830            scroll_anchor: self.scroll_manager.anchor(),
 4831            visible_rows: self.visible_line_count(),
 4832            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4833        }
 4834    }
 4835
 4836    pub fn splice_inlays(
 4837        &self,
 4838        to_remove: &[InlayId],
 4839        to_insert: Vec<Inlay>,
 4840        cx: &mut Context<Self>,
 4841    ) {
 4842        self.display_map.update(cx, |display_map, cx| {
 4843            display_map.splice_inlays(to_remove, to_insert, cx)
 4844        });
 4845        cx.notify();
 4846    }
 4847
 4848    fn trigger_on_type_formatting(
 4849        &self,
 4850        input: String,
 4851        window: &mut Window,
 4852        cx: &mut Context<Self>,
 4853    ) -> Option<Task<Result<()>>> {
 4854        if input.len() != 1 {
 4855            return None;
 4856        }
 4857
 4858        let project = self.project.as_ref()?;
 4859        let position = self.selections.newest_anchor().head();
 4860        let (buffer, buffer_position) = self
 4861            .buffer
 4862            .read(cx)
 4863            .text_anchor_for_position(position, cx)?;
 4864
 4865        let settings = language_settings::language_settings(
 4866            buffer
 4867                .read(cx)
 4868                .language_at(buffer_position)
 4869                .map(|l| l.name()),
 4870            buffer.read(cx).file(),
 4871            cx,
 4872        );
 4873        if !settings.use_on_type_format {
 4874            return None;
 4875        }
 4876
 4877        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4878        // hence we do LSP request & edit on host side only — add formats to host's history.
 4879        let push_to_lsp_host_history = true;
 4880        // If this is not the host, append its history with new edits.
 4881        let push_to_client_history = project.read(cx).is_via_collab();
 4882
 4883        let on_type_formatting = project.update(cx, |project, cx| {
 4884            project.on_type_format(
 4885                buffer.clone(),
 4886                buffer_position,
 4887                input,
 4888                push_to_lsp_host_history,
 4889                cx,
 4890            )
 4891        });
 4892        Some(cx.spawn_in(window, async move |editor, cx| {
 4893            if let Some(transaction) = on_type_formatting.await? {
 4894                if push_to_client_history {
 4895                    buffer
 4896                        .update(cx, |buffer, _| {
 4897                            buffer.push_transaction(transaction, Instant::now());
 4898                            buffer.finalize_last_transaction();
 4899                        })
 4900                        .ok();
 4901                }
 4902                editor.update(cx, |editor, cx| {
 4903                    editor.refresh_document_highlights(cx);
 4904                })?;
 4905            }
 4906            Ok(())
 4907        }))
 4908    }
 4909
 4910    pub fn show_word_completions(
 4911        &mut self,
 4912        _: &ShowWordCompletions,
 4913        window: &mut Window,
 4914        cx: &mut Context<Self>,
 4915    ) {
 4916        self.open_completions_menu(true, None, window, cx);
 4917    }
 4918
 4919    pub fn show_completions(
 4920        &mut self,
 4921        options: &ShowCompletions,
 4922        window: &mut Window,
 4923        cx: &mut Context<Self>,
 4924    ) {
 4925        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4926    }
 4927
 4928    fn open_completions_menu(
 4929        &mut self,
 4930        ignore_completion_provider: bool,
 4931        trigger: Option<&str>,
 4932        window: &mut Window,
 4933        cx: &mut Context<Self>,
 4934    ) {
 4935        if self.pending_rename.is_some() {
 4936            return;
 4937        }
 4938        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4939            return;
 4940        }
 4941
 4942        let position = self.selections.newest_anchor().head();
 4943        if position.diff_base_anchor.is_some() {
 4944            return;
 4945        }
 4946        let (buffer, buffer_position) =
 4947            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4948                output
 4949            } else {
 4950                return;
 4951            };
 4952        let buffer_snapshot = buffer.read(cx).snapshot();
 4953        let show_completion_documentation = buffer_snapshot
 4954            .settings_at(buffer_position, cx)
 4955            .show_completion_documentation;
 4956
 4957        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4958
 4959        let trigger_kind = match trigger {
 4960            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4961                CompletionTriggerKind::TRIGGER_CHARACTER
 4962            }
 4963            _ => CompletionTriggerKind::INVOKED,
 4964        };
 4965        let completion_context = CompletionContext {
 4966            trigger_character: trigger.and_then(|trigger| {
 4967                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4968                    Some(String::from(trigger))
 4969                } else {
 4970                    None
 4971                }
 4972            }),
 4973            trigger_kind,
 4974        };
 4975
 4976        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4977        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4978            let word_to_exclude = buffer_snapshot
 4979                .text_for_range(old_range.clone())
 4980                .collect::<String>();
 4981            (
 4982                buffer_snapshot.anchor_before(old_range.start)
 4983                    ..buffer_snapshot.anchor_after(old_range.end),
 4984                Some(word_to_exclude),
 4985            )
 4986        } else {
 4987            (buffer_position..buffer_position, None)
 4988        };
 4989
 4990        let language = buffer_snapshot
 4991            .language_at(buffer_position)
 4992            .map(|language| language.name());
 4993
 4994        let completion_settings =
 4995            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 4996
 4997        // The document can be large, so stay in reasonable bounds when searching for words,
 4998        // otherwise completion pop-up might be slow to appear.
 4999        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5000        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5001        let min_word_search = buffer_snapshot.clip_point(
 5002            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5003            Bias::Left,
 5004        );
 5005        let max_word_search = buffer_snapshot.clip_point(
 5006            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5007            Bias::Right,
 5008        );
 5009        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5010            ..buffer_snapshot.point_to_offset(max_word_search);
 5011
 5012        let provider = if ignore_completion_provider {
 5013            None
 5014        } else {
 5015            self.completion_provider.clone()
 5016        };
 5017        let skip_digits = query
 5018            .as_ref()
 5019            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5020
 5021        let (mut words, provided_completions) = match &provider {
 5022            Some(provider) => {
 5023                let completions = provider.completions(
 5024                    position.excerpt_id,
 5025                    &buffer,
 5026                    buffer_position,
 5027                    completion_context,
 5028                    window,
 5029                    cx,
 5030                );
 5031
 5032                let words = match completion_settings.words {
 5033                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5034                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5035                        .background_spawn(async move {
 5036                            buffer_snapshot.words_in_range(WordsQuery {
 5037                                fuzzy_contents: None,
 5038                                range: word_search_range,
 5039                                skip_digits,
 5040                            })
 5041                        }),
 5042                };
 5043
 5044                (words, completions)
 5045            }
 5046            None => (
 5047                cx.background_spawn(async move {
 5048                    buffer_snapshot.words_in_range(WordsQuery {
 5049                        fuzzy_contents: None,
 5050                        range: word_search_range,
 5051                        skip_digits,
 5052                    })
 5053                }),
 5054                Task::ready(Ok(None)),
 5055            ),
 5056        };
 5057
 5058        let sort_completions = provider
 5059            .as_ref()
 5060            .map_or(false, |provider| provider.sort_completions());
 5061
 5062        let filter_completions = provider
 5063            .as_ref()
 5064            .map_or(true, |provider| provider.filter_completions());
 5065
 5066        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5067
 5068        let id = post_inc(&mut self.next_completion_id);
 5069        let task = cx.spawn_in(window, async move |editor, cx| {
 5070            async move {
 5071                editor.update(cx, |this, _| {
 5072                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5073                })?;
 5074
 5075                let mut completions = Vec::new();
 5076                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5077                    completions.extend(provided_completions);
 5078                    if completion_settings.words == WordsCompletionMode::Fallback {
 5079                        words = Task::ready(BTreeMap::default());
 5080                    }
 5081                }
 5082
 5083                let mut words = words.await;
 5084                if let Some(word_to_exclude) = &word_to_exclude {
 5085                    words.remove(word_to_exclude);
 5086                }
 5087                for lsp_completion in &completions {
 5088                    words.remove(&lsp_completion.new_text);
 5089                }
 5090                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5091                    replace_range: old_range.clone(),
 5092                    new_text: word.clone(),
 5093                    label: CodeLabel::plain(word, None),
 5094                    icon_path: None,
 5095                    documentation: None,
 5096                    source: CompletionSource::BufferWord {
 5097                        word_range,
 5098                        resolved: false,
 5099                    },
 5100                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5101                    confirm: None,
 5102                }));
 5103
 5104                let menu = if completions.is_empty() {
 5105                    None
 5106                } else {
 5107                    let mut menu = editor.update(cx, |editor, cx| {
 5108                        let languages = editor
 5109                            .workspace
 5110                            .as_ref()
 5111                            .and_then(|(workspace, _)| workspace.upgrade())
 5112                            .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5113                        CompletionsMenu::new(
 5114                            id,
 5115                            sort_completions,
 5116                            show_completion_documentation,
 5117                            ignore_completion_provider,
 5118                            position,
 5119                            buffer.clone(),
 5120                            completions.into(),
 5121                            snippet_sort_order,
 5122                            languages,
 5123                            language,
 5124                            cx,
 5125                        )
 5126                    })?;
 5127
 5128                    menu.filter(
 5129                        if filter_completions {
 5130                            query.as_deref()
 5131                        } else {
 5132                            None
 5133                        },
 5134                        provider,
 5135                        editor.clone(),
 5136                        cx,
 5137                    )
 5138                    .await;
 5139
 5140                    menu.visible().then_some(menu)
 5141                };
 5142
 5143                editor.update_in(cx, |editor, window, cx| {
 5144                    match editor.context_menu.borrow().as_ref() {
 5145                        None => {}
 5146                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5147                            if prev_menu.id > id {
 5148                                return;
 5149                            }
 5150                        }
 5151                        _ => return,
 5152                    }
 5153
 5154                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5155                        let mut menu = menu.unwrap();
 5156                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5157                        crate::hover_popover::hide_hover(editor, cx);
 5158                        *editor.context_menu.borrow_mut() =
 5159                            Some(CodeContextMenu::Completions(menu));
 5160
 5161                        if editor.show_edit_predictions_in_menu() {
 5162                            editor.update_visible_inline_completion(window, cx);
 5163                        } else {
 5164                            editor.discard_inline_completion(false, cx);
 5165                        }
 5166
 5167                        cx.notify();
 5168                    } else if editor.completion_tasks.len() <= 1 {
 5169                        // If there are no more completion tasks and the last menu was
 5170                        // empty, we should hide it.
 5171                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5172                        // If it was already hidden and we don't show inline
 5173                        // completions in the menu, we should also show the
 5174                        // inline-completion when available.
 5175                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5176                            editor.update_visible_inline_completion(window, cx);
 5177                        }
 5178                    }
 5179                })?;
 5180
 5181                anyhow::Ok(())
 5182            }
 5183            .log_err()
 5184            .await
 5185        });
 5186
 5187        self.completion_tasks.push((id, task));
 5188    }
 5189
 5190    #[cfg(feature = "test-support")]
 5191    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5192        let menu = self.context_menu.borrow();
 5193        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5194            let completions = menu.completions.borrow();
 5195            Some(completions.to_vec())
 5196        } else {
 5197            None
 5198        }
 5199    }
 5200
 5201    pub fn with_completions_menu_matching_id<R>(
 5202        &self,
 5203        id: CompletionId,
 5204        on_absent: impl FnOnce() -> R,
 5205        on_match: impl FnOnce(&mut CompletionsMenu) -> R,
 5206    ) -> R {
 5207        let mut context_menu = self.context_menu.borrow_mut();
 5208        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5209            return on_absent();
 5210        };
 5211        if completions_menu.id != id {
 5212            return on_absent();
 5213        }
 5214        on_match(completions_menu)
 5215    }
 5216
 5217    pub fn confirm_completion(
 5218        &mut self,
 5219        action: &ConfirmCompletion,
 5220        window: &mut Window,
 5221        cx: &mut Context<Self>,
 5222    ) -> Option<Task<Result<()>>> {
 5223        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5224        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5225    }
 5226
 5227    pub fn confirm_completion_insert(
 5228        &mut self,
 5229        _: &ConfirmCompletionInsert,
 5230        window: &mut Window,
 5231        cx: &mut Context<Self>,
 5232    ) -> Option<Task<Result<()>>> {
 5233        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5234        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5235    }
 5236
 5237    pub fn confirm_completion_replace(
 5238        &mut self,
 5239        _: &ConfirmCompletionReplace,
 5240        window: &mut Window,
 5241        cx: &mut Context<Self>,
 5242    ) -> Option<Task<Result<()>>> {
 5243        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5244        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5245    }
 5246
 5247    pub fn compose_completion(
 5248        &mut self,
 5249        action: &ComposeCompletion,
 5250        window: &mut Window,
 5251        cx: &mut Context<Self>,
 5252    ) -> Option<Task<Result<()>>> {
 5253        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5254        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5255    }
 5256
 5257    fn do_completion(
 5258        &mut self,
 5259        item_ix: Option<usize>,
 5260        intent: CompletionIntent,
 5261        window: &mut Window,
 5262        cx: &mut Context<Editor>,
 5263    ) -> Option<Task<Result<()>>> {
 5264        use language::ToOffset as _;
 5265
 5266        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5267        else {
 5268            return None;
 5269        };
 5270
 5271        let candidate_id = {
 5272            let entries = completions_menu.entries.borrow();
 5273            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5274            if self.show_edit_predictions_in_menu() {
 5275                self.discard_inline_completion(true, cx);
 5276            }
 5277            mat.candidate_id
 5278        };
 5279
 5280        let buffer_handle = completions_menu.buffer;
 5281        let completion = completions_menu
 5282            .completions
 5283            .borrow()
 5284            .get(candidate_id)?
 5285            .clone();
 5286        cx.stop_propagation();
 5287
 5288        let snapshot = self.buffer.read(cx).snapshot(cx);
 5289        let newest_anchor = self.selections.newest_anchor();
 5290
 5291        let snippet;
 5292        let new_text;
 5293        if completion.is_snippet() {
 5294            let mut snippet_source = completion.new_text.clone();
 5295            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5296                if scope.prefers_label_for_snippet_in_completion() {
 5297                    if let Some(label) = completion.label() {
 5298                        if matches!(
 5299                            completion.kind(),
 5300                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5301                        ) {
 5302                            snippet_source = label;
 5303                        }
 5304                    }
 5305                }
 5306            }
 5307            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5308            new_text = snippet.as_ref().unwrap().text.clone();
 5309        } else {
 5310            snippet = None;
 5311            new_text = completion.new_text.clone();
 5312        };
 5313
 5314        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5315        let buffer = buffer_handle.read(cx);
 5316        let replace_range_multibuffer = {
 5317            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5318            let multibuffer_anchor = snapshot
 5319                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5320                .unwrap()
 5321                ..snapshot
 5322                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5323                    .unwrap();
 5324            multibuffer_anchor.start.to_offset(&snapshot)
 5325                ..multibuffer_anchor.end.to_offset(&snapshot)
 5326        };
 5327        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5328            return None;
 5329        }
 5330
 5331        let old_text = buffer
 5332            .text_for_range(replace_range.clone())
 5333            .collect::<String>();
 5334        let lookbehind = newest_anchor
 5335            .start
 5336            .text_anchor
 5337            .to_offset(buffer)
 5338            .saturating_sub(replace_range.start);
 5339        let lookahead = replace_range
 5340            .end
 5341            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5342        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5343        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5344
 5345        let selections = self.selections.all::<usize>(cx);
 5346        let mut ranges = Vec::new();
 5347        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5348
 5349        for selection in &selections {
 5350            let range = if selection.id == newest_anchor.id {
 5351                replace_range_multibuffer.clone()
 5352            } else {
 5353                let mut range = selection.range();
 5354
 5355                // if prefix is present, don't duplicate it
 5356                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5357                    range.start = range.start.saturating_sub(lookbehind);
 5358
 5359                    // if suffix is also present, mimic the newest cursor and replace it
 5360                    if selection.id != newest_anchor.id
 5361                        && snapshot.contains_str_at(range.end, suffix)
 5362                    {
 5363                        range.end += lookahead;
 5364                    }
 5365                }
 5366                range
 5367            };
 5368
 5369            ranges.push(range.clone());
 5370
 5371            if !self.linked_edit_ranges.is_empty() {
 5372                let start_anchor = snapshot.anchor_before(range.start);
 5373                let end_anchor = snapshot.anchor_after(range.end);
 5374                if let Some(ranges) = self
 5375                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5376                {
 5377                    for (buffer, edits) in ranges {
 5378                        linked_edits
 5379                            .entry(buffer.clone())
 5380                            .or_default()
 5381                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5382                    }
 5383                }
 5384            }
 5385        }
 5386
 5387        cx.emit(EditorEvent::InputHandled {
 5388            utf16_range_to_replace: None,
 5389            text: new_text.clone().into(),
 5390        });
 5391
 5392        self.transact(window, cx, |this, window, cx| {
 5393            if let Some(mut snippet) = snippet {
 5394                snippet.text = new_text.to_string();
 5395                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5396            } else {
 5397                this.buffer.update(cx, |buffer, cx| {
 5398                    let auto_indent = match completion.insert_text_mode {
 5399                        Some(InsertTextMode::AS_IS) => None,
 5400                        _ => this.autoindent_mode.clone(),
 5401                    };
 5402                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5403                    buffer.edit(edits, auto_indent, cx);
 5404                });
 5405            }
 5406            for (buffer, edits) in linked_edits {
 5407                buffer.update(cx, |buffer, cx| {
 5408                    let snapshot = buffer.snapshot();
 5409                    let edits = edits
 5410                        .into_iter()
 5411                        .map(|(range, text)| {
 5412                            use text::ToPoint as TP;
 5413                            let end_point = TP::to_point(&range.end, &snapshot);
 5414                            let start_point = TP::to_point(&range.start, &snapshot);
 5415                            (start_point..end_point, text)
 5416                        })
 5417                        .sorted_by_key(|(range, _)| range.start);
 5418                    buffer.edit(edits, None, cx);
 5419                })
 5420            }
 5421
 5422            this.refresh_inline_completion(true, false, window, cx);
 5423        });
 5424
 5425        let show_new_completions_on_confirm = completion
 5426            .confirm
 5427            .as_ref()
 5428            .map_or(false, |confirm| confirm(intent, window, cx));
 5429        if show_new_completions_on_confirm {
 5430            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5431        }
 5432
 5433        let provider = self.completion_provider.as_ref()?;
 5434        drop(completion);
 5435        let apply_edits = provider.apply_additional_edits_for_completion(
 5436            buffer_handle,
 5437            completions_menu.completions.clone(),
 5438            candidate_id,
 5439            true,
 5440            cx,
 5441        );
 5442
 5443        let editor_settings = EditorSettings::get_global(cx);
 5444        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5445            // After the code completion is finished, users often want to know what signatures are needed.
 5446            // so we should automatically call signature_help
 5447            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5448        }
 5449
 5450        Some(cx.foreground_executor().spawn(async move {
 5451            apply_edits.await?;
 5452            Ok(())
 5453        }))
 5454    }
 5455
 5456    pub fn toggle_code_actions(
 5457        &mut self,
 5458        action: &ToggleCodeActions,
 5459        window: &mut Window,
 5460        cx: &mut Context<Self>,
 5461    ) {
 5462        let quick_launch = action.quick_launch;
 5463        let mut context_menu = self.context_menu.borrow_mut();
 5464        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5465            if code_actions.deployed_from == action.deployed_from {
 5466                // Toggle if we're selecting the same one
 5467                *context_menu = None;
 5468                cx.notify();
 5469                return;
 5470            } else {
 5471                // Otherwise, clear it and start a new one
 5472                *context_menu = None;
 5473                cx.notify();
 5474            }
 5475        }
 5476        drop(context_menu);
 5477        let snapshot = self.snapshot(window, cx);
 5478        let deployed_from = action.deployed_from.clone();
 5479        let mut task = self.code_actions_task.take();
 5480        let action = action.clone();
 5481        cx.spawn_in(window, async move |editor, cx| {
 5482            while let Some(prev_task) = task {
 5483                prev_task.await.log_err();
 5484                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5485            }
 5486
 5487            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5488                if editor.focus_handle.is_focused(window) {
 5489                    let multibuffer_point = match &action.deployed_from {
 5490                        Some(CodeActionSource::Indicator(row)) => {
 5491                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5492                        }
 5493                        _ => editor.selections.newest::<Point>(cx).head(),
 5494                    };
 5495                    let (buffer, buffer_row) = snapshot
 5496                        .buffer_snapshot
 5497                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5498                        .and_then(|(buffer_snapshot, range)| {
 5499                            editor
 5500                                .buffer
 5501                                .read(cx)
 5502                                .buffer(buffer_snapshot.remote_id())
 5503                                .map(|buffer| (buffer, range.start.row))
 5504                        })?;
 5505                    let (_, code_actions) = editor
 5506                        .available_code_actions
 5507                        .clone()
 5508                        .and_then(|(location, code_actions)| {
 5509                            let snapshot = location.buffer.read(cx).snapshot();
 5510                            let point_range = location.range.to_point(&snapshot);
 5511                            let point_range = point_range.start.row..=point_range.end.row;
 5512                            if point_range.contains(&buffer_row) {
 5513                                Some((location, code_actions))
 5514                            } else {
 5515                                None
 5516                            }
 5517                        })
 5518                        .unzip();
 5519                    let buffer_id = buffer.read(cx).remote_id();
 5520                    let tasks = editor
 5521                        .tasks
 5522                        .get(&(buffer_id, buffer_row))
 5523                        .map(|t| Arc::new(t.to_owned()));
 5524                    if tasks.is_none() && code_actions.is_none() {
 5525                        return None;
 5526                    }
 5527
 5528                    editor.completion_tasks.clear();
 5529                    editor.discard_inline_completion(false, cx);
 5530                    let task_context =
 5531                        tasks
 5532                            .as_ref()
 5533                            .zip(editor.project.clone())
 5534                            .map(|(tasks, project)| {
 5535                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5536                            });
 5537
 5538                    Some(cx.spawn_in(window, async move |editor, cx| {
 5539                        let task_context = match task_context {
 5540                            Some(task_context) => task_context.await,
 5541                            None => None,
 5542                        };
 5543                        let resolved_tasks =
 5544                            tasks
 5545                                .zip(task_context.clone())
 5546                                .map(|(tasks, task_context)| ResolvedTasks {
 5547                                    templates: tasks.resolve(&task_context).collect(),
 5548                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5549                                        multibuffer_point.row,
 5550                                        tasks.column,
 5551                                    )),
 5552                                });
 5553                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5554                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5555                                maybe!({
 5556                                    let project = editor.project.as_ref()?;
 5557                                    let dap_store = project.read(cx).dap_store();
 5558                                    let mut scenarios = vec![];
 5559                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5560                                    let buffer = buffer.read(cx);
 5561                                    let language = buffer.language()?;
 5562                                    let file = buffer.file();
 5563                                    let debug_adapter =
 5564                                        language_settings(language.name().into(), file, cx)
 5565                                            .debuggers
 5566                                            .first()
 5567                                            .map(SharedString::from)
 5568                                            .or_else(|| {
 5569                                                language
 5570                                                    .config()
 5571                                                    .debuggers
 5572                                                    .first()
 5573                                                    .map(SharedString::from)
 5574                                            })?;
 5575
 5576                                    dap_store.update(cx, |dap_store, cx| {
 5577                                        for (_, task) in &resolved_tasks.templates {
 5578                                            if let Some(scenario) = dap_store
 5579                                                .debug_scenario_for_build_task(
 5580                                                    task.original_task().clone(),
 5581                                                    debug_adapter.clone().into(),
 5582                                                    task.display_label().to_owned().into(),
 5583                                                    cx,
 5584                                                )
 5585                                            {
 5586                                                scenarios.push(scenario);
 5587                                            }
 5588                                        }
 5589                                    });
 5590                                    Some(scenarios)
 5591                                })
 5592                                .unwrap_or_default()
 5593                            } else {
 5594                                vec![]
 5595                            }
 5596                        })?;
 5597                        let spawn_straight_away = quick_launch
 5598                            && resolved_tasks
 5599                                .as_ref()
 5600                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5601                            && code_actions
 5602                                .as_ref()
 5603                                .map_or(true, |actions| actions.is_empty())
 5604                            && debug_scenarios.is_empty();
 5605                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5606                            crate::hover_popover::hide_hover(editor, cx);
 5607                            *editor.context_menu.borrow_mut() =
 5608                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5609                                    buffer,
 5610                                    actions: CodeActionContents::new(
 5611                                        resolved_tasks,
 5612                                        code_actions,
 5613                                        debug_scenarios,
 5614                                        task_context.unwrap_or_default(),
 5615                                    ),
 5616                                    selected_item: Default::default(),
 5617                                    scroll_handle: UniformListScrollHandle::default(),
 5618                                    deployed_from,
 5619                                }));
 5620                            if spawn_straight_away {
 5621                                if let Some(task) = editor.confirm_code_action(
 5622                                    &ConfirmCodeAction { item_ix: Some(0) },
 5623                                    window,
 5624                                    cx,
 5625                                ) {
 5626                                    cx.notify();
 5627                                    return task;
 5628                                }
 5629                            }
 5630                            cx.notify();
 5631                            Task::ready(Ok(()))
 5632                        }) {
 5633                            task.await
 5634                        } else {
 5635                            Ok(())
 5636                        }
 5637                    }))
 5638                } else {
 5639                    Some(Task::ready(Ok(())))
 5640                }
 5641            })?;
 5642            if let Some(task) = spawned_test_task {
 5643                task.await?;
 5644            }
 5645
 5646            anyhow::Ok(())
 5647        })
 5648        .detach_and_log_err(cx);
 5649    }
 5650
 5651    pub fn confirm_code_action(
 5652        &mut self,
 5653        action: &ConfirmCodeAction,
 5654        window: &mut Window,
 5655        cx: &mut Context<Self>,
 5656    ) -> Option<Task<Result<()>>> {
 5657        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5658
 5659        let actions_menu =
 5660            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5661                menu
 5662            } else {
 5663                return None;
 5664            };
 5665
 5666        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5667        let action = actions_menu.actions.get(action_ix)?;
 5668        let title = action.label();
 5669        let buffer = actions_menu.buffer;
 5670        let workspace = self.workspace()?;
 5671
 5672        match action {
 5673            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5674                workspace.update(cx, |workspace, cx| {
 5675                    workspace.schedule_resolved_task(
 5676                        task_source_kind,
 5677                        resolved_task,
 5678                        false,
 5679                        window,
 5680                        cx,
 5681                    );
 5682
 5683                    Some(Task::ready(Ok(())))
 5684                })
 5685            }
 5686            CodeActionsItem::CodeAction {
 5687                excerpt_id,
 5688                action,
 5689                provider,
 5690            } => {
 5691                let apply_code_action =
 5692                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5693                let workspace = workspace.downgrade();
 5694                Some(cx.spawn_in(window, async move |editor, cx| {
 5695                    let project_transaction = apply_code_action.await?;
 5696                    Self::open_project_transaction(
 5697                        &editor,
 5698                        workspace,
 5699                        project_transaction,
 5700                        title,
 5701                        cx,
 5702                    )
 5703                    .await
 5704                }))
 5705            }
 5706            CodeActionsItem::DebugScenario(scenario) => {
 5707                let context = actions_menu.actions.context.clone();
 5708
 5709                workspace.update(cx, |workspace, cx| {
 5710                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5711                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5712                });
 5713                Some(Task::ready(Ok(())))
 5714            }
 5715        }
 5716    }
 5717
 5718    pub async fn open_project_transaction(
 5719        this: &WeakEntity<Editor>,
 5720        workspace: WeakEntity<Workspace>,
 5721        transaction: ProjectTransaction,
 5722        title: String,
 5723        cx: &mut AsyncWindowContext,
 5724    ) -> Result<()> {
 5725        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5726        cx.update(|_, cx| {
 5727            entries.sort_unstable_by_key(|(buffer, _)| {
 5728                buffer.read(cx).file().map(|f| f.path().clone())
 5729            });
 5730        })?;
 5731
 5732        // If the project transaction's edits are all contained within this editor, then
 5733        // avoid opening a new editor to display them.
 5734
 5735        if let Some((buffer, transaction)) = entries.first() {
 5736            if entries.len() == 1 {
 5737                let excerpt = this.update(cx, |editor, cx| {
 5738                    editor
 5739                        .buffer()
 5740                        .read(cx)
 5741                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5742                })?;
 5743                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5744                    if excerpted_buffer == *buffer {
 5745                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5746                            let excerpt_range = excerpt_range.to_offset(buffer);
 5747                            buffer
 5748                                .edited_ranges_for_transaction::<usize>(transaction)
 5749                                .all(|range| {
 5750                                    excerpt_range.start <= range.start
 5751                                        && excerpt_range.end >= range.end
 5752                                })
 5753                        })?;
 5754
 5755                        if all_edits_within_excerpt {
 5756                            return Ok(());
 5757                        }
 5758                    }
 5759                }
 5760            }
 5761        } else {
 5762            return Ok(());
 5763        }
 5764
 5765        let mut ranges_to_highlight = Vec::new();
 5766        let excerpt_buffer = cx.new(|cx| {
 5767            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5768            for (buffer_handle, transaction) in &entries {
 5769                let edited_ranges = buffer_handle
 5770                    .read(cx)
 5771                    .edited_ranges_for_transaction::<Point>(transaction)
 5772                    .collect::<Vec<_>>();
 5773                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5774                    PathKey::for_buffer(buffer_handle, cx),
 5775                    buffer_handle.clone(),
 5776                    edited_ranges,
 5777                    DEFAULT_MULTIBUFFER_CONTEXT,
 5778                    cx,
 5779                );
 5780
 5781                ranges_to_highlight.extend(ranges);
 5782            }
 5783            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5784            multibuffer
 5785        })?;
 5786
 5787        workspace.update_in(cx, |workspace, window, cx| {
 5788            let project = workspace.project().clone();
 5789            let editor =
 5790                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5791            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5792            editor.update(cx, |editor, cx| {
 5793                editor.highlight_background::<Self>(
 5794                    &ranges_to_highlight,
 5795                    |theme| theme.editor_highlighted_line_background,
 5796                    cx,
 5797                );
 5798            });
 5799        })?;
 5800
 5801        Ok(())
 5802    }
 5803
 5804    pub fn clear_code_action_providers(&mut self) {
 5805        self.code_action_providers.clear();
 5806        self.available_code_actions.take();
 5807    }
 5808
 5809    pub fn add_code_action_provider(
 5810        &mut self,
 5811        provider: Rc<dyn CodeActionProvider>,
 5812        window: &mut Window,
 5813        cx: &mut Context<Self>,
 5814    ) {
 5815        if self
 5816            .code_action_providers
 5817            .iter()
 5818            .any(|existing_provider| existing_provider.id() == provider.id())
 5819        {
 5820            return;
 5821        }
 5822
 5823        self.code_action_providers.push(provider);
 5824        self.refresh_code_actions(window, cx);
 5825    }
 5826
 5827    pub fn remove_code_action_provider(
 5828        &mut self,
 5829        id: Arc<str>,
 5830        window: &mut Window,
 5831        cx: &mut Context<Self>,
 5832    ) {
 5833        self.code_action_providers
 5834            .retain(|provider| provider.id() != id);
 5835        self.refresh_code_actions(window, cx);
 5836    }
 5837
 5838    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5839        !self.code_action_providers.is_empty()
 5840            && EditorSettings::get_global(cx).toolbar.code_actions
 5841    }
 5842
 5843    pub fn has_available_code_actions(&self) -> bool {
 5844        self.available_code_actions
 5845            .as_ref()
 5846            .is_some_and(|(_, actions)| !actions.is_empty())
 5847    }
 5848
 5849    fn render_inline_code_actions(
 5850        &self,
 5851        icon_size: ui::IconSize,
 5852        display_row: DisplayRow,
 5853        is_active: bool,
 5854        cx: &mut Context<Self>,
 5855    ) -> AnyElement {
 5856        let show_tooltip = !self.context_menu_visible();
 5857        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5858            .icon_size(icon_size)
 5859            .shape(ui::IconButtonShape::Square)
 5860            .style(ButtonStyle::Transparent)
 5861            .icon_color(ui::Color::Hidden)
 5862            .toggle_state(is_active)
 5863            .when(show_tooltip, |this| {
 5864                this.tooltip({
 5865                    let focus_handle = self.focus_handle.clone();
 5866                    move |window, cx| {
 5867                        Tooltip::for_action_in(
 5868                            "Toggle Code Actions",
 5869                            &ToggleCodeActions {
 5870                                deployed_from: None,
 5871                                quick_launch: false,
 5872                            },
 5873                            &focus_handle,
 5874                            window,
 5875                            cx,
 5876                        )
 5877                    }
 5878                })
 5879            })
 5880            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5881                window.focus(&editor.focus_handle(cx));
 5882                editor.toggle_code_actions(
 5883                    &crate::actions::ToggleCodeActions {
 5884                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5885                            display_row,
 5886                        )),
 5887                        quick_launch: false,
 5888                    },
 5889                    window,
 5890                    cx,
 5891                );
 5892            }))
 5893            .into_any_element()
 5894    }
 5895
 5896    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5897        &self.context_menu
 5898    }
 5899
 5900    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5901        let newest_selection = self.selections.newest_anchor().clone();
 5902        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5903        let buffer = self.buffer.read(cx);
 5904        if newest_selection.head().diff_base_anchor.is_some() {
 5905            return None;
 5906        }
 5907        let (start_buffer, start) =
 5908            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5909        let (end_buffer, end) =
 5910            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5911        if start_buffer != end_buffer {
 5912            return None;
 5913        }
 5914
 5915        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5916            cx.background_executor()
 5917                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5918                .await;
 5919
 5920            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5921                let providers = this.code_action_providers.clone();
 5922                let tasks = this
 5923                    .code_action_providers
 5924                    .iter()
 5925                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5926                    .collect::<Vec<_>>();
 5927                (providers, tasks)
 5928            })?;
 5929
 5930            let mut actions = Vec::new();
 5931            for (provider, provider_actions) in
 5932                providers.into_iter().zip(future::join_all(tasks).await)
 5933            {
 5934                if let Some(provider_actions) = provider_actions.log_err() {
 5935                    actions.extend(provider_actions.into_iter().map(|action| {
 5936                        AvailableCodeAction {
 5937                            excerpt_id: newest_selection.start.excerpt_id,
 5938                            action,
 5939                            provider: provider.clone(),
 5940                        }
 5941                    }));
 5942                }
 5943            }
 5944
 5945            this.update(cx, |this, cx| {
 5946                this.available_code_actions = if actions.is_empty() {
 5947                    None
 5948                } else {
 5949                    Some((
 5950                        Location {
 5951                            buffer: start_buffer,
 5952                            range: start..end,
 5953                        },
 5954                        actions.into(),
 5955                    ))
 5956                };
 5957                cx.notify();
 5958            })
 5959        }));
 5960        None
 5961    }
 5962
 5963    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5964        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5965            self.show_git_blame_inline = false;
 5966
 5967            self.show_git_blame_inline_delay_task =
 5968                Some(cx.spawn_in(window, async move |this, cx| {
 5969                    cx.background_executor().timer(delay).await;
 5970
 5971                    this.update(cx, |this, cx| {
 5972                        this.show_git_blame_inline = true;
 5973                        cx.notify();
 5974                    })
 5975                    .log_err();
 5976                }));
 5977        }
 5978    }
 5979
 5980    fn show_blame_popover(
 5981        &mut self,
 5982        blame_entry: &BlameEntry,
 5983        position: gpui::Point<Pixels>,
 5984        cx: &mut Context<Self>,
 5985    ) {
 5986        if let Some(state) = &mut self.inline_blame_popover {
 5987            state.hide_task.take();
 5988            cx.notify();
 5989        } else {
 5990            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5991            let show_task = cx.spawn(async move |editor, cx| {
 5992                cx.background_executor()
 5993                    .timer(std::time::Duration::from_millis(delay))
 5994                    .await;
 5995                editor
 5996                    .update(cx, |editor, cx| {
 5997                        if let Some(state) = &mut editor.inline_blame_popover {
 5998                            state.show_task = None;
 5999                            cx.notify();
 6000                        }
 6001                    })
 6002                    .ok();
 6003            });
 6004            let Some(blame) = self.blame.as_ref() else {
 6005                return;
 6006            };
 6007            let blame = blame.read(cx);
 6008            let details = blame.details_for_entry(&blame_entry);
 6009            let markdown = cx.new(|cx| {
 6010                Markdown::new(
 6011                    details
 6012                        .as_ref()
 6013                        .map(|message| message.message.clone())
 6014                        .unwrap_or_default(),
 6015                    None,
 6016                    None,
 6017                    cx,
 6018                )
 6019            });
 6020            self.inline_blame_popover = Some(InlineBlamePopover {
 6021                position,
 6022                show_task: Some(show_task),
 6023                hide_task: None,
 6024                popover_bounds: None,
 6025                popover_state: InlineBlamePopoverState {
 6026                    scroll_handle: ScrollHandle::new(),
 6027                    commit_message: details,
 6028                    markdown,
 6029                },
 6030            });
 6031        }
 6032    }
 6033
 6034    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6035        if let Some(state) = &mut self.inline_blame_popover {
 6036            if state.show_task.is_some() {
 6037                self.inline_blame_popover.take();
 6038                cx.notify();
 6039            } else {
 6040                let hide_task = cx.spawn(async move |editor, cx| {
 6041                    cx.background_executor()
 6042                        .timer(std::time::Duration::from_millis(100))
 6043                        .await;
 6044                    editor
 6045                        .update(cx, |editor, cx| {
 6046                            editor.inline_blame_popover.take();
 6047                            cx.notify();
 6048                        })
 6049                        .ok();
 6050                });
 6051                state.hide_task = Some(hide_task);
 6052            }
 6053        }
 6054    }
 6055
 6056    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6057        if self.pending_rename.is_some() {
 6058            return None;
 6059        }
 6060
 6061        let provider = self.semantics_provider.clone()?;
 6062        let buffer = self.buffer.read(cx);
 6063        let newest_selection = self.selections.newest_anchor().clone();
 6064        let cursor_position = newest_selection.head();
 6065        let (cursor_buffer, cursor_buffer_position) =
 6066            buffer.text_anchor_for_position(cursor_position, cx)?;
 6067        let (tail_buffer, tail_buffer_position) =
 6068            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6069        if cursor_buffer != tail_buffer {
 6070            return None;
 6071        }
 6072
 6073        let snapshot = cursor_buffer.read(cx).snapshot();
 6074        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6075        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6076        if start_word_range != end_word_range {
 6077            self.document_highlights_task.take();
 6078            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6079            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6080            return None;
 6081        }
 6082
 6083        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6084        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6085            cx.background_executor()
 6086                .timer(Duration::from_millis(debounce))
 6087                .await;
 6088
 6089            let highlights = if let Some(highlights) = cx
 6090                .update(|cx| {
 6091                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6092                })
 6093                .ok()
 6094                .flatten()
 6095            {
 6096                highlights.await.log_err()
 6097            } else {
 6098                None
 6099            };
 6100
 6101            if let Some(highlights) = highlights {
 6102                this.update(cx, |this, cx| {
 6103                    if this.pending_rename.is_some() {
 6104                        return;
 6105                    }
 6106
 6107                    let buffer_id = cursor_position.buffer_id;
 6108                    let buffer = this.buffer.read(cx);
 6109                    if !buffer
 6110                        .text_anchor_for_position(cursor_position, cx)
 6111                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6112                    {
 6113                        return;
 6114                    }
 6115
 6116                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6117                    let mut write_ranges = Vec::new();
 6118                    let mut read_ranges = Vec::new();
 6119                    for highlight in highlights {
 6120                        for (excerpt_id, excerpt_range) in
 6121                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6122                        {
 6123                            let start = highlight
 6124                                .range
 6125                                .start
 6126                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6127                            let end = highlight
 6128                                .range
 6129                                .end
 6130                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6131                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6132                                continue;
 6133                            }
 6134
 6135                            let range = Anchor {
 6136                                buffer_id,
 6137                                excerpt_id,
 6138                                text_anchor: start,
 6139                                diff_base_anchor: None,
 6140                            }..Anchor {
 6141                                buffer_id,
 6142                                excerpt_id,
 6143                                text_anchor: end,
 6144                                diff_base_anchor: None,
 6145                            };
 6146                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6147                                write_ranges.push(range);
 6148                            } else {
 6149                                read_ranges.push(range);
 6150                            }
 6151                        }
 6152                    }
 6153
 6154                    this.highlight_background::<DocumentHighlightRead>(
 6155                        &read_ranges,
 6156                        |theme| theme.editor_document_highlight_read_background,
 6157                        cx,
 6158                    );
 6159                    this.highlight_background::<DocumentHighlightWrite>(
 6160                        &write_ranges,
 6161                        |theme| theme.editor_document_highlight_write_background,
 6162                        cx,
 6163                    );
 6164                    cx.notify();
 6165                })
 6166                .log_err();
 6167            }
 6168        }));
 6169        None
 6170    }
 6171
 6172    fn prepare_highlight_query_from_selection(
 6173        &mut self,
 6174        cx: &mut Context<Editor>,
 6175    ) -> Option<(String, Range<Anchor>)> {
 6176        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6177            return None;
 6178        }
 6179        if !EditorSettings::get_global(cx).selection_highlight {
 6180            return None;
 6181        }
 6182        if self.selections.count() != 1 || self.selections.line_mode {
 6183            return None;
 6184        }
 6185        let selection = self.selections.newest::<Point>(cx);
 6186        if selection.is_empty() || selection.start.row != selection.end.row {
 6187            return None;
 6188        }
 6189        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6190        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6191        let query = multi_buffer_snapshot
 6192            .text_for_range(selection_anchor_range.clone())
 6193            .collect::<String>();
 6194        if query.trim().is_empty() {
 6195            return None;
 6196        }
 6197        Some((query, selection_anchor_range))
 6198    }
 6199
 6200    fn update_selection_occurrence_highlights(
 6201        &mut self,
 6202        query_text: String,
 6203        query_range: Range<Anchor>,
 6204        multi_buffer_range_to_query: Range<Point>,
 6205        use_debounce: bool,
 6206        window: &mut Window,
 6207        cx: &mut Context<Editor>,
 6208    ) -> Task<()> {
 6209        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6210        cx.spawn_in(window, async move |editor, cx| {
 6211            if use_debounce {
 6212                cx.background_executor()
 6213                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6214                    .await;
 6215            }
 6216            let match_task = cx.background_spawn(async move {
 6217                let buffer_ranges = multi_buffer_snapshot
 6218                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6219                    .into_iter()
 6220                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6221                let mut match_ranges = Vec::new();
 6222                let Ok(regex) = project::search::SearchQuery::text(
 6223                    query_text.clone(),
 6224                    false,
 6225                    false,
 6226                    false,
 6227                    Default::default(),
 6228                    Default::default(),
 6229                    false,
 6230                    None,
 6231                ) else {
 6232                    return Vec::default();
 6233                };
 6234                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6235                    match_ranges.extend(
 6236                        regex
 6237                            .search(&buffer_snapshot, Some(search_range.clone()))
 6238                            .await
 6239                            .into_iter()
 6240                            .filter_map(|match_range| {
 6241                                let match_start = buffer_snapshot
 6242                                    .anchor_after(search_range.start + match_range.start);
 6243                                let match_end = buffer_snapshot
 6244                                    .anchor_before(search_range.start + match_range.end);
 6245                                let match_anchor_range = Anchor::range_in_buffer(
 6246                                    excerpt_id,
 6247                                    buffer_snapshot.remote_id(),
 6248                                    match_start..match_end,
 6249                                );
 6250                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6251                            }),
 6252                    );
 6253                }
 6254                match_ranges
 6255            });
 6256            let match_ranges = match_task.await;
 6257            editor
 6258                .update_in(cx, |editor, _, cx| {
 6259                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6260                    if !match_ranges.is_empty() {
 6261                        editor.highlight_background::<SelectedTextHighlight>(
 6262                            &match_ranges,
 6263                            |theme| theme.editor_document_highlight_bracket_background,
 6264                            cx,
 6265                        )
 6266                    }
 6267                })
 6268                .log_err();
 6269        })
 6270    }
 6271
 6272    fn refresh_selected_text_highlights(
 6273        &mut self,
 6274        on_buffer_edit: bool,
 6275        window: &mut Window,
 6276        cx: &mut Context<Editor>,
 6277    ) {
 6278        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6279        else {
 6280            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6281            self.quick_selection_highlight_task.take();
 6282            self.debounced_selection_highlight_task.take();
 6283            return;
 6284        };
 6285        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6286        if on_buffer_edit
 6287            || self
 6288                .quick_selection_highlight_task
 6289                .as_ref()
 6290                .map_or(true, |(prev_anchor_range, _)| {
 6291                    prev_anchor_range != &query_range
 6292                })
 6293        {
 6294            let multi_buffer_visible_start = self
 6295                .scroll_manager
 6296                .anchor()
 6297                .anchor
 6298                .to_point(&multi_buffer_snapshot);
 6299            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6300                multi_buffer_visible_start
 6301                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6302                Bias::Left,
 6303            );
 6304            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6305            self.quick_selection_highlight_task = Some((
 6306                query_range.clone(),
 6307                self.update_selection_occurrence_highlights(
 6308                    query_text.clone(),
 6309                    query_range.clone(),
 6310                    multi_buffer_visible_range,
 6311                    false,
 6312                    window,
 6313                    cx,
 6314                ),
 6315            ));
 6316        }
 6317        if on_buffer_edit
 6318            || self
 6319                .debounced_selection_highlight_task
 6320                .as_ref()
 6321                .map_or(true, |(prev_anchor_range, _)| {
 6322                    prev_anchor_range != &query_range
 6323                })
 6324        {
 6325            let multi_buffer_start = multi_buffer_snapshot
 6326                .anchor_before(0)
 6327                .to_point(&multi_buffer_snapshot);
 6328            let multi_buffer_end = multi_buffer_snapshot
 6329                .anchor_after(multi_buffer_snapshot.len())
 6330                .to_point(&multi_buffer_snapshot);
 6331            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6332            self.debounced_selection_highlight_task = Some((
 6333                query_range.clone(),
 6334                self.update_selection_occurrence_highlights(
 6335                    query_text,
 6336                    query_range,
 6337                    multi_buffer_full_range,
 6338                    true,
 6339                    window,
 6340                    cx,
 6341                ),
 6342            ));
 6343        }
 6344    }
 6345
 6346    pub fn refresh_inline_completion(
 6347        &mut self,
 6348        debounce: bool,
 6349        user_requested: bool,
 6350        window: &mut Window,
 6351        cx: &mut Context<Self>,
 6352    ) -> Option<()> {
 6353        let provider = self.edit_prediction_provider()?;
 6354        let cursor = self.selections.newest_anchor().head();
 6355        let (buffer, cursor_buffer_position) =
 6356            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6357
 6358        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6359            self.discard_inline_completion(false, cx);
 6360            return None;
 6361        }
 6362
 6363        if !user_requested
 6364            && (!self.should_show_edit_predictions()
 6365                || !self.is_focused(window)
 6366                || buffer.read(cx).is_empty())
 6367        {
 6368            self.discard_inline_completion(false, cx);
 6369            return None;
 6370        }
 6371
 6372        self.update_visible_inline_completion(window, cx);
 6373        provider.refresh(
 6374            self.project.clone(),
 6375            buffer,
 6376            cursor_buffer_position,
 6377            debounce,
 6378            cx,
 6379        );
 6380        Some(())
 6381    }
 6382
 6383    fn show_edit_predictions_in_menu(&self) -> bool {
 6384        match self.edit_prediction_settings {
 6385            EditPredictionSettings::Disabled => false,
 6386            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6387        }
 6388    }
 6389
 6390    pub fn edit_predictions_enabled(&self) -> bool {
 6391        match self.edit_prediction_settings {
 6392            EditPredictionSettings::Disabled => false,
 6393            EditPredictionSettings::Enabled { .. } => true,
 6394        }
 6395    }
 6396
 6397    fn edit_prediction_requires_modifier(&self) -> bool {
 6398        match self.edit_prediction_settings {
 6399            EditPredictionSettings::Disabled => false,
 6400            EditPredictionSettings::Enabled {
 6401                preview_requires_modifier,
 6402                ..
 6403            } => preview_requires_modifier,
 6404        }
 6405    }
 6406
 6407    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6408        if self.edit_prediction_provider.is_none() {
 6409            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6410        } else {
 6411            let selection = self.selections.newest_anchor();
 6412            let cursor = selection.head();
 6413
 6414            if let Some((buffer, cursor_buffer_position)) =
 6415                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6416            {
 6417                self.edit_prediction_settings =
 6418                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6419            }
 6420        }
 6421    }
 6422
 6423    fn edit_prediction_settings_at_position(
 6424        &self,
 6425        buffer: &Entity<Buffer>,
 6426        buffer_position: language::Anchor,
 6427        cx: &App,
 6428    ) -> EditPredictionSettings {
 6429        if !self.mode.is_full()
 6430            || !self.show_inline_completions_override.unwrap_or(true)
 6431            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6432        {
 6433            return EditPredictionSettings::Disabled;
 6434        }
 6435
 6436        let buffer = buffer.read(cx);
 6437
 6438        let file = buffer.file();
 6439
 6440        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6441            return EditPredictionSettings::Disabled;
 6442        };
 6443
 6444        let by_provider = matches!(
 6445            self.menu_inline_completions_policy,
 6446            MenuInlineCompletionsPolicy::ByProvider
 6447        );
 6448
 6449        let show_in_menu = by_provider
 6450            && self
 6451                .edit_prediction_provider
 6452                .as_ref()
 6453                .map_or(false, |provider| {
 6454                    provider.provider.show_completions_in_menu()
 6455                });
 6456
 6457        let preview_requires_modifier =
 6458            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6459
 6460        EditPredictionSettings::Enabled {
 6461            show_in_menu,
 6462            preview_requires_modifier,
 6463        }
 6464    }
 6465
 6466    fn should_show_edit_predictions(&self) -> bool {
 6467        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6468    }
 6469
 6470    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6471        matches!(
 6472            self.edit_prediction_preview,
 6473            EditPredictionPreview::Active { .. }
 6474        )
 6475    }
 6476
 6477    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6478        let cursor = self.selections.newest_anchor().head();
 6479        if let Some((buffer, cursor_position)) =
 6480            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6481        {
 6482            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6483        } else {
 6484            false
 6485        }
 6486    }
 6487
 6488    pub fn supports_minimap(&self, cx: &App) -> bool {
 6489        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6490    }
 6491
 6492    fn edit_predictions_enabled_in_buffer(
 6493        &self,
 6494        buffer: &Entity<Buffer>,
 6495        buffer_position: language::Anchor,
 6496        cx: &App,
 6497    ) -> bool {
 6498        maybe!({
 6499            if self.read_only(cx) {
 6500                return Some(false);
 6501            }
 6502            let provider = self.edit_prediction_provider()?;
 6503            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6504                return Some(false);
 6505            }
 6506            let buffer = buffer.read(cx);
 6507            let Some(file) = buffer.file() else {
 6508                return Some(true);
 6509            };
 6510            let settings = all_language_settings(Some(file), cx);
 6511            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6512        })
 6513        .unwrap_or(false)
 6514    }
 6515
 6516    fn cycle_inline_completion(
 6517        &mut self,
 6518        direction: Direction,
 6519        window: &mut Window,
 6520        cx: &mut Context<Self>,
 6521    ) -> Option<()> {
 6522        let provider = self.edit_prediction_provider()?;
 6523        let cursor = self.selections.newest_anchor().head();
 6524        let (buffer, cursor_buffer_position) =
 6525            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6526        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6527            return None;
 6528        }
 6529
 6530        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6531        self.update_visible_inline_completion(window, cx);
 6532
 6533        Some(())
 6534    }
 6535
 6536    pub fn show_inline_completion(
 6537        &mut self,
 6538        _: &ShowEditPrediction,
 6539        window: &mut Window,
 6540        cx: &mut Context<Self>,
 6541    ) {
 6542        if !self.has_active_inline_completion() {
 6543            self.refresh_inline_completion(false, true, window, cx);
 6544            return;
 6545        }
 6546
 6547        self.update_visible_inline_completion(window, cx);
 6548    }
 6549
 6550    pub fn display_cursor_names(
 6551        &mut self,
 6552        _: &DisplayCursorNames,
 6553        window: &mut Window,
 6554        cx: &mut Context<Self>,
 6555    ) {
 6556        self.show_cursor_names(window, cx);
 6557    }
 6558
 6559    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6560        self.show_cursor_names = true;
 6561        cx.notify();
 6562        cx.spawn_in(window, async move |this, cx| {
 6563            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6564            this.update(cx, |this, cx| {
 6565                this.show_cursor_names = false;
 6566                cx.notify()
 6567            })
 6568            .ok()
 6569        })
 6570        .detach();
 6571    }
 6572
 6573    pub fn next_edit_prediction(
 6574        &mut self,
 6575        _: &NextEditPrediction,
 6576        window: &mut Window,
 6577        cx: &mut Context<Self>,
 6578    ) {
 6579        if self.has_active_inline_completion() {
 6580            self.cycle_inline_completion(Direction::Next, window, cx);
 6581        } else {
 6582            let is_copilot_disabled = self
 6583                .refresh_inline_completion(false, true, window, cx)
 6584                .is_none();
 6585            if is_copilot_disabled {
 6586                cx.propagate();
 6587            }
 6588        }
 6589    }
 6590
 6591    pub fn previous_edit_prediction(
 6592        &mut self,
 6593        _: &PreviousEditPrediction,
 6594        window: &mut Window,
 6595        cx: &mut Context<Self>,
 6596    ) {
 6597        if self.has_active_inline_completion() {
 6598            self.cycle_inline_completion(Direction::Prev, window, cx);
 6599        } else {
 6600            let is_copilot_disabled = self
 6601                .refresh_inline_completion(false, true, window, cx)
 6602                .is_none();
 6603            if is_copilot_disabled {
 6604                cx.propagate();
 6605            }
 6606        }
 6607    }
 6608
 6609    pub fn accept_edit_prediction(
 6610        &mut self,
 6611        _: &AcceptEditPrediction,
 6612        window: &mut Window,
 6613        cx: &mut Context<Self>,
 6614    ) {
 6615        if self.show_edit_predictions_in_menu() {
 6616            self.hide_context_menu(window, cx);
 6617        }
 6618
 6619        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6620            return;
 6621        };
 6622
 6623        self.report_inline_completion_event(
 6624            active_inline_completion.completion_id.clone(),
 6625            true,
 6626            cx,
 6627        );
 6628
 6629        match &active_inline_completion.completion {
 6630            InlineCompletion::Move { target, .. } => {
 6631                let target = *target;
 6632
 6633                if let Some(position_map) = &self.last_position_map {
 6634                    if position_map
 6635                        .visible_row_range
 6636                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6637                        || !self.edit_prediction_requires_modifier()
 6638                    {
 6639                        self.unfold_ranges(&[target..target], true, false, cx);
 6640                        // Note that this is also done in vim's handler of the Tab action.
 6641                        self.change_selections(
 6642                            Some(Autoscroll::newest()),
 6643                            window,
 6644                            cx,
 6645                            |selections| {
 6646                                selections.select_anchor_ranges([target..target]);
 6647                            },
 6648                        );
 6649                        self.clear_row_highlights::<EditPredictionPreview>();
 6650
 6651                        self.edit_prediction_preview
 6652                            .set_previous_scroll_position(None);
 6653                    } else {
 6654                        self.edit_prediction_preview
 6655                            .set_previous_scroll_position(Some(
 6656                                position_map.snapshot.scroll_anchor,
 6657                            ));
 6658
 6659                        self.highlight_rows::<EditPredictionPreview>(
 6660                            target..target,
 6661                            cx.theme().colors().editor_highlighted_line_background,
 6662                            RowHighlightOptions {
 6663                                autoscroll: true,
 6664                                ..Default::default()
 6665                            },
 6666                            cx,
 6667                        );
 6668                        self.request_autoscroll(Autoscroll::fit(), cx);
 6669                    }
 6670                }
 6671            }
 6672            InlineCompletion::Edit { edits, .. } => {
 6673                if let Some(provider) = self.edit_prediction_provider() {
 6674                    provider.accept(cx);
 6675                }
 6676
 6677                // Store the transaction ID and selections before applying the edit
 6678                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6679
 6680                let snapshot = self.buffer.read(cx).snapshot(cx);
 6681                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6682
 6683                self.buffer.update(cx, |buffer, cx| {
 6684                    buffer.edit(edits.iter().cloned(), None, cx)
 6685                });
 6686
 6687                self.change_selections(None, window, cx, |s| {
 6688                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6689                });
 6690
 6691                let selections = self.selections.disjoint_anchors();
 6692                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6693                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6694                    if has_new_transaction {
 6695                        self.selection_history
 6696                            .insert_transaction(transaction_id_now, selections);
 6697                    }
 6698                }
 6699
 6700                self.update_visible_inline_completion(window, cx);
 6701                if self.active_inline_completion.is_none() {
 6702                    self.refresh_inline_completion(true, true, window, cx);
 6703                }
 6704
 6705                cx.notify();
 6706            }
 6707        }
 6708
 6709        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6710    }
 6711
 6712    pub fn accept_partial_inline_completion(
 6713        &mut self,
 6714        _: &AcceptPartialEditPrediction,
 6715        window: &mut Window,
 6716        cx: &mut Context<Self>,
 6717    ) {
 6718        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6719            return;
 6720        };
 6721        if self.selections.count() != 1 {
 6722            return;
 6723        }
 6724
 6725        self.report_inline_completion_event(
 6726            active_inline_completion.completion_id.clone(),
 6727            true,
 6728            cx,
 6729        );
 6730
 6731        match &active_inline_completion.completion {
 6732            InlineCompletion::Move { target, .. } => {
 6733                let target = *target;
 6734                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6735                    selections.select_anchor_ranges([target..target]);
 6736                });
 6737            }
 6738            InlineCompletion::Edit { edits, .. } => {
 6739                // Find an insertion that starts at the cursor position.
 6740                let snapshot = self.buffer.read(cx).snapshot(cx);
 6741                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6742                let insertion = edits.iter().find_map(|(range, text)| {
 6743                    let range = range.to_offset(&snapshot);
 6744                    if range.is_empty() && range.start == cursor_offset {
 6745                        Some(text)
 6746                    } else {
 6747                        None
 6748                    }
 6749                });
 6750
 6751                if let Some(text) = insertion {
 6752                    let mut partial_completion = text
 6753                        .chars()
 6754                        .by_ref()
 6755                        .take_while(|c| c.is_alphabetic())
 6756                        .collect::<String>();
 6757                    if partial_completion.is_empty() {
 6758                        partial_completion = text
 6759                            .chars()
 6760                            .by_ref()
 6761                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6762                            .collect::<String>();
 6763                    }
 6764
 6765                    cx.emit(EditorEvent::InputHandled {
 6766                        utf16_range_to_replace: None,
 6767                        text: partial_completion.clone().into(),
 6768                    });
 6769
 6770                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6771
 6772                    self.refresh_inline_completion(true, true, window, cx);
 6773                    cx.notify();
 6774                } else {
 6775                    self.accept_edit_prediction(&Default::default(), window, cx);
 6776                }
 6777            }
 6778        }
 6779    }
 6780
 6781    fn discard_inline_completion(
 6782        &mut self,
 6783        should_report_inline_completion_event: bool,
 6784        cx: &mut Context<Self>,
 6785    ) -> bool {
 6786        if should_report_inline_completion_event {
 6787            let completion_id = self
 6788                .active_inline_completion
 6789                .as_ref()
 6790                .and_then(|active_completion| active_completion.completion_id.clone());
 6791
 6792            self.report_inline_completion_event(completion_id, false, cx);
 6793        }
 6794
 6795        if let Some(provider) = self.edit_prediction_provider() {
 6796            provider.discard(cx);
 6797        }
 6798
 6799        self.take_active_inline_completion(cx)
 6800    }
 6801
 6802    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6803        let Some(provider) = self.edit_prediction_provider() else {
 6804            return;
 6805        };
 6806
 6807        let Some((_, buffer, _)) = self
 6808            .buffer
 6809            .read(cx)
 6810            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6811        else {
 6812            return;
 6813        };
 6814
 6815        let extension = buffer
 6816            .read(cx)
 6817            .file()
 6818            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6819
 6820        let event_type = match accepted {
 6821            true => "Edit Prediction Accepted",
 6822            false => "Edit Prediction Discarded",
 6823        };
 6824        telemetry::event!(
 6825            event_type,
 6826            provider = provider.name(),
 6827            prediction_id = id,
 6828            suggestion_accepted = accepted,
 6829            file_extension = extension,
 6830        );
 6831    }
 6832
 6833    pub fn has_active_inline_completion(&self) -> bool {
 6834        self.active_inline_completion.is_some()
 6835    }
 6836
 6837    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6838        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6839            return false;
 6840        };
 6841
 6842        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6843        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6844        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6845        true
 6846    }
 6847
 6848    /// Returns true when we're displaying the edit prediction popover below the cursor
 6849    /// like we are not previewing and the LSP autocomplete menu is visible
 6850    /// or we are in `when_holding_modifier` mode.
 6851    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6852        if self.edit_prediction_preview_is_active()
 6853            || !self.show_edit_predictions_in_menu()
 6854            || !self.edit_predictions_enabled()
 6855        {
 6856            return false;
 6857        }
 6858
 6859        if self.has_visible_completions_menu() {
 6860            return true;
 6861        }
 6862
 6863        has_completion && self.edit_prediction_requires_modifier()
 6864    }
 6865
 6866    fn handle_modifiers_changed(
 6867        &mut self,
 6868        modifiers: Modifiers,
 6869        position_map: &PositionMap,
 6870        window: &mut Window,
 6871        cx: &mut Context<Self>,
 6872    ) {
 6873        if self.show_edit_predictions_in_menu() {
 6874            self.update_edit_prediction_preview(&modifiers, window, cx);
 6875        }
 6876
 6877        self.update_selection_mode(&modifiers, position_map, window, cx);
 6878
 6879        let mouse_position = window.mouse_position();
 6880        if !position_map.text_hitbox.is_hovered(window) {
 6881            return;
 6882        }
 6883
 6884        self.update_hovered_link(
 6885            position_map.point_for_position(mouse_position),
 6886            &position_map.snapshot,
 6887            modifiers,
 6888            window,
 6889            cx,
 6890        )
 6891    }
 6892
 6893    fn update_selection_mode(
 6894        &mut self,
 6895        modifiers: &Modifiers,
 6896        position_map: &PositionMap,
 6897        window: &mut Window,
 6898        cx: &mut Context<Self>,
 6899    ) {
 6900        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6901            return;
 6902        }
 6903
 6904        let mouse_position = window.mouse_position();
 6905        let point_for_position = position_map.point_for_position(mouse_position);
 6906        let position = point_for_position.previous_valid;
 6907
 6908        self.select(
 6909            SelectPhase::BeginColumnar {
 6910                position,
 6911                reset: false,
 6912                goal_column: point_for_position.exact_unclipped.column(),
 6913            },
 6914            window,
 6915            cx,
 6916        );
 6917    }
 6918
 6919    fn update_edit_prediction_preview(
 6920        &mut self,
 6921        modifiers: &Modifiers,
 6922        window: &mut Window,
 6923        cx: &mut Context<Self>,
 6924    ) {
 6925        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6926        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6927            return;
 6928        };
 6929
 6930        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6931            if matches!(
 6932                self.edit_prediction_preview,
 6933                EditPredictionPreview::Inactive { .. }
 6934            ) {
 6935                self.edit_prediction_preview = EditPredictionPreview::Active {
 6936                    previous_scroll_position: None,
 6937                    since: Instant::now(),
 6938                };
 6939
 6940                self.update_visible_inline_completion(window, cx);
 6941                cx.notify();
 6942            }
 6943        } else if let EditPredictionPreview::Active {
 6944            previous_scroll_position,
 6945            since,
 6946        } = self.edit_prediction_preview
 6947        {
 6948            if let (Some(previous_scroll_position), Some(position_map)) =
 6949                (previous_scroll_position, self.last_position_map.as_ref())
 6950            {
 6951                self.set_scroll_position(
 6952                    previous_scroll_position
 6953                        .scroll_position(&position_map.snapshot.display_snapshot),
 6954                    window,
 6955                    cx,
 6956                );
 6957            }
 6958
 6959            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6960                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6961            };
 6962            self.clear_row_highlights::<EditPredictionPreview>();
 6963            self.update_visible_inline_completion(window, cx);
 6964            cx.notify();
 6965        }
 6966    }
 6967
 6968    fn update_visible_inline_completion(
 6969        &mut self,
 6970        _window: &mut Window,
 6971        cx: &mut Context<Self>,
 6972    ) -> Option<()> {
 6973        let selection = self.selections.newest_anchor();
 6974        let cursor = selection.head();
 6975        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6976        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6977        let excerpt_id = cursor.excerpt_id;
 6978
 6979        let show_in_menu = self.show_edit_predictions_in_menu();
 6980        let completions_menu_has_precedence = !show_in_menu
 6981            && (self.context_menu.borrow().is_some()
 6982                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6983
 6984        if completions_menu_has_precedence
 6985            || !offset_selection.is_empty()
 6986            || self
 6987                .active_inline_completion
 6988                .as_ref()
 6989                .map_or(false, |completion| {
 6990                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6991                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6992                    !invalidation_range.contains(&offset_selection.head())
 6993                })
 6994        {
 6995            self.discard_inline_completion(false, cx);
 6996            return None;
 6997        }
 6998
 6999        self.take_active_inline_completion(cx);
 7000        let Some(provider) = self.edit_prediction_provider() else {
 7001            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7002            return None;
 7003        };
 7004
 7005        let (buffer, cursor_buffer_position) =
 7006            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7007
 7008        self.edit_prediction_settings =
 7009            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7010
 7011        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7012
 7013        if self.edit_prediction_indent_conflict {
 7014            let cursor_point = cursor.to_point(&multibuffer);
 7015
 7016            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7017
 7018            if let Some((_, indent)) = indents.iter().next() {
 7019                if indent.len == cursor_point.column {
 7020                    self.edit_prediction_indent_conflict = false;
 7021                }
 7022            }
 7023        }
 7024
 7025        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7026        let edits = inline_completion
 7027            .edits
 7028            .into_iter()
 7029            .flat_map(|(range, new_text)| {
 7030                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7031                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7032                Some((start..end, new_text))
 7033            })
 7034            .collect::<Vec<_>>();
 7035        if edits.is_empty() {
 7036            return None;
 7037        }
 7038
 7039        let first_edit_start = edits.first().unwrap().0.start;
 7040        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7041        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7042
 7043        let last_edit_end = edits.last().unwrap().0.end;
 7044        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7045        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7046
 7047        let cursor_row = cursor.to_point(&multibuffer).row;
 7048
 7049        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7050
 7051        let mut inlay_ids = Vec::new();
 7052        let invalidation_row_range;
 7053        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7054            Some(cursor_row..edit_end_row)
 7055        } else if cursor_row > edit_end_row {
 7056            Some(edit_start_row..cursor_row)
 7057        } else {
 7058            None
 7059        };
 7060        let is_move =
 7061            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7062        let completion = if is_move {
 7063            invalidation_row_range =
 7064                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7065            let target = first_edit_start;
 7066            InlineCompletion::Move { target, snapshot }
 7067        } else {
 7068            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7069                && !self.inline_completions_hidden_for_vim_mode;
 7070
 7071            if show_completions_in_buffer {
 7072                if edits
 7073                    .iter()
 7074                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7075                {
 7076                    let mut inlays = Vec::new();
 7077                    for (range, new_text) in &edits {
 7078                        let inlay = Inlay::inline_completion(
 7079                            post_inc(&mut self.next_inlay_id),
 7080                            range.start,
 7081                            new_text.as_str(),
 7082                        );
 7083                        inlay_ids.push(inlay.id);
 7084                        inlays.push(inlay);
 7085                    }
 7086
 7087                    self.splice_inlays(&[], inlays, cx);
 7088                } else {
 7089                    let background_color = cx.theme().status().deleted_background;
 7090                    self.highlight_text::<InlineCompletionHighlight>(
 7091                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7092                        HighlightStyle {
 7093                            background_color: Some(background_color),
 7094                            ..Default::default()
 7095                        },
 7096                        cx,
 7097                    );
 7098                }
 7099            }
 7100
 7101            invalidation_row_range = edit_start_row..edit_end_row;
 7102
 7103            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7104                if provider.show_tab_accept_marker() {
 7105                    EditDisplayMode::TabAccept
 7106                } else {
 7107                    EditDisplayMode::Inline
 7108                }
 7109            } else {
 7110                EditDisplayMode::DiffPopover
 7111            };
 7112
 7113            InlineCompletion::Edit {
 7114                edits,
 7115                edit_preview: inline_completion.edit_preview,
 7116                display_mode,
 7117                snapshot,
 7118            }
 7119        };
 7120
 7121        let invalidation_range = multibuffer
 7122            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7123            ..multibuffer.anchor_after(Point::new(
 7124                invalidation_row_range.end,
 7125                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7126            ));
 7127
 7128        self.stale_inline_completion_in_menu = None;
 7129        self.active_inline_completion = Some(InlineCompletionState {
 7130            inlay_ids,
 7131            completion,
 7132            completion_id: inline_completion.id,
 7133            invalidation_range,
 7134        });
 7135
 7136        cx.notify();
 7137
 7138        Some(())
 7139    }
 7140
 7141    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7142        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7143    }
 7144
 7145    fn clear_tasks(&mut self) {
 7146        self.tasks.clear()
 7147    }
 7148
 7149    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7150        if self.tasks.insert(key, value).is_some() {
 7151            // This case should hopefully be rare, but just in case...
 7152            log::error!(
 7153                "multiple different run targets found on a single line, only the last target will be rendered"
 7154            )
 7155        }
 7156    }
 7157
 7158    /// Get all display points of breakpoints that will be rendered within editor
 7159    ///
 7160    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7161    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7162    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7163    fn active_breakpoints(
 7164        &self,
 7165        range: Range<DisplayRow>,
 7166        window: &mut Window,
 7167        cx: &mut Context<Self>,
 7168    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7169        let mut breakpoint_display_points = HashMap::default();
 7170
 7171        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7172            return breakpoint_display_points;
 7173        };
 7174
 7175        let snapshot = self.snapshot(window, cx);
 7176
 7177        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7178        let Some(project) = self.project.as_ref() else {
 7179            return breakpoint_display_points;
 7180        };
 7181
 7182        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7183            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7184
 7185        for (buffer_snapshot, range, excerpt_id) in
 7186            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7187        {
 7188            let Some(buffer) = project
 7189                .read(cx)
 7190                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7191            else {
 7192                continue;
 7193            };
 7194            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7195                &buffer,
 7196                Some(
 7197                    buffer_snapshot.anchor_before(range.start)
 7198                        ..buffer_snapshot.anchor_after(range.end),
 7199                ),
 7200                buffer_snapshot,
 7201                cx,
 7202            );
 7203            for (breakpoint, state) in breakpoints {
 7204                let multi_buffer_anchor =
 7205                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7206                let position = multi_buffer_anchor
 7207                    .to_point(&multi_buffer_snapshot)
 7208                    .to_display_point(&snapshot);
 7209
 7210                breakpoint_display_points.insert(
 7211                    position.row(),
 7212                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7213                );
 7214            }
 7215        }
 7216
 7217        breakpoint_display_points
 7218    }
 7219
 7220    fn breakpoint_context_menu(
 7221        &self,
 7222        anchor: Anchor,
 7223        window: &mut Window,
 7224        cx: &mut Context<Self>,
 7225    ) -> Entity<ui::ContextMenu> {
 7226        let weak_editor = cx.weak_entity();
 7227        let focus_handle = self.focus_handle(cx);
 7228
 7229        let row = self
 7230            .buffer
 7231            .read(cx)
 7232            .snapshot(cx)
 7233            .summary_for_anchor::<Point>(&anchor)
 7234            .row;
 7235
 7236        let breakpoint = self
 7237            .breakpoint_at_row(row, window, cx)
 7238            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7239
 7240        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7241            "Edit Log Breakpoint"
 7242        } else {
 7243            "Set Log Breakpoint"
 7244        };
 7245
 7246        let condition_breakpoint_msg = if breakpoint
 7247            .as_ref()
 7248            .is_some_and(|bp| bp.1.condition.is_some())
 7249        {
 7250            "Edit Condition Breakpoint"
 7251        } else {
 7252            "Set Condition Breakpoint"
 7253        };
 7254
 7255        let hit_condition_breakpoint_msg = if breakpoint
 7256            .as_ref()
 7257            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7258        {
 7259            "Edit Hit Condition Breakpoint"
 7260        } else {
 7261            "Set Hit Condition Breakpoint"
 7262        };
 7263
 7264        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7265            "Unset Breakpoint"
 7266        } else {
 7267            "Set Breakpoint"
 7268        };
 7269
 7270        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7271            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7272
 7273        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7274            BreakpointState::Enabled => Some("Disable"),
 7275            BreakpointState::Disabled => Some("Enable"),
 7276        });
 7277
 7278        let (anchor, breakpoint) =
 7279            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7280
 7281        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7282            menu.on_blur_subscription(Subscription::new(|| {}))
 7283                .context(focus_handle)
 7284                .when(run_to_cursor, |this| {
 7285                    let weak_editor = weak_editor.clone();
 7286                    this.entry("Run to cursor", None, move |window, cx| {
 7287                        weak_editor
 7288                            .update(cx, |editor, cx| {
 7289                                editor.change_selections(None, window, cx, |s| {
 7290                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7291                                });
 7292                            })
 7293                            .ok();
 7294
 7295                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7296                    })
 7297                    .separator()
 7298                })
 7299                .when_some(toggle_state_msg, |this, msg| {
 7300                    this.entry(msg, None, {
 7301                        let weak_editor = weak_editor.clone();
 7302                        let breakpoint = breakpoint.clone();
 7303                        move |_window, cx| {
 7304                            weak_editor
 7305                                .update(cx, |this, cx| {
 7306                                    this.edit_breakpoint_at_anchor(
 7307                                        anchor,
 7308                                        breakpoint.as_ref().clone(),
 7309                                        BreakpointEditAction::InvertState,
 7310                                        cx,
 7311                                    );
 7312                                })
 7313                                .log_err();
 7314                        }
 7315                    })
 7316                })
 7317                .entry(set_breakpoint_msg, None, {
 7318                    let weak_editor = weak_editor.clone();
 7319                    let breakpoint = breakpoint.clone();
 7320                    move |_window, cx| {
 7321                        weak_editor
 7322                            .update(cx, |this, cx| {
 7323                                this.edit_breakpoint_at_anchor(
 7324                                    anchor,
 7325                                    breakpoint.as_ref().clone(),
 7326                                    BreakpointEditAction::Toggle,
 7327                                    cx,
 7328                                );
 7329                            })
 7330                            .log_err();
 7331                    }
 7332                })
 7333                .entry(log_breakpoint_msg, None, {
 7334                    let breakpoint = breakpoint.clone();
 7335                    let weak_editor = weak_editor.clone();
 7336                    move |window, cx| {
 7337                        weak_editor
 7338                            .update(cx, |this, cx| {
 7339                                this.add_edit_breakpoint_block(
 7340                                    anchor,
 7341                                    breakpoint.as_ref(),
 7342                                    BreakpointPromptEditAction::Log,
 7343                                    window,
 7344                                    cx,
 7345                                );
 7346                            })
 7347                            .log_err();
 7348                    }
 7349                })
 7350                .entry(condition_breakpoint_msg, None, {
 7351                    let breakpoint = breakpoint.clone();
 7352                    let weak_editor = weak_editor.clone();
 7353                    move |window, cx| {
 7354                        weak_editor
 7355                            .update(cx, |this, cx| {
 7356                                this.add_edit_breakpoint_block(
 7357                                    anchor,
 7358                                    breakpoint.as_ref(),
 7359                                    BreakpointPromptEditAction::Condition,
 7360                                    window,
 7361                                    cx,
 7362                                );
 7363                            })
 7364                            .log_err();
 7365                    }
 7366                })
 7367                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7368                    weak_editor
 7369                        .update(cx, |this, cx| {
 7370                            this.add_edit_breakpoint_block(
 7371                                anchor,
 7372                                breakpoint.as_ref(),
 7373                                BreakpointPromptEditAction::HitCondition,
 7374                                window,
 7375                                cx,
 7376                            );
 7377                        })
 7378                        .log_err();
 7379                })
 7380        })
 7381    }
 7382
 7383    fn render_breakpoint(
 7384        &self,
 7385        position: Anchor,
 7386        row: DisplayRow,
 7387        breakpoint: &Breakpoint,
 7388        state: Option<BreakpointSessionState>,
 7389        cx: &mut Context<Self>,
 7390    ) -> IconButton {
 7391        let is_rejected = state.is_some_and(|s| !s.verified);
 7392        // Is it a breakpoint that shows up when hovering over gutter?
 7393        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7394            (false, false),
 7395            |PhantomBreakpointIndicator {
 7396                 is_active,
 7397                 display_row,
 7398                 collides_with_existing_breakpoint,
 7399             }| {
 7400                (
 7401                    is_active && display_row == row,
 7402                    collides_with_existing_breakpoint,
 7403                )
 7404            },
 7405        );
 7406
 7407        let (color, icon) = {
 7408            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7409                (false, false) => ui::IconName::DebugBreakpoint,
 7410                (true, false) => ui::IconName::DebugLogBreakpoint,
 7411                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7412                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7413            };
 7414
 7415            let color = if is_phantom {
 7416                Color::Hint
 7417            } else if is_rejected {
 7418                Color::Disabled
 7419            } else {
 7420                Color::Debugger
 7421            };
 7422
 7423            (color, icon)
 7424        };
 7425
 7426        let breakpoint = Arc::from(breakpoint.clone());
 7427
 7428        let alt_as_text = gpui::Keystroke {
 7429            modifiers: Modifiers::secondary_key(),
 7430            ..Default::default()
 7431        };
 7432        let primary_action_text = if breakpoint.is_disabled() {
 7433            "Enable breakpoint"
 7434        } else if is_phantom && !collides_with_existing {
 7435            "Set breakpoint"
 7436        } else {
 7437            "Unset breakpoint"
 7438        };
 7439        let focus_handle = self.focus_handle.clone();
 7440
 7441        let meta = if is_rejected {
 7442            SharedString::from("No executable code is associated with this line.")
 7443        } else if collides_with_existing && !breakpoint.is_disabled() {
 7444            SharedString::from(format!(
 7445                "{alt_as_text}-click to disable,\nright-click for more options."
 7446            ))
 7447        } else {
 7448            SharedString::from("Right-click for more options.")
 7449        };
 7450        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7451            .icon_size(IconSize::XSmall)
 7452            .size(ui::ButtonSize::None)
 7453            .when(is_rejected, |this| {
 7454                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7455            })
 7456            .icon_color(color)
 7457            .style(ButtonStyle::Transparent)
 7458            .on_click(cx.listener({
 7459                let breakpoint = breakpoint.clone();
 7460
 7461                move |editor, event: &ClickEvent, window, cx| {
 7462                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7463                        BreakpointEditAction::InvertState
 7464                    } else {
 7465                        BreakpointEditAction::Toggle
 7466                    };
 7467
 7468                    window.focus(&editor.focus_handle(cx));
 7469                    editor.edit_breakpoint_at_anchor(
 7470                        position,
 7471                        breakpoint.as_ref().clone(),
 7472                        edit_action,
 7473                        cx,
 7474                    );
 7475                }
 7476            }))
 7477            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7478                editor.set_breakpoint_context_menu(
 7479                    row,
 7480                    Some(position),
 7481                    event.down.position,
 7482                    window,
 7483                    cx,
 7484                );
 7485            }))
 7486            .tooltip(move |window, cx| {
 7487                Tooltip::with_meta_in(
 7488                    primary_action_text,
 7489                    Some(&ToggleBreakpoint),
 7490                    meta.clone(),
 7491                    &focus_handle,
 7492                    window,
 7493                    cx,
 7494                )
 7495            })
 7496    }
 7497
 7498    fn build_tasks_context(
 7499        project: &Entity<Project>,
 7500        buffer: &Entity<Buffer>,
 7501        buffer_row: u32,
 7502        tasks: &Arc<RunnableTasks>,
 7503        cx: &mut Context<Self>,
 7504    ) -> Task<Option<task::TaskContext>> {
 7505        let position = Point::new(buffer_row, tasks.column);
 7506        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7507        let location = Location {
 7508            buffer: buffer.clone(),
 7509            range: range_start..range_start,
 7510        };
 7511        // Fill in the environmental variables from the tree-sitter captures
 7512        let mut captured_task_variables = TaskVariables::default();
 7513        for (capture_name, value) in tasks.extra_variables.clone() {
 7514            captured_task_variables.insert(
 7515                task::VariableName::Custom(capture_name.into()),
 7516                value.clone(),
 7517            );
 7518        }
 7519        project.update(cx, |project, cx| {
 7520            project.task_store().update(cx, |task_store, cx| {
 7521                task_store.task_context_for_location(captured_task_variables, location, cx)
 7522            })
 7523        })
 7524    }
 7525
 7526    pub fn spawn_nearest_task(
 7527        &mut self,
 7528        action: &SpawnNearestTask,
 7529        window: &mut Window,
 7530        cx: &mut Context<Self>,
 7531    ) {
 7532        let Some((workspace, _)) = self.workspace.clone() else {
 7533            return;
 7534        };
 7535        let Some(project) = self.project.clone() else {
 7536            return;
 7537        };
 7538
 7539        // Try to find a closest, enclosing node using tree-sitter that has a
 7540        // task
 7541        let Some((buffer, buffer_row, tasks)) = self
 7542            .find_enclosing_node_task(cx)
 7543            // Or find the task that's closest in row-distance.
 7544            .or_else(|| self.find_closest_task(cx))
 7545        else {
 7546            return;
 7547        };
 7548
 7549        let reveal_strategy = action.reveal;
 7550        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7551        cx.spawn_in(window, async move |_, cx| {
 7552            let context = task_context.await?;
 7553            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7554
 7555            let resolved = &mut resolved_task.resolved;
 7556            resolved.reveal = reveal_strategy;
 7557
 7558            workspace
 7559                .update_in(cx, |workspace, window, cx| {
 7560                    workspace.schedule_resolved_task(
 7561                        task_source_kind,
 7562                        resolved_task,
 7563                        false,
 7564                        window,
 7565                        cx,
 7566                    );
 7567                })
 7568                .ok()
 7569        })
 7570        .detach();
 7571    }
 7572
 7573    fn find_closest_task(
 7574        &mut self,
 7575        cx: &mut Context<Self>,
 7576    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7577        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7578
 7579        let ((buffer_id, row), tasks) = self
 7580            .tasks
 7581            .iter()
 7582            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7583
 7584        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7585        let tasks = Arc::new(tasks.to_owned());
 7586        Some((buffer, *row, tasks))
 7587    }
 7588
 7589    fn find_enclosing_node_task(
 7590        &mut self,
 7591        cx: &mut Context<Self>,
 7592    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7593        let snapshot = self.buffer.read(cx).snapshot(cx);
 7594        let offset = self.selections.newest::<usize>(cx).head();
 7595        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7596        let buffer_id = excerpt.buffer().remote_id();
 7597
 7598        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7599        let mut cursor = layer.node().walk();
 7600
 7601        while cursor.goto_first_child_for_byte(offset).is_some() {
 7602            if cursor.node().end_byte() == offset {
 7603                cursor.goto_next_sibling();
 7604            }
 7605        }
 7606
 7607        // Ascend to the smallest ancestor that contains the range and has a task.
 7608        loop {
 7609            let node = cursor.node();
 7610            let node_range = node.byte_range();
 7611            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7612
 7613            // Check if this node contains our offset
 7614            if node_range.start <= offset && node_range.end >= offset {
 7615                // If it contains offset, check for task
 7616                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7617                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7618                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7619                }
 7620            }
 7621
 7622            if !cursor.goto_parent() {
 7623                break;
 7624            }
 7625        }
 7626        None
 7627    }
 7628
 7629    fn render_run_indicator(
 7630        &self,
 7631        _style: &EditorStyle,
 7632        is_active: bool,
 7633        row: DisplayRow,
 7634        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7635        cx: &mut Context<Self>,
 7636    ) -> IconButton {
 7637        let color = Color::Muted;
 7638        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7639
 7640        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7641            .shape(ui::IconButtonShape::Square)
 7642            .icon_size(IconSize::XSmall)
 7643            .icon_color(color)
 7644            .toggle_state(is_active)
 7645            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7646                let quick_launch = e.down.button == MouseButton::Left;
 7647                window.focus(&editor.focus_handle(cx));
 7648                editor.toggle_code_actions(
 7649                    &ToggleCodeActions {
 7650                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7651                        quick_launch,
 7652                    },
 7653                    window,
 7654                    cx,
 7655                );
 7656            }))
 7657            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7658                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7659            }))
 7660    }
 7661
 7662    pub fn context_menu_visible(&self) -> bool {
 7663        !self.edit_prediction_preview_is_active()
 7664            && self
 7665                .context_menu
 7666                .borrow()
 7667                .as_ref()
 7668                .map_or(false, |menu| menu.visible())
 7669    }
 7670
 7671    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7672        self.context_menu
 7673            .borrow()
 7674            .as_ref()
 7675            .map(|menu| menu.origin())
 7676    }
 7677
 7678    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7679        self.context_menu_options = Some(options);
 7680    }
 7681
 7682    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7683    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7684
 7685    fn render_edit_prediction_popover(
 7686        &mut self,
 7687        text_bounds: &Bounds<Pixels>,
 7688        content_origin: gpui::Point<Pixels>,
 7689        right_margin: Pixels,
 7690        editor_snapshot: &EditorSnapshot,
 7691        visible_row_range: Range<DisplayRow>,
 7692        scroll_top: f32,
 7693        scroll_bottom: f32,
 7694        line_layouts: &[LineWithInvisibles],
 7695        line_height: Pixels,
 7696        scroll_pixel_position: gpui::Point<Pixels>,
 7697        newest_selection_head: Option<DisplayPoint>,
 7698        editor_width: Pixels,
 7699        style: &EditorStyle,
 7700        window: &mut Window,
 7701        cx: &mut App,
 7702    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7703        if self.mode().is_minimap() {
 7704            return None;
 7705        }
 7706        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7707
 7708        if self.edit_prediction_visible_in_cursor_popover(true) {
 7709            return None;
 7710        }
 7711
 7712        match &active_inline_completion.completion {
 7713            InlineCompletion::Move { target, .. } => {
 7714                let target_display_point = target.to_display_point(editor_snapshot);
 7715
 7716                if self.edit_prediction_requires_modifier() {
 7717                    if !self.edit_prediction_preview_is_active() {
 7718                        return None;
 7719                    }
 7720
 7721                    self.render_edit_prediction_modifier_jump_popover(
 7722                        text_bounds,
 7723                        content_origin,
 7724                        visible_row_range,
 7725                        line_layouts,
 7726                        line_height,
 7727                        scroll_pixel_position,
 7728                        newest_selection_head,
 7729                        target_display_point,
 7730                        window,
 7731                        cx,
 7732                    )
 7733                } else {
 7734                    self.render_edit_prediction_eager_jump_popover(
 7735                        text_bounds,
 7736                        content_origin,
 7737                        editor_snapshot,
 7738                        visible_row_range,
 7739                        scroll_top,
 7740                        scroll_bottom,
 7741                        line_height,
 7742                        scroll_pixel_position,
 7743                        target_display_point,
 7744                        editor_width,
 7745                        window,
 7746                        cx,
 7747                    )
 7748                }
 7749            }
 7750            InlineCompletion::Edit {
 7751                display_mode: EditDisplayMode::Inline,
 7752                ..
 7753            } => None,
 7754            InlineCompletion::Edit {
 7755                display_mode: EditDisplayMode::TabAccept,
 7756                edits,
 7757                ..
 7758            } => {
 7759                let range = &edits.first()?.0;
 7760                let target_display_point = range.end.to_display_point(editor_snapshot);
 7761
 7762                self.render_edit_prediction_end_of_line_popover(
 7763                    "Accept",
 7764                    editor_snapshot,
 7765                    visible_row_range,
 7766                    target_display_point,
 7767                    line_height,
 7768                    scroll_pixel_position,
 7769                    content_origin,
 7770                    editor_width,
 7771                    window,
 7772                    cx,
 7773                )
 7774            }
 7775            InlineCompletion::Edit {
 7776                edits,
 7777                edit_preview,
 7778                display_mode: EditDisplayMode::DiffPopover,
 7779                snapshot,
 7780            } => self.render_edit_prediction_diff_popover(
 7781                text_bounds,
 7782                content_origin,
 7783                right_margin,
 7784                editor_snapshot,
 7785                visible_row_range,
 7786                line_layouts,
 7787                line_height,
 7788                scroll_pixel_position,
 7789                newest_selection_head,
 7790                editor_width,
 7791                style,
 7792                edits,
 7793                edit_preview,
 7794                snapshot,
 7795                window,
 7796                cx,
 7797            ),
 7798        }
 7799    }
 7800
 7801    fn render_edit_prediction_modifier_jump_popover(
 7802        &mut self,
 7803        text_bounds: &Bounds<Pixels>,
 7804        content_origin: gpui::Point<Pixels>,
 7805        visible_row_range: Range<DisplayRow>,
 7806        line_layouts: &[LineWithInvisibles],
 7807        line_height: Pixels,
 7808        scroll_pixel_position: gpui::Point<Pixels>,
 7809        newest_selection_head: Option<DisplayPoint>,
 7810        target_display_point: DisplayPoint,
 7811        window: &mut Window,
 7812        cx: &mut App,
 7813    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7814        let scrolled_content_origin =
 7815            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7816
 7817        const SCROLL_PADDING_Y: Pixels = px(12.);
 7818
 7819        if target_display_point.row() < visible_row_range.start {
 7820            return self.render_edit_prediction_scroll_popover(
 7821                |_| SCROLL_PADDING_Y,
 7822                IconName::ArrowUp,
 7823                visible_row_range,
 7824                line_layouts,
 7825                newest_selection_head,
 7826                scrolled_content_origin,
 7827                window,
 7828                cx,
 7829            );
 7830        } else if target_display_point.row() >= visible_row_range.end {
 7831            return self.render_edit_prediction_scroll_popover(
 7832                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7833                IconName::ArrowDown,
 7834                visible_row_range,
 7835                line_layouts,
 7836                newest_selection_head,
 7837                scrolled_content_origin,
 7838                window,
 7839                cx,
 7840            );
 7841        }
 7842
 7843        const POLE_WIDTH: Pixels = px(2.);
 7844
 7845        let line_layout =
 7846            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7847        let target_column = target_display_point.column() as usize;
 7848
 7849        let target_x = line_layout.x_for_index(target_column);
 7850        let target_y =
 7851            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7852
 7853        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7854
 7855        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7856        border_color.l += 0.001;
 7857
 7858        let mut element = v_flex()
 7859            .items_end()
 7860            .when(flag_on_right, |el| el.items_start())
 7861            .child(if flag_on_right {
 7862                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7863                    .rounded_bl(px(0.))
 7864                    .rounded_tl(px(0.))
 7865                    .border_l_2()
 7866                    .border_color(border_color)
 7867            } else {
 7868                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7869                    .rounded_br(px(0.))
 7870                    .rounded_tr(px(0.))
 7871                    .border_r_2()
 7872                    .border_color(border_color)
 7873            })
 7874            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7875            .into_any();
 7876
 7877        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7878
 7879        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7880            - point(
 7881                if flag_on_right {
 7882                    POLE_WIDTH
 7883                } else {
 7884                    size.width - POLE_WIDTH
 7885                },
 7886                size.height - line_height,
 7887            );
 7888
 7889        origin.x = origin.x.max(content_origin.x);
 7890
 7891        element.prepaint_at(origin, window, cx);
 7892
 7893        Some((element, origin))
 7894    }
 7895
 7896    fn render_edit_prediction_scroll_popover(
 7897        &mut self,
 7898        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7899        scroll_icon: IconName,
 7900        visible_row_range: Range<DisplayRow>,
 7901        line_layouts: &[LineWithInvisibles],
 7902        newest_selection_head: Option<DisplayPoint>,
 7903        scrolled_content_origin: gpui::Point<Pixels>,
 7904        window: &mut Window,
 7905        cx: &mut App,
 7906    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7907        let mut element = self
 7908            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7909            .into_any();
 7910
 7911        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7912
 7913        let cursor = newest_selection_head?;
 7914        let cursor_row_layout =
 7915            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7916        let cursor_column = cursor.column() as usize;
 7917
 7918        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7919
 7920        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7921
 7922        element.prepaint_at(origin, window, cx);
 7923        Some((element, origin))
 7924    }
 7925
 7926    fn render_edit_prediction_eager_jump_popover(
 7927        &mut self,
 7928        text_bounds: &Bounds<Pixels>,
 7929        content_origin: gpui::Point<Pixels>,
 7930        editor_snapshot: &EditorSnapshot,
 7931        visible_row_range: Range<DisplayRow>,
 7932        scroll_top: f32,
 7933        scroll_bottom: f32,
 7934        line_height: Pixels,
 7935        scroll_pixel_position: gpui::Point<Pixels>,
 7936        target_display_point: DisplayPoint,
 7937        editor_width: Pixels,
 7938        window: &mut Window,
 7939        cx: &mut App,
 7940    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7941        if target_display_point.row().as_f32() < scroll_top {
 7942            let mut element = self
 7943                .render_edit_prediction_line_popover(
 7944                    "Jump to Edit",
 7945                    Some(IconName::ArrowUp),
 7946                    window,
 7947                    cx,
 7948                )?
 7949                .into_any();
 7950
 7951            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7952            let offset = point(
 7953                (text_bounds.size.width - size.width) / 2.,
 7954                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7955            );
 7956
 7957            let origin = text_bounds.origin + offset;
 7958            element.prepaint_at(origin, window, cx);
 7959            Some((element, origin))
 7960        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7961            let mut element = self
 7962                .render_edit_prediction_line_popover(
 7963                    "Jump to Edit",
 7964                    Some(IconName::ArrowDown),
 7965                    window,
 7966                    cx,
 7967                )?
 7968                .into_any();
 7969
 7970            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7971            let offset = point(
 7972                (text_bounds.size.width - size.width) / 2.,
 7973                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7974            );
 7975
 7976            let origin = text_bounds.origin + offset;
 7977            element.prepaint_at(origin, window, cx);
 7978            Some((element, origin))
 7979        } else {
 7980            self.render_edit_prediction_end_of_line_popover(
 7981                "Jump to Edit",
 7982                editor_snapshot,
 7983                visible_row_range,
 7984                target_display_point,
 7985                line_height,
 7986                scroll_pixel_position,
 7987                content_origin,
 7988                editor_width,
 7989                window,
 7990                cx,
 7991            )
 7992        }
 7993    }
 7994
 7995    fn render_edit_prediction_end_of_line_popover(
 7996        self: &mut Editor,
 7997        label: &'static str,
 7998        editor_snapshot: &EditorSnapshot,
 7999        visible_row_range: Range<DisplayRow>,
 8000        target_display_point: DisplayPoint,
 8001        line_height: Pixels,
 8002        scroll_pixel_position: gpui::Point<Pixels>,
 8003        content_origin: gpui::Point<Pixels>,
 8004        editor_width: Pixels,
 8005        window: &mut Window,
 8006        cx: &mut App,
 8007    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8008        let target_line_end = DisplayPoint::new(
 8009            target_display_point.row(),
 8010            editor_snapshot.line_len(target_display_point.row()),
 8011        );
 8012
 8013        let mut element = self
 8014            .render_edit_prediction_line_popover(label, None, window, cx)?
 8015            .into_any();
 8016
 8017        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8018
 8019        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8020
 8021        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8022        let mut origin = start_point
 8023            + line_origin
 8024            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8025        origin.x = origin.x.max(content_origin.x);
 8026
 8027        let max_x = content_origin.x + editor_width - size.width;
 8028
 8029        if origin.x > max_x {
 8030            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8031
 8032            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8033                origin.y += offset;
 8034                IconName::ArrowUp
 8035            } else {
 8036                origin.y -= offset;
 8037                IconName::ArrowDown
 8038            };
 8039
 8040            element = self
 8041                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8042                .into_any();
 8043
 8044            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8045
 8046            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8047        }
 8048
 8049        element.prepaint_at(origin, window, cx);
 8050        Some((element, origin))
 8051    }
 8052
 8053    fn render_edit_prediction_diff_popover(
 8054        self: &Editor,
 8055        text_bounds: &Bounds<Pixels>,
 8056        content_origin: gpui::Point<Pixels>,
 8057        right_margin: Pixels,
 8058        editor_snapshot: &EditorSnapshot,
 8059        visible_row_range: Range<DisplayRow>,
 8060        line_layouts: &[LineWithInvisibles],
 8061        line_height: Pixels,
 8062        scroll_pixel_position: gpui::Point<Pixels>,
 8063        newest_selection_head: Option<DisplayPoint>,
 8064        editor_width: Pixels,
 8065        style: &EditorStyle,
 8066        edits: &Vec<(Range<Anchor>, String)>,
 8067        edit_preview: &Option<language::EditPreview>,
 8068        snapshot: &language::BufferSnapshot,
 8069        window: &mut Window,
 8070        cx: &mut App,
 8071    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8072        let edit_start = edits
 8073            .first()
 8074            .unwrap()
 8075            .0
 8076            .start
 8077            .to_display_point(editor_snapshot);
 8078        let edit_end = edits
 8079            .last()
 8080            .unwrap()
 8081            .0
 8082            .end
 8083            .to_display_point(editor_snapshot);
 8084
 8085        let is_visible = visible_row_range.contains(&edit_start.row())
 8086            || visible_row_range.contains(&edit_end.row());
 8087        if !is_visible {
 8088            return None;
 8089        }
 8090
 8091        let highlighted_edits =
 8092            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8093
 8094        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8095        let line_count = highlighted_edits.text.lines().count();
 8096
 8097        const BORDER_WIDTH: Pixels = px(1.);
 8098
 8099        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8100        let has_keybind = keybind.is_some();
 8101
 8102        let mut element = h_flex()
 8103            .items_start()
 8104            .child(
 8105                h_flex()
 8106                    .bg(cx.theme().colors().editor_background)
 8107                    .border(BORDER_WIDTH)
 8108                    .shadow_sm()
 8109                    .border_color(cx.theme().colors().border)
 8110                    .rounded_l_lg()
 8111                    .when(line_count > 1, |el| el.rounded_br_lg())
 8112                    .pr_1()
 8113                    .child(styled_text),
 8114            )
 8115            .child(
 8116                h_flex()
 8117                    .h(line_height + BORDER_WIDTH * 2.)
 8118                    .px_1p5()
 8119                    .gap_1()
 8120                    // Workaround: For some reason, there's a gap if we don't do this
 8121                    .ml(-BORDER_WIDTH)
 8122                    .shadow(vec![gpui::BoxShadow {
 8123                        color: gpui::black().opacity(0.05),
 8124                        offset: point(px(1.), px(1.)),
 8125                        blur_radius: px(2.),
 8126                        spread_radius: px(0.),
 8127                    }])
 8128                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8129                    .border(BORDER_WIDTH)
 8130                    .border_color(cx.theme().colors().border)
 8131                    .rounded_r_lg()
 8132                    .id("edit_prediction_diff_popover_keybind")
 8133                    .when(!has_keybind, |el| {
 8134                        let status_colors = cx.theme().status();
 8135
 8136                        el.bg(status_colors.error_background)
 8137                            .border_color(status_colors.error.opacity(0.6))
 8138                            .child(Icon::new(IconName::Info).color(Color::Error))
 8139                            .cursor_default()
 8140                            .hoverable_tooltip(move |_window, cx| {
 8141                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8142                            })
 8143                    })
 8144                    .children(keybind),
 8145            )
 8146            .into_any();
 8147
 8148        let longest_row =
 8149            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8150        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8151            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8152        } else {
 8153            layout_line(
 8154                longest_row,
 8155                editor_snapshot,
 8156                style,
 8157                editor_width,
 8158                |_| false,
 8159                window,
 8160                cx,
 8161            )
 8162            .width
 8163        };
 8164
 8165        let viewport_bounds =
 8166            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8167                right: -right_margin,
 8168                ..Default::default()
 8169            });
 8170
 8171        let x_after_longest =
 8172            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8173                - scroll_pixel_position.x;
 8174
 8175        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8176
 8177        // Fully visible if it can be displayed within the window (allow overlapping other
 8178        // panes). However, this is only allowed if the popover starts within text_bounds.
 8179        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8180            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8181
 8182        let mut origin = if can_position_to_the_right {
 8183            point(
 8184                x_after_longest,
 8185                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8186                    - scroll_pixel_position.y,
 8187            )
 8188        } else {
 8189            let cursor_row = newest_selection_head.map(|head| head.row());
 8190            let above_edit = edit_start
 8191                .row()
 8192                .0
 8193                .checked_sub(line_count as u32)
 8194                .map(DisplayRow);
 8195            let below_edit = Some(edit_end.row() + 1);
 8196            let above_cursor =
 8197                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8198            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8199
 8200            // Place the edit popover adjacent to the edit if there is a location
 8201            // available that is onscreen and does not obscure the cursor. Otherwise,
 8202            // place it adjacent to the cursor.
 8203            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8204                .into_iter()
 8205                .flatten()
 8206                .find(|&start_row| {
 8207                    let end_row = start_row + line_count as u32;
 8208                    visible_row_range.contains(&start_row)
 8209                        && visible_row_range.contains(&end_row)
 8210                        && cursor_row.map_or(true, |cursor_row| {
 8211                            !((start_row..end_row).contains(&cursor_row))
 8212                        })
 8213                })?;
 8214
 8215            content_origin
 8216                + point(
 8217                    -scroll_pixel_position.x,
 8218                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8219                )
 8220        };
 8221
 8222        origin.x -= BORDER_WIDTH;
 8223
 8224        window.defer_draw(element, origin, 1);
 8225
 8226        // Do not return an element, since it will already be drawn due to defer_draw.
 8227        None
 8228    }
 8229
 8230    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8231        px(30.)
 8232    }
 8233
 8234    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8235        if self.read_only(cx) {
 8236            cx.theme().players().read_only()
 8237        } else {
 8238            self.style.as_ref().unwrap().local_player
 8239        }
 8240    }
 8241
 8242    fn render_edit_prediction_accept_keybind(
 8243        &self,
 8244        window: &mut Window,
 8245        cx: &App,
 8246    ) -> Option<AnyElement> {
 8247        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8248        let accept_keystroke = accept_binding.keystroke()?;
 8249
 8250        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8251
 8252        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8253            Color::Accent
 8254        } else {
 8255            Color::Muted
 8256        };
 8257
 8258        h_flex()
 8259            .px_0p5()
 8260            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8261            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8262            .text_size(TextSize::XSmall.rems(cx))
 8263            .child(h_flex().children(ui::render_modifiers(
 8264                &accept_keystroke.modifiers,
 8265                PlatformStyle::platform(),
 8266                Some(modifiers_color),
 8267                Some(IconSize::XSmall.rems().into()),
 8268                true,
 8269            )))
 8270            .when(is_platform_style_mac, |parent| {
 8271                parent.child(accept_keystroke.key.clone())
 8272            })
 8273            .when(!is_platform_style_mac, |parent| {
 8274                parent.child(
 8275                    Key::new(
 8276                        util::capitalize(&accept_keystroke.key),
 8277                        Some(Color::Default),
 8278                    )
 8279                    .size(Some(IconSize::XSmall.rems().into())),
 8280                )
 8281            })
 8282            .into_any()
 8283            .into()
 8284    }
 8285
 8286    fn render_edit_prediction_line_popover(
 8287        &self,
 8288        label: impl Into<SharedString>,
 8289        icon: Option<IconName>,
 8290        window: &mut Window,
 8291        cx: &App,
 8292    ) -> Option<Stateful<Div>> {
 8293        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8294
 8295        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8296        let has_keybind = keybind.is_some();
 8297
 8298        let result = h_flex()
 8299            .id("ep-line-popover")
 8300            .py_0p5()
 8301            .pl_1()
 8302            .pr(padding_right)
 8303            .gap_1()
 8304            .rounded_md()
 8305            .border_1()
 8306            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8307            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8308            .shadow_sm()
 8309            .when(!has_keybind, |el| {
 8310                let status_colors = cx.theme().status();
 8311
 8312                el.bg(status_colors.error_background)
 8313                    .border_color(status_colors.error.opacity(0.6))
 8314                    .pl_2()
 8315                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8316                    .cursor_default()
 8317                    .hoverable_tooltip(move |_window, cx| {
 8318                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8319                    })
 8320            })
 8321            .children(keybind)
 8322            .child(
 8323                Label::new(label)
 8324                    .size(LabelSize::Small)
 8325                    .when(!has_keybind, |el| {
 8326                        el.color(cx.theme().status().error.into()).strikethrough()
 8327                    }),
 8328            )
 8329            .when(!has_keybind, |el| {
 8330                el.child(
 8331                    h_flex().ml_1().child(
 8332                        Icon::new(IconName::Info)
 8333                            .size(IconSize::Small)
 8334                            .color(cx.theme().status().error.into()),
 8335                    ),
 8336                )
 8337            })
 8338            .when_some(icon, |element, icon| {
 8339                element.child(
 8340                    div()
 8341                        .mt(px(1.5))
 8342                        .child(Icon::new(icon).size(IconSize::Small)),
 8343                )
 8344            });
 8345
 8346        Some(result)
 8347    }
 8348
 8349    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8350        let accent_color = cx.theme().colors().text_accent;
 8351        let editor_bg_color = cx.theme().colors().editor_background;
 8352        editor_bg_color.blend(accent_color.opacity(0.1))
 8353    }
 8354
 8355    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8356        let accent_color = cx.theme().colors().text_accent;
 8357        let editor_bg_color = cx.theme().colors().editor_background;
 8358        editor_bg_color.blend(accent_color.opacity(0.6))
 8359    }
 8360
 8361    fn render_edit_prediction_cursor_popover(
 8362        &self,
 8363        min_width: Pixels,
 8364        max_width: Pixels,
 8365        cursor_point: Point,
 8366        style: &EditorStyle,
 8367        accept_keystroke: Option<&gpui::Keystroke>,
 8368        _window: &Window,
 8369        cx: &mut Context<Editor>,
 8370    ) -> Option<AnyElement> {
 8371        let provider = self.edit_prediction_provider.as_ref()?;
 8372
 8373        if provider.provider.needs_terms_acceptance(cx) {
 8374            return Some(
 8375                h_flex()
 8376                    .min_w(min_width)
 8377                    .flex_1()
 8378                    .px_2()
 8379                    .py_1()
 8380                    .gap_3()
 8381                    .elevation_2(cx)
 8382                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8383                    .id("accept-terms")
 8384                    .cursor_pointer()
 8385                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8386                    .on_click(cx.listener(|this, _event, window, cx| {
 8387                        cx.stop_propagation();
 8388                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8389                        window.dispatch_action(
 8390                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8391                            cx,
 8392                        );
 8393                    }))
 8394                    .child(
 8395                        h_flex()
 8396                            .flex_1()
 8397                            .gap_2()
 8398                            .child(Icon::new(IconName::ZedPredict))
 8399                            .child(Label::new("Accept Terms of Service"))
 8400                            .child(div().w_full())
 8401                            .child(
 8402                                Icon::new(IconName::ArrowUpRight)
 8403                                    .color(Color::Muted)
 8404                                    .size(IconSize::Small),
 8405                            )
 8406                            .into_any_element(),
 8407                    )
 8408                    .into_any(),
 8409            );
 8410        }
 8411
 8412        let is_refreshing = provider.provider.is_refreshing(cx);
 8413
 8414        fn pending_completion_container() -> Div {
 8415            h_flex()
 8416                .h_full()
 8417                .flex_1()
 8418                .gap_2()
 8419                .child(Icon::new(IconName::ZedPredict))
 8420        }
 8421
 8422        let completion = match &self.active_inline_completion {
 8423            Some(prediction) => {
 8424                if !self.has_visible_completions_menu() {
 8425                    const RADIUS: Pixels = px(6.);
 8426                    const BORDER_WIDTH: Pixels = px(1.);
 8427
 8428                    return Some(
 8429                        h_flex()
 8430                            .elevation_2(cx)
 8431                            .border(BORDER_WIDTH)
 8432                            .border_color(cx.theme().colors().border)
 8433                            .when(accept_keystroke.is_none(), |el| {
 8434                                el.border_color(cx.theme().status().error)
 8435                            })
 8436                            .rounded(RADIUS)
 8437                            .rounded_tl(px(0.))
 8438                            .overflow_hidden()
 8439                            .child(div().px_1p5().child(match &prediction.completion {
 8440                                InlineCompletion::Move { target, snapshot } => {
 8441                                    use text::ToPoint as _;
 8442                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8443                                    {
 8444                                        Icon::new(IconName::ZedPredictDown)
 8445                                    } else {
 8446                                        Icon::new(IconName::ZedPredictUp)
 8447                                    }
 8448                                }
 8449                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8450                            }))
 8451                            .child(
 8452                                h_flex()
 8453                                    .gap_1()
 8454                                    .py_1()
 8455                                    .px_2()
 8456                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8457                                    .border_l_1()
 8458                                    .border_color(cx.theme().colors().border)
 8459                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8460                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8461                                        el.child(
 8462                                            Label::new("Hold")
 8463                                                .size(LabelSize::Small)
 8464                                                .when(accept_keystroke.is_none(), |el| {
 8465                                                    el.strikethrough()
 8466                                                })
 8467                                                .line_height_style(LineHeightStyle::UiLabel),
 8468                                        )
 8469                                    })
 8470                                    .id("edit_prediction_cursor_popover_keybind")
 8471                                    .when(accept_keystroke.is_none(), |el| {
 8472                                        let status_colors = cx.theme().status();
 8473
 8474                                        el.bg(status_colors.error_background)
 8475                                            .border_color(status_colors.error.opacity(0.6))
 8476                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8477                                            .cursor_default()
 8478                                            .hoverable_tooltip(move |_window, cx| {
 8479                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8480                                                    .into()
 8481                                            })
 8482                                    })
 8483                                    .when_some(
 8484                                        accept_keystroke.as_ref(),
 8485                                        |el, accept_keystroke| {
 8486                                            el.child(h_flex().children(ui::render_modifiers(
 8487                                                &accept_keystroke.modifiers,
 8488                                                PlatformStyle::platform(),
 8489                                                Some(Color::Default),
 8490                                                Some(IconSize::XSmall.rems().into()),
 8491                                                false,
 8492                                            )))
 8493                                        },
 8494                                    ),
 8495                            )
 8496                            .into_any(),
 8497                    );
 8498                }
 8499
 8500                self.render_edit_prediction_cursor_popover_preview(
 8501                    prediction,
 8502                    cursor_point,
 8503                    style,
 8504                    cx,
 8505                )?
 8506            }
 8507
 8508            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8509                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8510                    stale_completion,
 8511                    cursor_point,
 8512                    style,
 8513                    cx,
 8514                )?,
 8515
 8516                None => {
 8517                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8518                }
 8519            },
 8520
 8521            None => pending_completion_container().child(Label::new("No Prediction")),
 8522        };
 8523
 8524        let completion = if is_refreshing {
 8525            completion
 8526                .with_animation(
 8527                    "loading-completion",
 8528                    Animation::new(Duration::from_secs(2))
 8529                        .repeat()
 8530                        .with_easing(pulsating_between(0.4, 0.8)),
 8531                    |label, delta| label.opacity(delta),
 8532                )
 8533                .into_any_element()
 8534        } else {
 8535            completion.into_any_element()
 8536        };
 8537
 8538        let has_completion = self.active_inline_completion.is_some();
 8539
 8540        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8541        Some(
 8542            h_flex()
 8543                .min_w(min_width)
 8544                .max_w(max_width)
 8545                .flex_1()
 8546                .elevation_2(cx)
 8547                .border_color(cx.theme().colors().border)
 8548                .child(
 8549                    div()
 8550                        .flex_1()
 8551                        .py_1()
 8552                        .px_2()
 8553                        .overflow_hidden()
 8554                        .child(completion),
 8555                )
 8556                .when_some(accept_keystroke, |el, accept_keystroke| {
 8557                    if !accept_keystroke.modifiers.modified() {
 8558                        return el;
 8559                    }
 8560
 8561                    el.child(
 8562                        h_flex()
 8563                            .h_full()
 8564                            .border_l_1()
 8565                            .rounded_r_lg()
 8566                            .border_color(cx.theme().colors().border)
 8567                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8568                            .gap_1()
 8569                            .py_1()
 8570                            .px_2()
 8571                            .child(
 8572                                h_flex()
 8573                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8574                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8575                                    .child(h_flex().children(ui::render_modifiers(
 8576                                        &accept_keystroke.modifiers,
 8577                                        PlatformStyle::platform(),
 8578                                        Some(if !has_completion {
 8579                                            Color::Muted
 8580                                        } else {
 8581                                            Color::Default
 8582                                        }),
 8583                                        None,
 8584                                        false,
 8585                                    ))),
 8586                            )
 8587                            .child(Label::new("Preview").into_any_element())
 8588                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8589                    )
 8590                })
 8591                .into_any(),
 8592        )
 8593    }
 8594
 8595    fn render_edit_prediction_cursor_popover_preview(
 8596        &self,
 8597        completion: &InlineCompletionState,
 8598        cursor_point: Point,
 8599        style: &EditorStyle,
 8600        cx: &mut Context<Editor>,
 8601    ) -> Option<Div> {
 8602        use text::ToPoint as _;
 8603
 8604        fn render_relative_row_jump(
 8605            prefix: impl Into<String>,
 8606            current_row: u32,
 8607            target_row: u32,
 8608        ) -> Div {
 8609            let (row_diff, arrow) = if target_row < current_row {
 8610                (current_row - target_row, IconName::ArrowUp)
 8611            } else {
 8612                (target_row - current_row, IconName::ArrowDown)
 8613            };
 8614
 8615            h_flex()
 8616                .child(
 8617                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8618                        .color(Color::Muted)
 8619                        .size(LabelSize::Small),
 8620                )
 8621                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8622        }
 8623
 8624        match &completion.completion {
 8625            InlineCompletion::Move {
 8626                target, snapshot, ..
 8627            } => Some(
 8628                h_flex()
 8629                    .px_2()
 8630                    .gap_2()
 8631                    .flex_1()
 8632                    .child(
 8633                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8634                            Icon::new(IconName::ZedPredictDown)
 8635                        } else {
 8636                            Icon::new(IconName::ZedPredictUp)
 8637                        },
 8638                    )
 8639                    .child(Label::new("Jump to Edit")),
 8640            ),
 8641
 8642            InlineCompletion::Edit {
 8643                edits,
 8644                edit_preview,
 8645                snapshot,
 8646                display_mode: _,
 8647            } => {
 8648                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8649
 8650                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8651                    &snapshot,
 8652                    &edits,
 8653                    edit_preview.as_ref()?,
 8654                    true,
 8655                    cx,
 8656                )
 8657                .first_line_preview();
 8658
 8659                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8660                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8661
 8662                let preview = h_flex()
 8663                    .gap_1()
 8664                    .min_w_16()
 8665                    .child(styled_text)
 8666                    .when(has_more_lines, |parent| parent.child(""));
 8667
 8668                let left = if first_edit_row != cursor_point.row {
 8669                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8670                        .into_any_element()
 8671                } else {
 8672                    Icon::new(IconName::ZedPredict).into_any_element()
 8673                };
 8674
 8675                Some(
 8676                    h_flex()
 8677                        .h_full()
 8678                        .flex_1()
 8679                        .gap_2()
 8680                        .pr_1()
 8681                        .overflow_x_hidden()
 8682                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8683                        .child(left)
 8684                        .child(preview),
 8685                )
 8686            }
 8687        }
 8688    }
 8689
 8690    pub fn render_context_menu(
 8691        &self,
 8692        style: &EditorStyle,
 8693        max_height_in_lines: u32,
 8694        window: &mut Window,
 8695        cx: &mut Context<Editor>,
 8696    ) -> Option<AnyElement> {
 8697        let menu = self.context_menu.borrow();
 8698        let menu = menu.as_ref()?;
 8699        if !menu.visible() {
 8700            return None;
 8701        };
 8702        Some(menu.render(style, max_height_in_lines, window, cx))
 8703    }
 8704
 8705    fn render_context_menu_aside(
 8706        &mut self,
 8707        max_size: Size<Pixels>,
 8708        window: &mut Window,
 8709        cx: &mut Context<Editor>,
 8710    ) -> Option<AnyElement> {
 8711        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8712            if menu.visible() {
 8713                menu.render_aside(max_size, window, cx)
 8714            } else {
 8715                None
 8716            }
 8717        })
 8718    }
 8719
 8720    fn hide_context_menu(
 8721        &mut self,
 8722        window: &mut Window,
 8723        cx: &mut Context<Self>,
 8724    ) -> Option<CodeContextMenu> {
 8725        cx.notify();
 8726        self.completion_tasks.clear();
 8727        let context_menu = self.context_menu.borrow_mut().take();
 8728        self.stale_inline_completion_in_menu.take();
 8729        self.update_visible_inline_completion(window, cx);
 8730        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8731            if let Some(completion_provider) = &self.completion_provider {
 8732                completion_provider.selection_changed(None, window, cx);
 8733            }
 8734        }
 8735        context_menu
 8736    }
 8737
 8738    fn show_snippet_choices(
 8739        &mut self,
 8740        choices: &Vec<String>,
 8741        selection: Range<Anchor>,
 8742        cx: &mut Context<Self>,
 8743    ) {
 8744        if selection.start.buffer_id.is_none() {
 8745            return;
 8746        }
 8747        let buffer_id = selection.start.buffer_id.unwrap();
 8748        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8749        let id = post_inc(&mut self.next_completion_id);
 8750        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8751
 8752        if let Some(buffer) = buffer {
 8753            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8754                CompletionsMenu::new_snippet_choices(
 8755                    id,
 8756                    true,
 8757                    choices,
 8758                    selection,
 8759                    buffer,
 8760                    snippet_sort_order,
 8761                ),
 8762            ));
 8763        }
 8764    }
 8765
 8766    pub fn insert_snippet(
 8767        &mut self,
 8768        insertion_ranges: &[Range<usize>],
 8769        snippet: Snippet,
 8770        window: &mut Window,
 8771        cx: &mut Context<Self>,
 8772    ) -> Result<()> {
 8773        struct Tabstop<T> {
 8774            is_end_tabstop: bool,
 8775            ranges: Vec<Range<T>>,
 8776            choices: Option<Vec<String>>,
 8777        }
 8778
 8779        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8780            let snippet_text: Arc<str> = snippet.text.clone().into();
 8781            let edits = insertion_ranges
 8782                .iter()
 8783                .cloned()
 8784                .map(|range| (range, snippet_text.clone()));
 8785            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8786
 8787            let snapshot = &*buffer.read(cx);
 8788            let snippet = &snippet;
 8789            snippet
 8790                .tabstops
 8791                .iter()
 8792                .map(|tabstop| {
 8793                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8794                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8795                    });
 8796                    let mut tabstop_ranges = tabstop
 8797                        .ranges
 8798                        .iter()
 8799                        .flat_map(|tabstop_range| {
 8800                            let mut delta = 0_isize;
 8801                            insertion_ranges.iter().map(move |insertion_range| {
 8802                                let insertion_start = insertion_range.start as isize + delta;
 8803                                delta +=
 8804                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8805
 8806                                let start = ((insertion_start + tabstop_range.start) as usize)
 8807                                    .min(snapshot.len());
 8808                                let end = ((insertion_start + tabstop_range.end) as usize)
 8809                                    .min(snapshot.len());
 8810                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8811                            })
 8812                        })
 8813                        .collect::<Vec<_>>();
 8814                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8815
 8816                    Tabstop {
 8817                        is_end_tabstop,
 8818                        ranges: tabstop_ranges,
 8819                        choices: tabstop.choices.clone(),
 8820                    }
 8821                })
 8822                .collect::<Vec<_>>()
 8823        });
 8824        if let Some(tabstop) = tabstops.first() {
 8825            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8826                s.select_ranges(tabstop.ranges.iter().cloned());
 8827            });
 8828
 8829            if let Some(choices) = &tabstop.choices {
 8830                if let Some(selection) = tabstop.ranges.first() {
 8831                    self.show_snippet_choices(choices, selection.clone(), cx)
 8832                }
 8833            }
 8834
 8835            // If we're already at the last tabstop and it's at the end of the snippet,
 8836            // we're done, we don't need to keep the state around.
 8837            if !tabstop.is_end_tabstop {
 8838                let choices = tabstops
 8839                    .iter()
 8840                    .map(|tabstop| tabstop.choices.clone())
 8841                    .collect();
 8842
 8843                let ranges = tabstops
 8844                    .into_iter()
 8845                    .map(|tabstop| tabstop.ranges)
 8846                    .collect::<Vec<_>>();
 8847
 8848                self.snippet_stack.push(SnippetState {
 8849                    active_index: 0,
 8850                    ranges,
 8851                    choices,
 8852                });
 8853            }
 8854
 8855            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8856            if self.autoclose_regions.is_empty() {
 8857                let snapshot = self.buffer.read(cx).snapshot(cx);
 8858                for selection in &mut self.selections.all::<Point>(cx) {
 8859                    let selection_head = selection.head();
 8860                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8861                        continue;
 8862                    };
 8863
 8864                    let mut bracket_pair = None;
 8865                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8866                    let prev_chars = snapshot
 8867                        .reversed_chars_at(selection_head)
 8868                        .collect::<String>();
 8869                    for (pair, enabled) in scope.brackets() {
 8870                        if enabled
 8871                            && pair.close
 8872                            && prev_chars.starts_with(pair.start.as_str())
 8873                            && next_chars.starts_with(pair.end.as_str())
 8874                        {
 8875                            bracket_pair = Some(pair.clone());
 8876                            break;
 8877                        }
 8878                    }
 8879                    if let Some(pair) = bracket_pair {
 8880                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8881                        let autoclose_enabled =
 8882                            self.use_autoclose && snapshot_settings.use_autoclose;
 8883                        if autoclose_enabled {
 8884                            let start = snapshot.anchor_after(selection_head);
 8885                            let end = snapshot.anchor_after(selection_head);
 8886                            self.autoclose_regions.push(AutocloseRegion {
 8887                                selection_id: selection.id,
 8888                                range: start..end,
 8889                                pair,
 8890                            });
 8891                        }
 8892                    }
 8893                }
 8894            }
 8895        }
 8896        Ok(())
 8897    }
 8898
 8899    pub fn move_to_next_snippet_tabstop(
 8900        &mut self,
 8901        window: &mut Window,
 8902        cx: &mut Context<Self>,
 8903    ) -> bool {
 8904        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8905    }
 8906
 8907    pub fn move_to_prev_snippet_tabstop(
 8908        &mut self,
 8909        window: &mut Window,
 8910        cx: &mut Context<Self>,
 8911    ) -> bool {
 8912        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8913    }
 8914
 8915    pub fn move_to_snippet_tabstop(
 8916        &mut self,
 8917        bias: Bias,
 8918        window: &mut Window,
 8919        cx: &mut Context<Self>,
 8920    ) -> bool {
 8921        if let Some(mut snippet) = self.snippet_stack.pop() {
 8922            match bias {
 8923                Bias::Left => {
 8924                    if snippet.active_index > 0 {
 8925                        snippet.active_index -= 1;
 8926                    } else {
 8927                        self.snippet_stack.push(snippet);
 8928                        return false;
 8929                    }
 8930                }
 8931                Bias::Right => {
 8932                    if snippet.active_index + 1 < snippet.ranges.len() {
 8933                        snippet.active_index += 1;
 8934                    } else {
 8935                        self.snippet_stack.push(snippet);
 8936                        return false;
 8937                    }
 8938                }
 8939            }
 8940            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8941                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8942                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8943                });
 8944
 8945                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8946                    if let Some(selection) = current_ranges.first() {
 8947                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8948                    }
 8949                }
 8950
 8951                // If snippet state is not at the last tabstop, push it back on the stack
 8952                if snippet.active_index + 1 < snippet.ranges.len() {
 8953                    self.snippet_stack.push(snippet);
 8954                }
 8955                return true;
 8956            }
 8957        }
 8958
 8959        false
 8960    }
 8961
 8962    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8963        self.transact(window, cx, |this, window, cx| {
 8964            this.select_all(&SelectAll, window, cx);
 8965            this.insert("", window, cx);
 8966        });
 8967    }
 8968
 8969    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8970        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8971        self.transact(window, cx, |this, window, cx| {
 8972            this.select_autoclose_pair(window, cx);
 8973            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8974            if !this.linked_edit_ranges.is_empty() {
 8975                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8976                let snapshot = this.buffer.read(cx).snapshot(cx);
 8977
 8978                for selection in selections.iter() {
 8979                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8980                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8981                    if selection_start.buffer_id != selection_end.buffer_id {
 8982                        continue;
 8983                    }
 8984                    if let Some(ranges) =
 8985                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8986                    {
 8987                        for (buffer, entries) in ranges {
 8988                            linked_ranges.entry(buffer).or_default().extend(entries);
 8989                        }
 8990                    }
 8991                }
 8992            }
 8993
 8994            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8995            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8996            for selection in &mut selections {
 8997                if selection.is_empty() {
 8998                    let old_head = selection.head();
 8999                    let mut new_head =
 9000                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9001                            .to_point(&display_map);
 9002                    if let Some((buffer, line_buffer_range)) = display_map
 9003                        .buffer_snapshot
 9004                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9005                    {
 9006                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9007                        let indent_len = match indent_size.kind {
 9008                            IndentKind::Space => {
 9009                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9010                            }
 9011                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9012                        };
 9013                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9014                            let indent_len = indent_len.get();
 9015                            new_head = cmp::min(
 9016                                new_head,
 9017                                MultiBufferPoint::new(
 9018                                    old_head.row,
 9019                                    ((old_head.column - 1) / indent_len) * indent_len,
 9020                                ),
 9021                            );
 9022                        }
 9023                    }
 9024
 9025                    selection.set_head(new_head, SelectionGoal::None);
 9026                }
 9027            }
 9028
 9029            this.signature_help_state.set_backspace_pressed(true);
 9030            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9031                s.select(selections)
 9032            });
 9033            this.insert("", window, cx);
 9034            let empty_str: Arc<str> = Arc::from("");
 9035            for (buffer, edits) in linked_ranges {
 9036                let snapshot = buffer.read(cx).snapshot();
 9037                use text::ToPoint as TP;
 9038
 9039                let edits = edits
 9040                    .into_iter()
 9041                    .map(|range| {
 9042                        let end_point = TP::to_point(&range.end, &snapshot);
 9043                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9044
 9045                        if end_point == start_point {
 9046                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9047                                .saturating_sub(1);
 9048                            start_point =
 9049                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9050                        };
 9051
 9052                        (start_point..end_point, empty_str.clone())
 9053                    })
 9054                    .sorted_by_key(|(range, _)| range.start)
 9055                    .collect::<Vec<_>>();
 9056                buffer.update(cx, |this, cx| {
 9057                    this.edit(edits, None, cx);
 9058                })
 9059            }
 9060            this.refresh_inline_completion(true, false, window, cx);
 9061            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9062        });
 9063    }
 9064
 9065    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9066        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9067        self.transact(window, cx, |this, window, cx| {
 9068            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9069                s.move_with(|map, selection| {
 9070                    if selection.is_empty() {
 9071                        let cursor = movement::right(map, selection.head());
 9072                        selection.end = cursor;
 9073                        selection.reversed = true;
 9074                        selection.goal = SelectionGoal::None;
 9075                    }
 9076                })
 9077            });
 9078            this.insert("", window, cx);
 9079            this.refresh_inline_completion(true, false, window, cx);
 9080        });
 9081    }
 9082
 9083    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9084        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9085        if self.move_to_prev_snippet_tabstop(window, cx) {
 9086            return;
 9087        }
 9088        self.outdent(&Outdent, window, cx);
 9089    }
 9090
 9091    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9092        if self.move_to_next_snippet_tabstop(window, cx) {
 9093            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9094            return;
 9095        }
 9096        if self.read_only(cx) {
 9097            return;
 9098        }
 9099        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9100        let mut selections = self.selections.all_adjusted(cx);
 9101        let buffer = self.buffer.read(cx);
 9102        let snapshot = buffer.snapshot(cx);
 9103        let rows_iter = selections.iter().map(|s| s.head().row);
 9104        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9105
 9106        let has_some_cursor_in_whitespace = selections
 9107            .iter()
 9108            .filter(|selection| selection.is_empty())
 9109            .any(|selection| {
 9110                let cursor = selection.head();
 9111                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9112                cursor.column < current_indent.len
 9113            });
 9114
 9115        let mut edits = Vec::new();
 9116        let mut prev_edited_row = 0;
 9117        let mut row_delta = 0;
 9118        for selection in &mut selections {
 9119            if selection.start.row != prev_edited_row {
 9120                row_delta = 0;
 9121            }
 9122            prev_edited_row = selection.end.row;
 9123
 9124            // If the selection is non-empty, then increase the indentation of the selected lines.
 9125            if !selection.is_empty() {
 9126                row_delta =
 9127                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9128                continue;
 9129            }
 9130
 9131            let cursor = selection.head();
 9132            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9133            if let Some(suggested_indent) =
 9134                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9135            {
 9136                // Don't do anything if already at suggested indent
 9137                // and there is any other cursor which is not
 9138                if has_some_cursor_in_whitespace
 9139                    && cursor.column == current_indent.len
 9140                    && current_indent.len == suggested_indent.len
 9141                {
 9142                    continue;
 9143                }
 9144
 9145                // Adjust line and move cursor to suggested indent
 9146                // if cursor is not at suggested indent
 9147                if cursor.column < suggested_indent.len
 9148                    && cursor.column <= current_indent.len
 9149                    && current_indent.len <= suggested_indent.len
 9150                {
 9151                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9152                    selection.end = selection.start;
 9153                    if row_delta == 0 {
 9154                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9155                            cursor.row,
 9156                            current_indent,
 9157                            suggested_indent,
 9158                        ));
 9159                        row_delta = suggested_indent.len - current_indent.len;
 9160                    }
 9161                    continue;
 9162                }
 9163
 9164                // If current indent is more than suggested indent
 9165                // only move cursor to current indent and skip indent
 9166                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9167                    selection.start = Point::new(cursor.row, current_indent.len);
 9168                    selection.end = selection.start;
 9169                    continue;
 9170                }
 9171            }
 9172
 9173            // Otherwise, insert a hard or soft tab.
 9174            let settings = buffer.language_settings_at(cursor, cx);
 9175            let tab_size = if settings.hard_tabs {
 9176                IndentSize::tab()
 9177            } else {
 9178                let tab_size = settings.tab_size.get();
 9179                let indent_remainder = snapshot
 9180                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9181                    .flat_map(str::chars)
 9182                    .fold(row_delta % tab_size, |counter: u32, c| {
 9183                        if c == '\t' {
 9184                            0
 9185                        } else {
 9186                            (counter + 1) % tab_size
 9187                        }
 9188                    });
 9189
 9190                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9191                IndentSize::spaces(chars_to_next_tab_stop)
 9192            };
 9193            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9194            selection.end = selection.start;
 9195            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9196            row_delta += tab_size.len;
 9197        }
 9198
 9199        self.transact(window, cx, |this, window, cx| {
 9200            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9201            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9202                s.select(selections)
 9203            });
 9204            this.refresh_inline_completion(true, false, window, cx);
 9205        });
 9206    }
 9207
 9208    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9209        if self.read_only(cx) {
 9210            return;
 9211        }
 9212        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9213        let mut selections = self.selections.all::<Point>(cx);
 9214        let mut prev_edited_row = 0;
 9215        let mut row_delta = 0;
 9216        let mut edits = Vec::new();
 9217        let buffer = self.buffer.read(cx);
 9218        let snapshot = buffer.snapshot(cx);
 9219        for selection in &mut selections {
 9220            if selection.start.row != prev_edited_row {
 9221                row_delta = 0;
 9222            }
 9223            prev_edited_row = selection.end.row;
 9224
 9225            row_delta =
 9226                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9227        }
 9228
 9229        self.transact(window, cx, |this, window, cx| {
 9230            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9231            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9232                s.select(selections)
 9233            });
 9234        });
 9235    }
 9236
 9237    fn indent_selection(
 9238        buffer: &MultiBuffer,
 9239        snapshot: &MultiBufferSnapshot,
 9240        selection: &mut Selection<Point>,
 9241        edits: &mut Vec<(Range<Point>, String)>,
 9242        delta_for_start_row: u32,
 9243        cx: &App,
 9244    ) -> u32 {
 9245        let settings = buffer.language_settings_at(selection.start, cx);
 9246        let tab_size = settings.tab_size.get();
 9247        let indent_kind = if settings.hard_tabs {
 9248            IndentKind::Tab
 9249        } else {
 9250            IndentKind::Space
 9251        };
 9252        let mut start_row = selection.start.row;
 9253        let mut end_row = selection.end.row + 1;
 9254
 9255        // If a selection ends at the beginning of a line, don't indent
 9256        // that last line.
 9257        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9258            end_row -= 1;
 9259        }
 9260
 9261        // Avoid re-indenting a row that has already been indented by a
 9262        // previous selection, but still update this selection's column
 9263        // to reflect that indentation.
 9264        if delta_for_start_row > 0 {
 9265            start_row += 1;
 9266            selection.start.column += delta_for_start_row;
 9267            if selection.end.row == selection.start.row {
 9268                selection.end.column += delta_for_start_row;
 9269            }
 9270        }
 9271
 9272        let mut delta_for_end_row = 0;
 9273        let has_multiple_rows = start_row + 1 != end_row;
 9274        for row in start_row..end_row {
 9275            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9276            let indent_delta = match (current_indent.kind, indent_kind) {
 9277                (IndentKind::Space, IndentKind::Space) => {
 9278                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9279                    IndentSize::spaces(columns_to_next_tab_stop)
 9280                }
 9281                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9282                (_, IndentKind::Tab) => IndentSize::tab(),
 9283            };
 9284
 9285            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9286                0
 9287            } else {
 9288                selection.start.column
 9289            };
 9290            let row_start = Point::new(row, start);
 9291            edits.push((
 9292                row_start..row_start,
 9293                indent_delta.chars().collect::<String>(),
 9294            ));
 9295
 9296            // Update this selection's endpoints to reflect the indentation.
 9297            if row == selection.start.row {
 9298                selection.start.column += indent_delta.len;
 9299            }
 9300            if row == selection.end.row {
 9301                selection.end.column += indent_delta.len;
 9302                delta_for_end_row = indent_delta.len;
 9303            }
 9304        }
 9305
 9306        if selection.start.row == selection.end.row {
 9307            delta_for_start_row + delta_for_end_row
 9308        } else {
 9309            delta_for_end_row
 9310        }
 9311    }
 9312
 9313    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9314        if self.read_only(cx) {
 9315            return;
 9316        }
 9317        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9318        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9319        let selections = self.selections.all::<Point>(cx);
 9320        let mut deletion_ranges = Vec::new();
 9321        let mut last_outdent = None;
 9322        {
 9323            let buffer = self.buffer.read(cx);
 9324            let snapshot = buffer.snapshot(cx);
 9325            for selection in &selections {
 9326                let settings = buffer.language_settings_at(selection.start, cx);
 9327                let tab_size = settings.tab_size.get();
 9328                let mut rows = selection.spanned_rows(false, &display_map);
 9329
 9330                // Avoid re-outdenting a row that has already been outdented by a
 9331                // previous selection.
 9332                if let Some(last_row) = last_outdent {
 9333                    if last_row == rows.start {
 9334                        rows.start = rows.start.next_row();
 9335                    }
 9336                }
 9337                let has_multiple_rows = rows.len() > 1;
 9338                for row in rows.iter_rows() {
 9339                    let indent_size = snapshot.indent_size_for_line(row);
 9340                    if indent_size.len > 0 {
 9341                        let deletion_len = match indent_size.kind {
 9342                            IndentKind::Space => {
 9343                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9344                                if columns_to_prev_tab_stop == 0 {
 9345                                    tab_size
 9346                                } else {
 9347                                    columns_to_prev_tab_stop
 9348                                }
 9349                            }
 9350                            IndentKind::Tab => 1,
 9351                        };
 9352                        let start = if has_multiple_rows
 9353                            || deletion_len > selection.start.column
 9354                            || indent_size.len < selection.start.column
 9355                        {
 9356                            0
 9357                        } else {
 9358                            selection.start.column - deletion_len
 9359                        };
 9360                        deletion_ranges.push(
 9361                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9362                        );
 9363                        last_outdent = Some(row);
 9364                    }
 9365                }
 9366            }
 9367        }
 9368
 9369        self.transact(window, cx, |this, window, cx| {
 9370            this.buffer.update(cx, |buffer, cx| {
 9371                let empty_str: Arc<str> = Arc::default();
 9372                buffer.edit(
 9373                    deletion_ranges
 9374                        .into_iter()
 9375                        .map(|range| (range, empty_str.clone())),
 9376                    None,
 9377                    cx,
 9378                );
 9379            });
 9380            let selections = this.selections.all::<usize>(cx);
 9381            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9382                s.select(selections)
 9383            });
 9384        });
 9385    }
 9386
 9387    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9388        if self.read_only(cx) {
 9389            return;
 9390        }
 9391        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9392        let selections = self
 9393            .selections
 9394            .all::<usize>(cx)
 9395            .into_iter()
 9396            .map(|s| s.range());
 9397
 9398        self.transact(window, cx, |this, window, cx| {
 9399            this.buffer.update(cx, |buffer, cx| {
 9400                buffer.autoindent_ranges(selections, cx);
 9401            });
 9402            let selections = this.selections.all::<usize>(cx);
 9403            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9404                s.select(selections)
 9405            });
 9406        });
 9407    }
 9408
 9409    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9410        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9411        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9412        let selections = self.selections.all::<Point>(cx);
 9413
 9414        let mut new_cursors = Vec::new();
 9415        let mut edit_ranges = Vec::new();
 9416        let mut selections = selections.iter().peekable();
 9417        while let Some(selection) = selections.next() {
 9418            let mut rows = selection.spanned_rows(false, &display_map);
 9419            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9420
 9421            // Accumulate contiguous regions of rows that we want to delete.
 9422            while let Some(next_selection) = selections.peek() {
 9423                let next_rows = next_selection.spanned_rows(false, &display_map);
 9424                if next_rows.start <= rows.end {
 9425                    rows.end = next_rows.end;
 9426                    selections.next().unwrap();
 9427                } else {
 9428                    break;
 9429                }
 9430            }
 9431
 9432            let buffer = &display_map.buffer_snapshot;
 9433            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9434            let edit_end;
 9435            let cursor_buffer_row;
 9436            if buffer.max_point().row >= rows.end.0 {
 9437                // If there's a line after the range, delete the \n from the end of the row range
 9438                // and position the cursor on the next line.
 9439                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9440                cursor_buffer_row = rows.end;
 9441            } else {
 9442                // If there isn't a line after the range, delete the \n from the line before the
 9443                // start of the row range and position the cursor there.
 9444                edit_start = edit_start.saturating_sub(1);
 9445                edit_end = buffer.len();
 9446                cursor_buffer_row = rows.start.previous_row();
 9447            }
 9448
 9449            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9450            *cursor.column_mut() =
 9451                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9452
 9453            new_cursors.push((
 9454                selection.id,
 9455                buffer.anchor_after(cursor.to_point(&display_map)),
 9456            ));
 9457            edit_ranges.push(edit_start..edit_end);
 9458        }
 9459
 9460        self.transact(window, cx, |this, window, cx| {
 9461            let buffer = this.buffer.update(cx, |buffer, cx| {
 9462                let empty_str: Arc<str> = Arc::default();
 9463                buffer.edit(
 9464                    edit_ranges
 9465                        .into_iter()
 9466                        .map(|range| (range, empty_str.clone())),
 9467                    None,
 9468                    cx,
 9469                );
 9470                buffer.snapshot(cx)
 9471            });
 9472            let new_selections = new_cursors
 9473                .into_iter()
 9474                .map(|(id, cursor)| {
 9475                    let cursor = cursor.to_point(&buffer);
 9476                    Selection {
 9477                        id,
 9478                        start: cursor,
 9479                        end: cursor,
 9480                        reversed: false,
 9481                        goal: SelectionGoal::None,
 9482                    }
 9483                })
 9484                .collect();
 9485
 9486            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9487                s.select(new_selections);
 9488            });
 9489        });
 9490    }
 9491
 9492    pub fn join_lines_impl(
 9493        &mut self,
 9494        insert_whitespace: bool,
 9495        window: &mut Window,
 9496        cx: &mut Context<Self>,
 9497    ) {
 9498        if self.read_only(cx) {
 9499            return;
 9500        }
 9501        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9502        for selection in self.selections.all::<Point>(cx) {
 9503            let start = MultiBufferRow(selection.start.row);
 9504            // Treat single line selections as if they include the next line. Otherwise this action
 9505            // would do nothing for single line selections individual cursors.
 9506            let end = if selection.start.row == selection.end.row {
 9507                MultiBufferRow(selection.start.row + 1)
 9508            } else {
 9509                MultiBufferRow(selection.end.row)
 9510            };
 9511
 9512            if let Some(last_row_range) = row_ranges.last_mut() {
 9513                if start <= last_row_range.end {
 9514                    last_row_range.end = end;
 9515                    continue;
 9516                }
 9517            }
 9518            row_ranges.push(start..end);
 9519        }
 9520
 9521        let snapshot = self.buffer.read(cx).snapshot(cx);
 9522        let mut cursor_positions = Vec::new();
 9523        for row_range in &row_ranges {
 9524            let anchor = snapshot.anchor_before(Point::new(
 9525                row_range.end.previous_row().0,
 9526                snapshot.line_len(row_range.end.previous_row()),
 9527            ));
 9528            cursor_positions.push(anchor..anchor);
 9529        }
 9530
 9531        self.transact(window, cx, |this, window, cx| {
 9532            for row_range in row_ranges.into_iter().rev() {
 9533                for row in row_range.iter_rows().rev() {
 9534                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9535                    let next_line_row = row.next_row();
 9536                    let indent = snapshot.indent_size_for_line(next_line_row);
 9537                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9538
 9539                    let replace =
 9540                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9541                            " "
 9542                        } else {
 9543                            ""
 9544                        };
 9545
 9546                    this.buffer.update(cx, |buffer, cx| {
 9547                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9548                    });
 9549                }
 9550            }
 9551
 9552            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9553                s.select_anchor_ranges(cursor_positions)
 9554            });
 9555        });
 9556    }
 9557
 9558    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9559        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9560        self.join_lines_impl(true, window, cx);
 9561    }
 9562
 9563    pub fn sort_lines_case_sensitive(
 9564        &mut self,
 9565        _: &SortLinesCaseSensitive,
 9566        window: &mut Window,
 9567        cx: &mut Context<Self>,
 9568    ) {
 9569        self.manipulate_lines(window, cx, |lines| lines.sort())
 9570    }
 9571
 9572    pub fn sort_lines_case_insensitive(
 9573        &mut self,
 9574        _: &SortLinesCaseInsensitive,
 9575        window: &mut Window,
 9576        cx: &mut Context<Self>,
 9577    ) {
 9578        self.manipulate_lines(window, cx, |lines| {
 9579            lines.sort_by_key(|line| line.to_lowercase())
 9580        })
 9581    }
 9582
 9583    pub fn unique_lines_case_insensitive(
 9584        &mut self,
 9585        _: &UniqueLinesCaseInsensitive,
 9586        window: &mut Window,
 9587        cx: &mut Context<Self>,
 9588    ) {
 9589        self.manipulate_lines(window, cx, |lines| {
 9590            let mut seen = HashSet::default();
 9591            lines.retain(|line| seen.insert(line.to_lowercase()));
 9592        })
 9593    }
 9594
 9595    pub fn unique_lines_case_sensitive(
 9596        &mut self,
 9597        _: &UniqueLinesCaseSensitive,
 9598        window: &mut Window,
 9599        cx: &mut Context<Self>,
 9600    ) {
 9601        self.manipulate_lines(window, cx, |lines| {
 9602            let mut seen = HashSet::default();
 9603            lines.retain(|line| seen.insert(*line));
 9604        })
 9605    }
 9606
 9607    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9608        let Some(project) = self.project.clone() else {
 9609            return;
 9610        };
 9611        self.reload(project, window, cx)
 9612            .detach_and_notify_err(window, cx);
 9613    }
 9614
 9615    pub fn restore_file(
 9616        &mut self,
 9617        _: &::git::RestoreFile,
 9618        window: &mut Window,
 9619        cx: &mut Context<Self>,
 9620    ) {
 9621        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9622        let mut buffer_ids = HashSet::default();
 9623        let snapshot = self.buffer().read(cx).snapshot(cx);
 9624        for selection in self.selections.all::<usize>(cx) {
 9625            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9626        }
 9627
 9628        let buffer = self.buffer().read(cx);
 9629        let ranges = buffer_ids
 9630            .into_iter()
 9631            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9632            .collect::<Vec<_>>();
 9633
 9634        self.restore_hunks_in_ranges(ranges, window, cx);
 9635    }
 9636
 9637    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9638        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9639        let selections = self
 9640            .selections
 9641            .all(cx)
 9642            .into_iter()
 9643            .map(|s| s.range())
 9644            .collect();
 9645        self.restore_hunks_in_ranges(selections, window, cx);
 9646    }
 9647
 9648    pub fn restore_hunks_in_ranges(
 9649        &mut self,
 9650        ranges: Vec<Range<Point>>,
 9651        window: &mut Window,
 9652        cx: &mut Context<Editor>,
 9653    ) {
 9654        let mut revert_changes = HashMap::default();
 9655        let chunk_by = self
 9656            .snapshot(window, cx)
 9657            .hunks_for_ranges(ranges)
 9658            .into_iter()
 9659            .chunk_by(|hunk| hunk.buffer_id);
 9660        for (buffer_id, hunks) in &chunk_by {
 9661            let hunks = hunks.collect::<Vec<_>>();
 9662            for hunk in &hunks {
 9663                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9664            }
 9665            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9666        }
 9667        drop(chunk_by);
 9668        if !revert_changes.is_empty() {
 9669            self.transact(window, cx, |editor, window, cx| {
 9670                editor.restore(revert_changes, window, cx);
 9671            });
 9672        }
 9673    }
 9674
 9675    pub fn open_active_item_in_terminal(
 9676        &mut self,
 9677        _: &OpenInTerminal,
 9678        window: &mut Window,
 9679        cx: &mut Context<Self>,
 9680    ) {
 9681        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9682            let project_path = buffer.read(cx).project_path(cx)?;
 9683            let project = self.project.as_ref()?.read(cx);
 9684            let entry = project.entry_for_path(&project_path, cx)?;
 9685            let parent = match &entry.canonical_path {
 9686                Some(canonical_path) => canonical_path.to_path_buf(),
 9687                None => project.absolute_path(&project_path, cx)?,
 9688            }
 9689            .parent()?
 9690            .to_path_buf();
 9691            Some(parent)
 9692        }) {
 9693            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9694        }
 9695    }
 9696
 9697    fn set_breakpoint_context_menu(
 9698        &mut self,
 9699        display_row: DisplayRow,
 9700        position: Option<Anchor>,
 9701        clicked_point: gpui::Point<Pixels>,
 9702        window: &mut Window,
 9703        cx: &mut Context<Self>,
 9704    ) {
 9705        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9706            return;
 9707        }
 9708        let source = self
 9709            .buffer
 9710            .read(cx)
 9711            .snapshot(cx)
 9712            .anchor_before(Point::new(display_row.0, 0u32));
 9713
 9714        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9715
 9716        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9717            self,
 9718            source,
 9719            clicked_point,
 9720            context_menu,
 9721            window,
 9722            cx,
 9723        );
 9724    }
 9725
 9726    fn add_edit_breakpoint_block(
 9727        &mut self,
 9728        anchor: Anchor,
 9729        breakpoint: &Breakpoint,
 9730        edit_action: BreakpointPromptEditAction,
 9731        window: &mut Window,
 9732        cx: &mut Context<Self>,
 9733    ) {
 9734        let weak_editor = cx.weak_entity();
 9735        let bp_prompt = cx.new(|cx| {
 9736            BreakpointPromptEditor::new(
 9737                weak_editor,
 9738                anchor,
 9739                breakpoint.clone(),
 9740                edit_action,
 9741                window,
 9742                cx,
 9743            )
 9744        });
 9745
 9746        let height = bp_prompt.update(cx, |this, cx| {
 9747            this.prompt
 9748                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9749        });
 9750        let cloned_prompt = bp_prompt.clone();
 9751        let blocks = vec![BlockProperties {
 9752            style: BlockStyle::Sticky,
 9753            placement: BlockPlacement::Above(anchor),
 9754            height: Some(height),
 9755            render: Arc::new(move |cx| {
 9756                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9757                cloned_prompt.clone().into_any_element()
 9758            }),
 9759            priority: 0,
 9760            render_in_minimap: true,
 9761        }];
 9762
 9763        let focus_handle = bp_prompt.focus_handle(cx);
 9764        window.focus(&focus_handle);
 9765
 9766        let block_ids = self.insert_blocks(blocks, None, cx);
 9767        bp_prompt.update(cx, |prompt, _| {
 9768            prompt.add_block_ids(block_ids);
 9769        });
 9770    }
 9771
 9772    pub(crate) fn breakpoint_at_row(
 9773        &self,
 9774        row: u32,
 9775        window: &mut Window,
 9776        cx: &mut Context<Self>,
 9777    ) -> Option<(Anchor, Breakpoint)> {
 9778        let snapshot = self.snapshot(window, cx);
 9779        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9780
 9781        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9782    }
 9783
 9784    pub(crate) fn breakpoint_at_anchor(
 9785        &self,
 9786        breakpoint_position: Anchor,
 9787        snapshot: &EditorSnapshot,
 9788        cx: &mut Context<Self>,
 9789    ) -> Option<(Anchor, Breakpoint)> {
 9790        let project = self.project.clone()?;
 9791
 9792        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9793            snapshot
 9794                .buffer_snapshot
 9795                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9796        })?;
 9797
 9798        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9799        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9800        let buffer_snapshot = buffer.read(cx).snapshot();
 9801
 9802        let row = buffer_snapshot
 9803            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9804            .row;
 9805
 9806        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9807        let anchor_end = snapshot
 9808            .buffer_snapshot
 9809            .anchor_after(Point::new(row, line_len));
 9810
 9811        let bp = self
 9812            .breakpoint_store
 9813            .as_ref()?
 9814            .read_with(cx, |breakpoint_store, cx| {
 9815                breakpoint_store
 9816                    .breakpoints(
 9817                        &buffer,
 9818                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9819                        &buffer_snapshot,
 9820                        cx,
 9821                    )
 9822                    .next()
 9823                    .and_then(|(bp, _)| {
 9824                        let breakpoint_row = buffer_snapshot
 9825                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9826                            .row;
 9827
 9828                        if breakpoint_row == row {
 9829                            snapshot
 9830                                .buffer_snapshot
 9831                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9832                                .map(|position| (position, bp.bp.clone()))
 9833                        } else {
 9834                            None
 9835                        }
 9836                    })
 9837            });
 9838        bp
 9839    }
 9840
 9841    pub fn edit_log_breakpoint(
 9842        &mut self,
 9843        _: &EditLogBreakpoint,
 9844        window: &mut Window,
 9845        cx: &mut Context<Self>,
 9846    ) {
 9847        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9848            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9849                message: None,
 9850                state: BreakpointState::Enabled,
 9851                condition: None,
 9852                hit_condition: None,
 9853            });
 9854
 9855            self.add_edit_breakpoint_block(
 9856                anchor,
 9857                &breakpoint,
 9858                BreakpointPromptEditAction::Log,
 9859                window,
 9860                cx,
 9861            );
 9862        }
 9863    }
 9864
 9865    fn breakpoints_at_cursors(
 9866        &self,
 9867        window: &mut Window,
 9868        cx: &mut Context<Self>,
 9869    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9870        let snapshot = self.snapshot(window, cx);
 9871        let cursors = self
 9872            .selections
 9873            .disjoint_anchors()
 9874            .into_iter()
 9875            .map(|selection| {
 9876                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9877
 9878                let breakpoint_position = self
 9879                    .breakpoint_at_row(cursor_position.row, window, cx)
 9880                    .map(|bp| bp.0)
 9881                    .unwrap_or_else(|| {
 9882                        snapshot
 9883                            .display_snapshot
 9884                            .buffer_snapshot
 9885                            .anchor_after(Point::new(cursor_position.row, 0))
 9886                    });
 9887
 9888                let breakpoint = self
 9889                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9890                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9891
 9892                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9893            })
 9894            // 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.
 9895            .collect::<HashMap<Anchor, _>>();
 9896
 9897        cursors.into_iter().collect()
 9898    }
 9899
 9900    pub fn enable_breakpoint(
 9901        &mut self,
 9902        _: &crate::actions::EnableBreakpoint,
 9903        window: &mut Window,
 9904        cx: &mut Context<Self>,
 9905    ) {
 9906        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9907            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9908                continue;
 9909            };
 9910            self.edit_breakpoint_at_anchor(
 9911                anchor,
 9912                breakpoint,
 9913                BreakpointEditAction::InvertState,
 9914                cx,
 9915            );
 9916        }
 9917    }
 9918
 9919    pub fn disable_breakpoint(
 9920        &mut self,
 9921        _: &crate::actions::DisableBreakpoint,
 9922        window: &mut Window,
 9923        cx: &mut Context<Self>,
 9924    ) {
 9925        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9926            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9927                continue;
 9928            };
 9929            self.edit_breakpoint_at_anchor(
 9930                anchor,
 9931                breakpoint,
 9932                BreakpointEditAction::InvertState,
 9933                cx,
 9934            );
 9935        }
 9936    }
 9937
 9938    pub fn toggle_breakpoint(
 9939        &mut self,
 9940        _: &crate::actions::ToggleBreakpoint,
 9941        window: &mut Window,
 9942        cx: &mut Context<Self>,
 9943    ) {
 9944        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9945            if let Some(breakpoint) = breakpoint {
 9946                self.edit_breakpoint_at_anchor(
 9947                    anchor,
 9948                    breakpoint,
 9949                    BreakpointEditAction::Toggle,
 9950                    cx,
 9951                );
 9952            } else {
 9953                self.edit_breakpoint_at_anchor(
 9954                    anchor,
 9955                    Breakpoint::new_standard(),
 9956                    BreakpointEditAction::Toggle,
 9957                    cx,
 9958                );
 9959            }
 9960        }
 9961    }
 9962
 9963    pub fn edit_breakpoint_at_anchor(
 9964        &mut self,
 9965        breakpoint_position: Anchor,
 9966        breakpoint: Breakpoint,
 9967        edit_action: BreakpointEditAction,
 9968        cx: &mut Context<Self>,
 9969    ) {
 9970        let Some(breakpoint_store) = &self.breakpoint_store else {
 9971            return;
 9972        };
 9973
 9974        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9975            if breakpoint_position == Anchor::min() {
 9976                self.buffer()
 9977                    .read(cx)
 9978                    .excerpt_buffer_ids()
 9979                    .into_iter()
 9980                    .next()
 9981            } else {
 9982                None
 9983            }
 9984        }) else {
 9985            return;
 9986        };
 9987
 9988        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9989            return;
 9990        };
 9991
 9992        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9993            breakpoint_store.toggle_breakpoint(
 9994                buffer,
 9995                BreakpointWithPosition {
 9996                    position: breakpoint_position.text_anchor,
 9997                    bp: breakpoint,
 9998                },
 9999                edit_action,
10000                cx,
10001            );
10002        });
10003
10004        cx.notify();
10005    }
10006
10007    #[cfg(any(test, feature = "test-support"))]
10008    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10009        self.breakpoint_store.clone()
10010    }
10011
10012    pub fn prepare_restore_change(
10013        &self,
10014        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10015        hunk: &MultiBufferDiffHunk,
10016        cx: &mut App,
10017    ) -> Option<()> {
10018        if hunk.is_created_file() {
10019            return None;
10020        }
10021        let buffer = self.buffer.read(cx);
10022        let diff = buffer.diff_for(hunk.buffer_id)?;
10023        let buffer = buffer.buffer(hunk.buffer_id)?;
10024        let buffer = buffer.read(cx);
10025        let original_text = diff
10026            .read(cx)
10027            .base_text()
10028            .as_rope()
10029            .slice(hunk.diff_base_byte_range.clone());
10030        let buffer_snapshot = buffer.snapshot();
10031        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10032        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10033            probe
10034                .0
10035                .start
10036                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10037                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10038        }) {
10039            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10040            Some(())
10041        } else {
10042            None
10043        }
10044    }
10045
10046    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10047        self.manipulate_lines(window, cx, |lines| lines.reverse())
10048    }
10049
10050    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10051        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10052    }
10053
10054    fn manipulate_lines<Fn>(
10055        &mut self,
10056        window: &mut Window,
10057        cx: &mut Context<Self>,
10058        mut callback: Fn,
10059    ) where
10060        Fn: FnMut(&mut Vec<&str>),
10061    {
10062        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10063
10064        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10065        let buffer = self.buffer.read(cx).snapshot(cx);
10066
10067        let mut edits = Vec::new();
10068
10069        let selections = self.selections.all::<Point>(cx);
10070        let mut selections = selections.iter().peekable();
10071        let mut contiguous_row_selections = Vec::new();
10072        let mut new_selections = Vec::new();
10073        let mut added_lines = 0;
10074        let mut removed_lines = 0;
10075
10076        while let Some(selection) = selections.next() {
10077            let (start_row, end_row) = consume_contiguous_rows(
10078                &mut contiguous_row_selections,
10079                selection,
10080                &display_map,
10081                &mut selections,
10082            );
10083
10084            let start_point = Point::new(start_row.0, 0);
10085            let end_point = Point::new(
10086                end_row.previous_row().0,
10087                buffer.line_len(end_row.previous_row()),
10088            );
10089            let text = buffer
10090                .text_for_range(start_point..end_point)
10091                .collect::<String>();
10092
10093            let mut lines = text.split('\n').collect_vec();
10094
10095            let lines_before = lines.len();
10096            callback(&mut lines);
10097            let lines_after = lines.len();
10098
10099            edits.push((start_point..end_point, lines.join("\n")));
10100
10101            // Selections must change based on added and removed line count
10102            let start_row =
10103                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10104            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10105            new_selections.push(Selection {
10106                id: selection.id,
10107                start: start_row,
10108                end: end_row,
10109                goal: SelectionGoal::None,
10110                reversed: selection.reversed,
10111            });
10112
10113            if lines_after > lines_before {
10114                added_lines += lines_after - lines_before;
10115            } else if lines_before > lines_after {
10116                removed_lines += lines_before - lines_after;
10117            }
10118        }
10119
10120        self.transact(window, cx, |this, window, cx| {
10121            let buffer = this.buffer.update(cx, |buffer, cx| {
10122                buffer.edit(edits, None, cx);
10123                buffer.snapshot(cx)
10124            });
10125
10126            // Recalculate offsets on newly edited buffer
10127            let new_selections = new_selections
10128                .iter()
10129                .map(|s| {
10130                    let start_point = Point::new(s.start.0, 0);
10131                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10132                    Selection {
10133                        id: s.id,
10134                        start: buffer.point_to_offset(start_point),
10135                        end: buffer.point_to_offset(end_point),
10136                        goal: s.goal,
10137                        reversed: s.reversed,
10138                    }
10139                })
10140                .collect();
10141
10142            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10143                s.select(new_selections);
10144            });
10145
10146            this.request_autoscroll(Autoscroll::fit(), cx);
10147        });
10148    }
10149
10150    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10151        self.manipulate_text(window, cx, |text| {
10152            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10153            if has_upper_case_characters {
10154                text.to_lowercase()
10155            } else {
10156                text.to_uppercase()
10157            }
10158        })
10159    }
10160
10161    pub fn convert_to_upper_case(
10162        &mut self,
10163        _: &ConvertToUpperCase,
10164        window: &mut Window,
10165        cx: &mut Context<Self>,
10166    ) {
10167        self.manipulate_text(window, cx, |text| text.to_uppercase())
10168    }
10169
10170    pub fn convert_to_lower_case(
10171        &mut self,
10172        _: &ConvertToLowerCase,
10173        window: &mut Window,
10174        cx: &mut Context<Self>,
10175    ) {
10176        self.manipulate_text(window, cx, |text| text.to_lowercase())
10177    }
10178
10179    pub fn convert_to_title_case(
10180        &mut self,
10181        _: &ConvertToTitleCase,
10182        window: &mut Window,
10183        cx: &mut Context<Self>,
10184    ) {
10185        self.manipulate_text(window, cx, |text| {
10186            text.split('\n')
10187                .map(|line| line.to_case(Case::Title))
10188                .join("\n")
10189        })
10190    }
10191
10192    pub fn convert_to_snake_case(
10193        &mut self,
10194        _: &ConvertToSnakeCase,
10195        window: &mut Window,
10196        cx: &mut Context<Self>,
10197    ) {
10198        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10199    }
10200
10201    pub fn convert_to_kebab_case(
10202        &mut self,
10203        _: &ConvertToKebabCase,
10204        window: &mut Window,
10205        cx: &mut Context<Self>,
10206    ) {
10207        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10208    }
10209
10210    pub fn convert_to_upper_camel_case(
10211        &mut self,
10212        _: &ConvertToUpperCamelCase,
10213        window: &mut Window,
10214        cx: &mut Context<Self>,
10215    ) {
10216        self.manipulate_text(window, cx, |text| {
10217            text.split('\n')
10218                .map(|line| line.to_case(Case::UpperCamel))
10219                .join("\n")
10220        })
10221    }
10222
10223    pub fn convert_to_lower_camel_case(
10224        &mut self,
10225        _: &ConvertToLowerCamelCase,
10226        window: &mut Window,
10227        cx: &mut Context<Self>,
10228    ) {
10229        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10230    }
10231
10232    pub fn convert_to_opposite_case(
10233        &mut self,
10234        _: &ConvertToOppositeCase,
10235        window: &mut Window,
10236        cx: &mut Context<Self>,
10237    ) {
10238        self.manipulate_text(window, cx, |text| {
10239            text.chars()
10240                .fold(String::with_capacity(text.len()), |mut t, c| {
10241                    if c.is_uppercase() {
10242                        t.extend(c.to_lowercase());
10243                    } else {
10244                        t.extend(c.to_uppercase());
10245                    }
10246                    t
10247                })
10248        })
10249    }
10250
10251    pub fn convert_to_rot13(
10252        &mut self,
10253        _: &ConvertToRot13,
10254        window: &mut Window,
10255        cx: &mut Context<Self>,
10256    ) {
10257        self.manipulate_text(window, cx, |text| {
10258            text.chars()
10259                .map(|c| match c {
10260                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10261                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10262                    _ => c,
10263                })
10264                .collect()
10265        })
10266    }
10267
10268    pub fn convert_to_rot47(
10269        &mut self,
10270        _: &ConvertToRot47,
10271        window: &mut Window,
10272        cx: &mut Context<Self>,
10273    ) {
10274        self.manipulate_text(window, cx, |text| {
10275            text.chars()
10276                .map(|c| {
10277                    let code_point = c as u32;
10278                    if code_point >= 33 && code_point <= 126 {
10279                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10280                    }
10281                    c
10282                })
10283                .collect()
10284        })
10285    }
10286
10287    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10288    where
10289        Fn: FnMut(&str) -> String,
10290    {
10291        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10292        let buffer = self.buffer.read(cx).snapshot(cx);
10293
10294        let mut new_selections = Vec::new();
10295        let mut edits = Vec::new();
10296        let mut selection_adjustment = 0i32;
10297
10298        for selection in self.selections.all::<usize>(cx) {
10299            let selection_is_empty = selection.is_empty();
10300
10301            let (start, end) = if selection_is_empty {
10302                let word_range = movement::surrounding_word(
10303                    &display_map,
10304                    selection.start.to_display_point(&display_map),
10305                );
10306                let start = word_range.start.to_offset(&display_map, Bias::Left);
10307                let end = word_range.end.to_offset(&display_map, Bias::Left);
10308                (start, end)
10309            } else {
10310                (selection.start, selection.end)
10311            };
10312
10313            let text = buffer.text_for_range(start..end).collect::<String>();
10314            let old_length = text.len() as i32;
10315            let text = callback(&text);
10316
10317            new_selections.push(Selection {
10318                start: (start as i32 - selection_adjustment) as usize,
10319                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10320                goal: SelectionGoal::None,
10321                ..selection
10322            });
10323
10324            selection_adjustment += old_length - text.len() as i32;
10325
10326            edits.push((start..end, text));
10327        }
10328
10329        self.transact(window, cx, |this, window, cx| {
10330            this.buffer.update(cx, |buffer, cx| {
10331                buffer.edit(edits, None, cx);
10332            });
10333
10334            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10335                s.select(new_selections);
10336            });
10337
10338            this.request_autoscroll(Autoscroll::fit(), cx);
10339        });
10340    }
10341
10342    pub fn duplicate(
10343        &mut self,
10344        upwards: bool,
10345        whole_lines: bool,
10346        window: &mut Window,
10347        cx: &mut Context<Self>,
10348    ) {
10349        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10350
10351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10352        let buffer = &display_map.buffer_snapshot;
10353        let selections = self.selections.all::<Point>(cx);
10354
10355        let mut edits = Vec::new();
10356        let mut selections_iter = selections.iter().peekable();
10357        while let Some(selection) = selections_iter.next() {
10358            let mut rows = selection.spanned_rows(false, &display_map);
10359            // duplicate line-wise
10360            if whole_lines || selection.start == selection.end {
10361                // Avoid duplicating the same lines twice.
10362                while let Some(next_selection) = selections_iter.peek() {
10363                    let next_rows = next_selection.spanned_rows(false, &display_map);
10364                    if next_rows.start < rows.end {
10365                        rows.end = next_rows.end;
10366                        selections_iter.next().unwrap();
10367                    } else {
10368                        break;
10369                    }
10370                }
10371
10372                // Copy the text from the selected row region and splice it either at the start
10373                // or end of the region.
10374                let start = Point::new(rows.start.0, 0);
10375                let end = Point::new(
10376                    rows.end.previous_row().0,
10377                    buffer.line_len(rows.end.previous_row()),
10378                );
10379                let text = buffer
10380                    .text_for_range(start..end)
10381                    .chain(Some("\n"))
10382                    .collect::<String>();
10383                let insert_location = if upwards {
10384                    Point::new(rows.end.0, 0)
10385                } else {
10386                    start
10387                };
10388                edits.push((insert_location..insert_location, text));
10389            } else {
10390                // duplicate character-wise
10391                let start = selection.start;
10392                let end = selection.end;
10393                let text = buffer.text_for_range(start..end).collect::<String>();
10394                edits.push((selection.end..selection.end, text));
10395            }
10396        }
10397
10398        self.transact(window, cx, |this, _, cx| {
10399            this.buffer.update(cx, |buffer, cx| {
10400                buffer.edit(edits, None, cx);
10401            });
10402
10403            this.request_autoscroll(Autoscroll::fit(), cx);
10404        });
10405    }
10406
10407    pub fn duplicate_line_up(
10408        &mut self,
10409        _: &DuplicateLineUp,
10410        window: &mut Window,
10411        cx: &mut Context<Self>,
10412    ) {
10413        self.duplicate(true, true, window, cx);
10414    }
10415
10416    pub fn duplicate_line_down(
10417        &mut self,
10418        _: &DuplicateLineDown,
10419        window: &mut Window,
10420        cx: &mut Context<Self>,
10421    ) {
10422        self.duplicate(false, true, window, cx);
10423    }
10424
10425    pub fn duplicate_selection(
10426        &mut self,
10427        _: &DuplicateSelection,
10428        window: &mut Window,
10429        cx: &mut Context<Self>,
10430    ) {
10431        self.duplicate(false, false, window, cx);
10432    }
10433
10434    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10435        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10436
10437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10438        let buffer = self.buffer.read(cx).snapshot(cx);
10439
10440        let mut edits = Vec::new();
10441        let mut unfold_ranges = Vec::new();
10442        let mut refold_creases = Vec::new();
10443
10444        let selections = self.selections.all::<Point>(cx);
10445        let mut selections = selections.iter().peekable();
10446        let mut contiguous_row_selections = Vec::new();
10447        let mut new_selections = Vec::new();
10448
10449        while let Some(selection) = selections.next() {
10450            // Find all the selections that span a contiguous row range
10451            let (start_row, end_row) = consume_contiguous_rows(
10452                &mut contiguous_row_selections,
10453                selection,
10454                &display_map,
10455                &mut selections,
10456            );
10457
10458            // Move the text spanned by the row range to be before the line preceding the row range
10459            if start_row.0 > 0 {
10460                let range_to_move = Point::new(
10461                    start_row.previous_row().0,
10462                    buffer.line_len(start_row.previous_row()),
10463                )
10464                    ..Point::new(
10465                        end_row.previous_row().0,
10466                        buffer.line_len(end_row.previous_row()),
10467                    );
10468                let insertion_point = display_map
10469                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10470                    .0;
10471
10472                // Don't move lines across excerpts
10473                if buffer
10474                    .excerpt_containing(insertion_point..range_to_move.end)
10475                    .is_some()
10476                {
10477                    let text = buffer
10478                        .text_for_range(range_to_move.clone())
10479                        .flat_map(|s| s.chars())
10480                        .skip(1)
10481                        .chain(['\n'])
10482                        .collect::<String>();
10483
10484                    edits.push((
10485                        buffer.anchor_after(range_to_move.start)
10486                            ..buffer.anchor_before(range_to_move.end),
10487                        String::new(),
10488                    ));
10489                    let insertion_anchor = buffer.anchor_after(insertion_point);
10490                    edits.push((insertion_anchor..insertion_anchor, text));
10491
10492                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10493
10494                    // Move selections up
10495                    new_selections.extend(contiguous_row_selections.drain(..).map(
10496                        |mut selection| {
10497                            selection.start.row -= row_delta;
10498                            selection.end.row -= row_delta;
10499                            selection
10500                        },
10501                    ));
10502
10503                    // Move folds up
10504                    unfold_ranges.push(range_to_move.clone());
10505                    for fold in display_map.folds_in_range(
10506                        buffer.anchor_before(range_to_move.start)
10507                            ..buffer.anchor_after(range_to_move.end),
10508                    ) {
10509                        let mut start = fold.range.start.to_point(&buffer);
10510                        let mut end = fold.range.end.to_point(&buffer);
10511                        start.row -= row_delta;
10512                        end.row -= row_delta;
10513                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10514                    }
10515                }
10516            }
10517
10518            // If we didn't move line(s), preserve the existing selections
10519            new_selections.append(&mut contiguous_row_selections);
10520        }
10521
10522        self.transact(window, cx, |this, window, cx| {
10523            this.unfold_ranges(&unfold_ranges, true, true, cx);
10524            this.buffer.update(cx, |buffer, cx| {
10525                for (range, text) in edits {
10526                    buffer.edit([(range, text)], None, cx);
10527                }
10528            });
10529            this.fold_creases(refold_creases, true, window, cx);
10530            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10531                s.select(new_selections);
10532            })
10533        });
10534    }
10535
10536    pub fn move_line_down(
10537        &mut self,
10538        _: &MoveLineDown,
10539        window: &mut Window,
10540        cx: &mut Context<Self>,
10541    ) {
10542        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10543
10544        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10545        let buffer = self.buffer.read(cx).snapshot(cx);
10546
10547        let mut edits = Vec::new();
10548        let mut unfold_ranges = Vec::new();
10549        let mut refold_creases = Vec::new();
10550
10551        let selections = self.selections.all::<Point>(cx);
10552        let mut selections = selections.iter().peekable();
10553        let mut contiguous_row_selections = Vec::new();
10554        let mut new_selections = Vec::new();
10555
10556        while let Some(selection) = selections.next() {
10557            // Find all the selections that span a contiguous row range
10558            let (start_row, end_row) = consume_contiguous_rows(
10559                &mut contiguous_row_selections,
10560                selection,
10561                &display_map,
10562                &mut selections,
10563            );
10564
10565            // Move the text spanned by the row range to be after the last line of the row range
10566            if end_row.0 <= buffer.max_point().row {
10567                let range_to_move =
10568                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10569                let insertion_point = display_map
10570                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10571                    .0;
10572
10573                // Don't move lines across excerpt boundaries
10574                if buffer
10575                    .excerpt_containing(range_to_move.start..insertion_point)
10576                    .is_some()
10577                {
10578                    let mut text = String::from("\n");
10579                    text.extend(buffer.text_for_range(range_to_move.clone()));
10580                    text.pop(); // Drop trailing newline
10581                    edits.push((
10582                        buffer.anchor_after(range_to_move.start)
10583                            ..buffer.anchor_before(range_to_move.end),
10584                        String::new(),
10585                    ));
10586                    let insertion_anchor = buffer.anchor_after(insertion_point);
10587                    edits.push((insertion_anchor..insertion_anchor, text));
10588
10589                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10590
10591                    // Move selections down
10592                    new_selections.extend(contiguous_row_selections.drain(..).map(
10593                        |mut selection| {
10594                            selection.start.row += row_delta;
10595                            selection.end.row += row_delta;
10596                            selection
10597                        },
10598                    ));
10599
10600                    // Move folds down
10601                    unfold_ranges.push(range_to_move.clone());
10602                    for fold in display_map.folds_in_range(
10603                        buffer.anchor_before(range_to_move.start)
10604                            ..buffer.anchor_after(range_to_move.end),
10605                    ) {
10606                        let mut start = fold.range.start.to_point(&buffer);
10607                        let mut end = fold.range.end.to_point(&buffer);
10608                        start.row += row_delta;
10609                        end.row += row_delta;
10610                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10611                    }
10612                }
10613            }
10614
10615            // If we didn't move line(s), preserve the existing selections
10616            new_selections.append(&mut contiguous_row_selections);
10617        }
10618
10619        self.transact(window, cx, |this, window, cx| {
10620            this.unfold_ranges(&unfold_ranges, true, true, cx);
10621            this.buffer.update(cx, |buffer, cx| {
10622                for (range, text) in edits {
10623                    buffer.edit([(range, text)], None, cx);
10624                }
10625            });
10626            this.fold_creases(refold_creases, true, window, cx);
10627            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10628                s.select(new_selections)
10629            });
10630        });
10631    }
10632
10633    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10634        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10635        let text_layout_details = &self.text_layout_details(window);
10636        self.transact(window, cx, |this, window, cx| {
10637            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10638                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10639                s.move_with(|display_map, selection| {
10640                    if !selection.is_empty() {
10641                        return;
10642                    }
10643
10644                    let mut head = selection.head();
10645                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10646                    if head.column() == display_map.line_len(head.row()) {
10647                        transpose_offset = display_map
10648                            .buffer_snapshot
10649                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10650                    }
10651
10652                    if transpose_offset == 0 {
10653                        return;
10654                    }
10655
10656                    *head.column_mut() += 1;
10657                    head = display_map.clip_point(head, Bias::Right);
10658                    let goal = SelectionGoal::HorizontalPosition(
10659                        display_map
10660                            .x_for_display_point(head, text_layout_details)
10661                            .into(),
10662                    );
10663                    selection.collapse_to(head, goal);
10664
10665                    let transpose_start = display_map
10666                        .buffer_snapshot
10667                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10668                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10669                        let transpose_end = display_map
10670                            .buffer_snapshot
10671                            .clip_offset(transpose_offset + 1, Bias::Right);
10672                        if let Some(ch) =
10673                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10674                        {
10675                            edits.push((transpose_start..transpose_offset, String::new()));
10676                            edits.push((transpose_end..transpose_end, ch.to_string()));
10677                        }
10678                    }
10679                });
10680                edits
10681            });
10682            this.buffer
10683                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10684            let selections = this.selections.all::<usize>(cx);
10685            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10686                s.select(selections);
10687            });
10688        });
10689    }
10690
10691    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10692        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10693        self.rewrap_impl(RewrapOptions::default(), cx)
10694    }
10695
10696    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10697        let buffer = self.buffer.read(cx).snapshot(cx);
10698        let selections = self.selections.all::<Point>(cx);
10699        let mut selections = selections.iter().peekable();
10700
10701        let mut edits = Vec::new();
10702        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10703
10704        while let Some(selection) = selections.next() {
10705            let mut start_row = selection.start.row;
10706            let mut end_row = selection.end.row;
10707
10708            // Skip selections that overlap with a range that has already been rewrapped.
10709            let selection_range = start_row..end_row;
10710            if rewrapped_row_ranges
10711                .iter()
10712                .any(|range| range.overlaps(&selection_range))
10713            {
10714                continue;
10715            }
10716
10717            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10718
10719            // Since not all lines in the selection may be at the same indent
10720            // level, choose the indent size that is the most common between all
10721            // of the lines.
10722            //
10723            // If there is a tie, we use the deepest indent.
10724            let (indent_size, indent_end) = {
10725                let mut indent_size_occurrences = HashMap::default();
10726                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10727
10728                for row in start_row..=end_row {
10729                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10730                    rows_by_indent_size.entry(indent).or_default().push(row);
10731                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10732                }
10733
10734                let indent_size = indent_size_occurrences
10735                    .into_iter()
10736                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10737                    .map(|(indent, _)| indent)
10738                    .unwrap_or_default();
10739                let row = rows_by_indent_size[&indent_size][0];
10740                let indent_end = Point::new(row, indent_size.len);
10741
10742                (indent_size, indent_end)
10743            };
10744
10745            let mut line_prefix = indent_size.chars().collect::<String>();
10746
10747            let mut inside_comment = false;
10748            if let Some(comment_prefix) =
10749                buffer
10750                    .language_scope_at(selection.head())
10751                    .and_then(|language| {
10752                        language
10753                            .line_comment_prefixes()
10754                            .iter()
10755                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10756                            .cloned()
10757                    })
10758            {
10759                line_prefix.push_str(&comment_prefix);
10760                inside_comment = true;
10761            }
10762
10763            let language_settings = buffer.language_settings_at(selection.head(), cx);
10764            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10765                RewrapBehavior::InComments => inside_comment,
10766                RewrapBehavior::InSelections => !selection.is_empty(),
10767                RewrapBehavior::Anywhere => true,
10768            };
10769
10770            let should_rewrap = options.override_language_settings
10771                || allow_rewrap_based_on_language
10772                || self.hard_wrap.is_some();
10773            if !should_rewrap {
10774                continue;
10775            }
10776
10777            if selection.is_empty() {
10778                'expand_upwards: while start_row > 0 {
10779                    let prev_row = start_row - 1;
10780                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10781                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10782                    {
10783                        start_row = prev_row;
10784                    } else {
10785                        break 'expand_upwards;
10786                    }
10787                }
10788
10789                'expand_downwards: while end_row < buffer.max_point().row {
10790                    let next_row = end_row + 1;
10791                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10792                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10793                    {
10794                        end_row = next_row;
10795                    } else {
10796                        break 'expand_downwards;
10797                    }
10798                }
10799            }
10800
10801            let start = Point::new(start_row, 0);
10802            let start_offset = start.to_offset(&buffer);
10803            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10804            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10805            let Some(lines_without_prefixes) = selection_text
10806                .lines()
10807                .map(|line| {
10808                    line.strip_prefix(&line_prefix)
10809                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10810                        .with_context(|| {
10811                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10812                        })
10813                })
10814                .collect::<Result<Vec<_>, _>>()
10815                .log_err()
10816            else {
10817                continue;
10818            };
10819
10820            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10821                buffer
10822                    .language_settings_at(Point::new(start_row, 0), cx)
10823                    .preferred_line_length as usize
10824            });
10825            let wrapped_text = wrap_with_prefix(
10826                line_prefix,
10827                lines_without_prefixes.join("\n"),
10828                wrap_column,
10829                tab_size,
10830                options.preserve_existing_whitespace,
10831            );
10832
10833            // TODO: should always use char-based diff while still supporting cursor behavior that
10834            // matches vim.
10835            let mut diff_options = DiffOptions::default();
10836            if options.override_language_settings {
10837                diff_options.max_word_diff_len = 0;
10838                diff_options.max_word_diff_line_count = 0;
10839            } else {
10840                diff_options.max_word_diff_len = usize::MAX;
10841                diff_options.max_word_diff_line_count = usize::MAX;
10842            }
10843
10844            for (old_range, new_text) in
10845                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10846            {
10847                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10848                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10849                edits.push((edit_start..edit_end, new_text));
10850            }
10851
10852            rewrapped_row_ranges.push(start_row..=end_row);
10853        }
10854
10855        self.buffer
10856            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10857    }
10858
10859    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10860        let mut text = String::new();
10861        let buffer = self.buffer.read(cx).snapshot(cx);
10862        let mut selections = self.selections.all::<Point>(cx);
10863        let mut clipboard_selections = Vec::with_capacity(selections.len());
10864        {
10865            let max_point = buffer.max_point();
10866            let mut is_first = true;
10867            for selection in &mut selections {
10868                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10869                if is_entire_line {
10870                    selection.start = Point::new(selection.start.row, 0);
10871                    if !selection.is_empty() && selection.end.column == 0 {
10872                        selection.end = cmp::min(max_point, selection.end);
10873                    } else {
10874                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10875                    }
10876                    selection.goal = SelectionGoal::None;
10877                }
10878                if is_first {
10879                    is_first = false;
10880                } else {
10881                    text += "\n";
10882                }
10883                let mut len = 0;
10884                for chunk in buffer.text_for_range(selection.start..selection.end) {
10885                    text.push_str(chunk);
10886                    len += chunk.len();
10887                }
10888                clipboard_selections.push(ClipboardSelection {
10889                    len,
10890                    is_entire_line,
10891                    first_line_indent: buffer
10892                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10893                        .len,
10894                });
10895            }
10896        }
10897
10898        self.transact(window, cx, |this, window, cx| {
10899            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10900                s.select(selections);
10901            });
10902            this.insert("", window, cx);
10903        });
10904        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10905    }
10906
10907    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10908        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10909        let item = self.cut_common(window, cx);
10910        cx.write_to_clipboard(item);
10911    }
10912
10913    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10915        self.change_selections(None, window, cx, |s| {
10916            s.move_with(|snapshot, sel| {
10917                if sel.is_empty() {
10918                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10919                }
10920            });
10921        });
10922        let item = self.cut_common(window, cx);
10923        cx.set_global(KillRing(item))
10924    }
10925
10926    pub fn kill_ring_yank(
10927        &mut self,
10928        _: &KillRingYank,
10929        window: &mut Window,
10930        cx: &mut Context<Self>,
10931    ) {
10932        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10933        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10934            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10935                (kill_ring.text().to_string(), kill_ring.metadata_json())
10936            } else {
10937                return;
10938            }
10939        } else {
10940            return;
10941        };
10942        self.do_paste(&text, metadata, false, window, cx);
10943    }
10944
10945    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10946        self.do_copy(true, cx);
10947    }
10948
10949    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10950        self.do_copy(false, cx);
10951    }
10952
10953    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10954        let selections = self.selections.all::<Point>(cx);
10955        let buffer = self.buffer.read(cx).read(cx);
10956        let mut text = String::new();
10957
10958        let mut clipboard_selections = Vec::with_capacity(selections.len());
10959        {
10960            let max_point = buffer.max_point();
10961            let mut is_first = true;
10962            for selection in &selections {
10963                let mut start = selection.start;
10964                let mut end = selection.end;
10965                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10966                if is_entire_line {
10967                    start = Point::new(start.row, 0);
10968                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10969                }
10970
10971                let mut trimmed_selections = Vec::new();
10972                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10973                    let row = MultiBufferRow(start.row);
10974                    let first_indent = buffer.indent_size_for_line(row);
10975                    if first_indent.len == 0 || start.column > first_indent.len {
10976                        trimmed_selections.push(start..end);
10977                    } else {
10978                        trimmed_selections.push(
10979                            Point::new(row.0, first_indent.len)
10980                                ..Point::new(row.0, buffer.line_len(row)),
10981                        );
10982                        for row in start.row + 1..=end.row {
10983                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10984                            if row == end.row {
10985                                line_len = end.column;
10986                            }
10987                            if line_len == 0 {
10988                                trimmed_selections
10989                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10990                                continue;
10991                            }
10992                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10993                            if row_indent_size.len >= first_indent.len {
10994                                trimmed_selections.push(
10995                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10996                                );
10997                            } else {
10998                                trimmed_selections.clear();
10999                                trimmed_selections.push(start..end);
11000                                break;
11001                            }
11002                        }
11003                    }
11004                } else {
11005                    trimmed_selections.push(start..end);
11006                }
11007
11008                for trimmed_range in trimmed_selections {
11009                    if is_first {
11010                        is_first = false;
11011                    } else {
11012                        text += "\n";
11013                    }
11014                    let mut len = 0;
11015                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11016                        text.push_str(chunk);
11017                        len += chunk.len();
11018                    }
11019                    clipboard_selections.push(ClipboardSelection {
11020                        len,
11021                        is_entire_line,
11022                        first_line_indent: buffer
11023                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11024                            .len,
11025                    });
11026                }
11027            }
11028        }
11029
11030        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11031            text,
11032            clipboard_selections,
11033        ));
11034    }
11035
11036    pub fn do_paste(
11037        &mut self,
11038        text: &String,
11039        clipboard_selections: Option<Vec<ClipboardSelection>>,
11040        handle_entire_lines: bool,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) {
11044        if self.read_only(cx) {
11045            return;
11046        }
11047
11048        let clipboard_text = Cow::Borrowed(text);
11049
11050        self.transact(window, cx, |this, window, cx| {
11051            if let Some(mut clipboard_selections) = clipboard_selections {
11052                let old_selections = this.selections.all::<usize>(cx);
11053                let all_selections_were_entire_line =
11054                    clipboard_selections.iter().all(|s| s.is_entire_line);
11055                let first_selection_indent_column =
11056                    clipboard_selections.first().map(|s| s.first_line_indent);
11057                if clipboard_selections.len() != old_selections.len() {
11058                    clipboard_selections.drain(..);
11059                }
11060                let cursor_offset = this.selections.last::<usize>(cx).head();
11061                let mut auto_indent_on_paste = true;
11062
11063                this.buffer.update(cx, |buffer, cx| {
11064                    let snapshot = buffer.read(cx);
11065                    auto_indent_on_paste = snapshot
11066                        .language_settings_at(cursor_offset, cx)
11067                        .auto_indent_on_paste;
11068
11069                    let mut start_offset = 0;
11070                    let mut edits = Vec::new();
11071                    let mut original_indent_columns = Vec::new();
11072                    for (ix, selection) in old_selections.iter().enumerate() {
11073                        let to_insert;
11074                        let entire_line;
11075                        let original_indent_column;
11076                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11077                            let end_offset = start_offset + clipboard_selection.len;
11078                            to_insert = &clipboard_text[start_offset..end_offset];
11079                            entire_line = clipboard_selection.is_entire_line;
11080                            start_offset = end_offset + 1;
11081                            original_indent_column = Some(clipboard_selection.first_line_indent);
11082                        } else {
11083                            to_insert = clipboard_text.as_str();
11084                            entire_line = all_selections_were_entire_line;
11085                            original_indent_column = first_selection_indent_column
11086                        }
11087
11088                        // If the corresponding selection was empty when this slice of the
11089                        // clipboard text was written, then the entire line containing the
11090                        // selection was copied. If this selection is also currently empty,
11091                        // then paste the line before the current line of the buffer.
11092                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11093                            let column = selection.start.to_point(&snapshot).column as usize;
11094                            let line_start = selection.start - column;
11095                            line_start..line_start
11096                        } else {
11097                            selection.range()
11098                        };
11099
11100                        edits.push((range, to_insert));
11101                        original_indent_columns.push(original_indent_column);
11102                    }
11103                    drop(snapshot);
11104
11105                    buffer.edit(
11106                        edits,
11107                        if auto_indent_on_paste {
11108                            Some(AutoindentMode::Block {
11109                                original_indent_columns,
11110                            })
11111                        } else {
11112                            None
11113                        },
11114                        cx,
11115                    );
11116                });
11117
11118                let selections = this.selections.all::<usize>(cx);
11119                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11120                    s.select(selections)
11121                });
11122            } else {
11123                this.insert(&clipboard_text, window, cx);
11124            }
11125        });
11126    }
11127
11128    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11129        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11130        if let Some(item) = cx.read_from_clipboard() {
11131            let entries = item.entries();
11132
11133            match entries.first() {
11134                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11135                // of all the pasted entries.
11136                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11137                    .do_paste(
11138                        clipboard_string.text(),
11139                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11140                        true,
11141                        window,
11142                        cx,
11143                    ),
11144                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11145            }
11146        }
11147    }
11148
11149    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11150        if self.read_only(cx) {
11151            return;
11152        }
11153
11154        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11155
11156        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11157            if let Some((selections, _)) =
11158                self.selection_history.transaction(transaction_id).cloned()
11159            {
11160                self.change_selections(None, window, cx, |s| {
11161                    s.select_anchors(selections.to_vec());
11162                });
11163            } else {
11164                log::error!(
11165                    "No entry in selection_history found for undo. \
11166                     This may correspond to a bug where undo does not update the selection. \
11167                     If this is occurring, please add details to \
11168                     https://github.com/zed-industries/zed/issues/22692"
11169                );
11170            }
11171            self.request_autoscroll(Autoscroll::fit(), cx);
11172            self.unmark_text(window, cx);
11173            self.refresh_inline_completion(true, false, window, cx);
11174            cx.emit(EditorEvent::Edited { transaction_id });
11175            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11176        }
11177    }
11178
11179    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11180        if self.read_only(cx) {
11181            return;
11182        }
11183
11184        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11185
11186        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11187            if let Some((_, Some(selections))) =
11188                self.selection_history.transaction(transaction_id).cloned()
11189            {
11190                self.change_selections(None, window, cx, |s| {
11191                    s.select_anchors(selections.to_vec());
11192                });
11193            } else {
11194                log::error!(
11195                    "No entry in selection_history found for redo. \
11196                     This may correspond to a bug where undo does not update the selection. \
11197                     If this is occurring, please add details to \
11198                     https://github.com/zed-industries/zed/issues/22692"
11199                );
11200            }
11201            self.request_autoscroll(Autoscroll::fit(), cx);
11202            self.unmark_text(window, cx);
11203            self.refresh_inline_completion(true, false, window, cx);
11204            cx.emit(EditorEvent::Edited { transaction_id });
11205        }
11206    }
11207
11208    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11209        self.buffer
11210            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11211    }
11212
11213    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11214        self.buffer
11215            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11216    }
11217
11218    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11220        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11221            s.move_with(|map, selection| {
11222                let cursor = if selection.is_empty() {
11223                    movement::left(map, selection.start)
11224                } else {
11225                    selection.start
11226                };
11227                selection.collapse_to(cursor, SelectionGoal::None);
11228            });
11229        })
11230    }
11231
11232    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11233        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11234        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11235            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11236        })
11237    }
11238
11239    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11240        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11242            s.move_with(|map, selection| {
11243                let cursor = if selection.is_empty() {
11244                    movement::right(map, selection.end)
11245                } else {
11246                    selection.end
11247                };
11248                selection.collapse_to(cursor, SelectionGoal::None)
11249            });
11250        })
11251    }
11252
11253    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11254        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11255        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11256            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11257        })
11258    }
11259
11260    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11261        if self.take_rename(true, window, cx).is_some() {
11262            return;
11263        }
11264
11265        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11266            cx.propagate();
11267            return;
11268        }
11269
11270        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11271
11272        let text_layout_details = &self.text_layout_details(window);
11273        let selection_count = self.selections.count();
11274        let first_selection = self.selections.first_anchor();
11275
11276        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11277            s.move_with(|map, selection| {
11278                if !selection.is_empty() {
11279                    selection.goal = SelectionGoal::None;
11280                }
11281                let (cursor, goal) = movement::up(
11282                    map,
11283                    selection.start,
11284                    selection.goal,
11285                    false,
11286                    text_layout_details,
11287                );
11288                selection.collapse_to(cursor, goal);
11289            });
11290        });
11291
11292        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11293        {
11294            cx.propagate();
11295        }
11296    }
11297
11298    pub fn move_up_by_lines(
11299        &mut self,
11300        action: &MoveUpByLines,
11301        window: &mut Window,
11302        cx: &mut Context<Self>,
11303    ) {
11304        if self.take_rename(true, window, cx).is_some() {
11305            return;
11306        }
11307
11308        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11309            cx.propagate();
11310            return;
11311        }
11312
11313        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11314
11315        let text_layout_details = &self.text_layout_details(window);
11316
11317        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11318            s.move_with(|map, selection| {
11319                if !selection.is_empty() {
11320                    selection.goal = SelectionGoal::None;
11321                }
11322                let (cursor, goal) = movement::up_by_rows(
11323                    map,
11324                    selection.start,
11325                    action.lines,
11326                    selection.goal,
11327                    false,
11328                    text_layout_details,
11329                );
11330                selection.collapse_to(cursor, goal);
11331            });
11332        })
11333    }
11334
11335    pub fn move_down_by_lines(
11336        &mut self,
11337        action: &MoveDownByLines,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        if self.take_rename(true, window, cx).is_some() {
11342            return;
11343        }
11344
11345        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11346            cx.propagate();
11347            return;
11348        }
11349
11350        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11351
11352        let text_layout_details = &self.text_layout_details(window);
11353
11354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11355            s.move_with(|map, selection| {
11356                if !selection.is_empty() {
11357                    selection.goal = SelectionGoal::None;
11358                }
11359                let (cursor, goal) = movement::down_by_rows(
11360                    map,
11361                    selection.start,
11362                    action.lines,
11363                    selection.goal,
11364                    false,
11365                    text_layout_details,
11366                );
11367                selection.collapse_to(cursor, goal);
11368            });
11369        })
11370    }
11371
11372    pub fn select_down_by_lines(
11373        &mut self,
11374        action: &SelectDownByLines,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11379        let text_layout_details = &self.text_layout_details(window);
11380        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11381            s.move_heads_with(|map, head, goal| {
11382                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11383            })
11384        })
11385    }
11386
11387    pub fn select_up_by_lines(
11388        &mut self,
11389        action: &SelectUpByLines,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11394        let text_layout_details = &self.text_layout_details(window);
11395        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11396            s.move_heads_with(|map, head, goal| {
11397                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11398            })
11399        })
11400    }
11401
11402    pub fn select_page_up(
11403        &mut self,
11404        _: &SelectPageUp,
11405        window: &mut Window,
11406        cx: &mut Context<Self>,
11407    ) {
11408        let Some(row_count) = self.visible_row_count() else {
11409            return;
11410        };
11411
11412        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11413
11414        let text_layout_details = &self.text_layout_details(window);
11415
11416        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11417            s.move_heads_with(|map, head, goal| {
11418                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11419            })
11420        })
11421    }
11422
11423    pub fn move_page_up(
11424        &mut self,
11425        action: &MovePageUp,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        if self.take_rename(true, window, cx).is_some() {
11430            return;
11431        }
11432
11433        if self
11434            .context_menu
11435            .borrow_mut()
11436            .as_mut()
11437            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11438            .unwrap_or(false)
11439        {
11440            return;
11441        }
11442
11443        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11444            cx.propagate();
11445            return;
11446        }
11447
11448        let Some(row_count) = self.visible_row_count() else {
11449            return;
11450        };
11451
11452        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11453
11454        let autoscroll = if action.center_cursor {
11455            Autoscroll::center()
11456        } else {
11457            Autoscroll::fit()
11458        };
11459
11460        let text_layout_details = &self.text_layout_details(window);
11461
11462        self.change_selections(Some(autoscroll), window, cx, |s| {
11463            s.move_with(|map, selection| {
11464                if !selection.is_empty() {
11465                    selection.goal = SelectionGoal::None;
11466                }
11467                let (cursor, goal) = movement::up_by_rows(
11468                    map,
11469                    selection.end,
11470                    row_count,
11471                    selection.goal,
11472                    false,
11473                    text_layout_details,
11474                );
11475                selection.collapse_to(cursor, goal);
11476            });
11477        });
11478    }
11479
11480    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11481        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11482        let text_layout_details = &self.text_layout_details(window);
11483        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11484            s.move_heads_with(|map, head, goal| {
11485                movement::up(map, head, goal, false, text_layout_details)
11486            })
11487        })
11488    }
11489
11490    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11491        self.take_rename(true, window, cx);
11492
11493        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11494            cx.propagate();
11495            return;
11496        }
11497
11498        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11499
11500        let text_layout_details = &self.text_layout_details(window);
11501        let selection_count = self.selections.count();
11502        let first_selection = self.selections.first_anchor();
11503
11504        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11505            s.move_with(|map, selection| {
11506                if !selection.is_empty() {
11507                    selection.goal = SelectionGoal::None;
11508                }
11509                let (cursor, goal) = movement::down(
11510                    map,
11511                    selection.end,
11512                    selection.goal,
11513                    false,
11514                    text_layout_details,
11515                );
11516                selection.collapse_to(cursor, goal);
11517            });
11518        });
11519
11520        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11521        {
11522            cx.propagate();
11523        }
11524    }
11525
11526    pub fn select_page_down(
11527        &mut self,
11528        _: &SelectPageDown,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) {
11532        let Some(row_count) = self.visible_row_count() else {
11533            return;
11534        };
11535
11536        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11537
11538        let text_layout_details = &self.text_layout_details(window);
11539
11540        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11541            s.move_heads_with(|map, head, goal| {
11542                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11543            })
11544        })
11545    }
11546
11547    pub fn move_page_down(
11548        &mut self,
11549        action: &MovePageDown,
11550        window: &mut Window,
11551        cx: &mut Context<Self>,
11552    ) {
11553        if self.take_rename(true, window, cx).is_some() {
11554            return;
11555        }
11556
11557        if self
11558            .context_menu
11559            .borrow_mut()
11560            .as_mut()
11561            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11562            .unwrap_or(false)
11563        {
11564            return;
11565        }
11566
11567        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11568            cx.propagate();
11569            return;
11570        }
11571
11572        let Some(row_count) = self.visible_row_count() else {
11573            return;
11574        };
11575
11576        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11577
11578        let autoscroll = if action.center_cursor {
11579            Autoscroll::center()
11580        } else {
11581            Autoscroll::fit()
11582        };
11583
11584        let text_layout_details = &self.text_layout_details(window);
11585        self.change_selections(Some(autoscroll), window, cx, |s| {
11586            s.move_with(|map, selection| {
11587                if !selection.is_empty() {
11588                    selection.goal = SelectionGoal::None;
11589                }
11590                let (cursor, goal) = movement::down_by_rows(
11591                    map,
11592                    selection.end,
11593                    row_count,
11594                    selection.goal,
11595                    false,
11596                    text_layout_details,
11597                );
11598                selection.collapse_to(cursor, goal);
11599            });
11600        });
11601    }
11602
11603    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11604        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11605        let text_layout_details = &self.text_layout_details(window);
11606        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11607            s.move_heads_with(|map, head, goal| {
11608                movement::down(map, head, goal, false, text_layout_details)
11609            })
11610        });
11611    }
11612
11613    pub fn context_menu_first(
11614        &mut self,
11615        _: &ContextMenuFirst,
11616        window: &mut Window,
11617        cx: &mut Context<Self>,
11618    ) {
11619        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11620            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11621        }
11622    }
11623
11624    pub fn context_menu_prev(
11625        &mut self,
11626        _: &ContextMenuPrevious,
11627        window: &mut Window,
11628        cx: &mut Context<Self>,
11629    ) {
11630        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11631            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11632        }
11633    }
11634
11635    pub fn context_menu_next(
11636        &mut self,
11637        _: &ContextMenuNext,
11638        window: &mut Window,
11639        cx: &mut Context<Self>,
11640    ) {
11641        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11642            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11643        }
11644    }
11645
11646    pub fn context_menu_last(
11647        &mut self,
11648        _: &ContextMenuLast,
11649        window: &mut Window,
11650        cx: &mut Context<Self>,
11651    ) {
11652        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11653            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11654        }
11655    }
11656
11657    pub fn move_to_previous_word_start(
11658        &mut self,
11659        _: &MoveToPreviousWordStart,
11660        window: &mut Window,
11661        cx: &mut Context<Self>,
11662    ) {
11663        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11664        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11665            s.move_cursors_with(|map, head, _| {
11666                (
11667                    movement::previous_word_start(map, head),
11668                    SelectionGoal::None,
11669                )
11670            });
11671        })
11672    }
11673
11674    pub fn move_to_previous_subword_start(
11675        &mut self,
11676        _: &MoveToPreviousSubwordStart,
11677        window: &mut Window,
11678        cx: &mut Context<Self>,
11679    ) {
11680        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11681        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11682            s.move_cursors_with(|map, head, _| {
11683                (
11684                    movement::previous_subword_start(map, head),
11685                    SelectionGoal::None,
11686                )
11687            });
11688        })
11689    }
11690
11691    pub fn select_to_previous_word_start(
11692        &mut self,
11693        _: &SelectToPreviousWordStart,
11694        window: &mut Window,
11695        cx: &mut Context<Self>,
11696    ) {
11697        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11698        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11699            s.move_heads_with(|map, head, _| {
11700                (
11701                    movement::previous_word_start(map, head),
11702                    SelectionGoal::None,
11703                )
11704            });
11705        })
11706    }
11707
11708    pub fn select_to_previous_subword_start(
11709        &mut self,
11710        _: &SelectToPreviousSubwordStart,
11711        window: &mut Window,
11712        cx: &mut Context<Self>,
11713    ) {
11714        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11715        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11716            s.move_heads_with(|map, head, _| {
11717                (
11718                    movement::previous_subword_start(map, head),
11719                    SelectionGoal::None,
11720                )
11721            });
11722        })
11723    }
11724
11725    pub fn delete_to_previous_word_start(
11726        &mut self,
11727        action: &DeleteToPreviousWordStart,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11732        self.transact(window, cx, |this, window, cx| {
11733            this.select_autoclose_pair(window, cx);
11734            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11735                s.move_with(|map, selection| {
11736                    if selection.is_empty() {
11737                        let cursor = if action.ignore_newlines {
11738                            movement::previous_word_start(map, selection.head())
11739                        } else {
11740                            movement::previous_word_start_or_newline(map, selection.head())
11741                        };
11742                        selection.set_head(cursor, SelectionGoal::None);
11743                    }
11744                });
11745            });
11746            this.insert("", window, cx);
11747        });
11748    }
11749
11750    pub fn delete_to_previous_subword_start(
11751        &mut self,
11752        _: &DeleteToPreviousSubwordStart,
11753        window: &mut Window,
11754        cx: &mut Context<Self>,
11755    ) {
11756        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11757        self.transact(window, cx, |this, window, cx| {
11758            this.select_autoclose_pair(window, cx);
11759            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11760                s.move_with(|map, selection| {
11761                    if selection.is_empty() {
11762                        let cursor = movement::previous_subword_start(map, selection.head());
11763                        selection.set_head(cursor, SelectionGoal::None);
11764                    }
11765                });
11766            });
11767            this.insert("", window, cx);
11768        });
11769    }
11770
11771    pub fn move_to_next_word_end(
11772        &mut self,
11773        _: &MoveToNextWordEnd,
11774        window: &mut Window,
11775        cx: &mut Context<Self>,
11776    ) {
11777        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11778        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11779            s.move_cursors_with(|map, head, _| {
11780                (movement::next_word_end(map, head), SelectionGoal::None)
11781            });
11782        })
11783    }
11784
11785    pub fn move_to_next_subword_end(
11786        &mut self,
11787        _: &MoveToNextSubwordEnd,
11788        window: &mut Window,
11789        cx: &mut Context<Self>,
11790    ) {
11791        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11792        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11793            s.move_cursors_with(|map, head, _| {
11794                (movement::next_subword_end(map, head), SelectionGoal::None)
11795            });
11796        })
11797    }
11798
11799    pub fn select_to_next_word_end(
11800        &mut self,
11801        _: &SelectToNextWordEnd,
11802        window: &mut Window,
11803        cx: &mut Context<Self>,
11804    ) {
11805        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11806        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11807            s.move_heads_with(|map, head, _| {
11808                (movement::next_word_end(map, head), SelectionGoal::None)
11809            });
11810        })
11811    }
11812
11813    pub fn select_to_next_subword_end(
11814        &mut self,
11815        _: &SelectToNextSubwordEnd,
11816        window: &mut Window,
11817        cx: &mut Context<Self>,
11818    ) {
11819        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11820        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11821            s.move_heads_with(|map, head, _| {
11822                (movement::next_subword_end(map, head), SelectionGoal::None)
11823            });
11824        })
11825    }
11826
11827    pub fn delete_to_next_word_end(
11828        &mut self,
11829        action: &DeleteToNextWordEnd,
11830        window: &mut Window,
11831        cx: &mut Context<Self>,
11832    ) {
11833        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11834        self.transact(window, cx, |this, window, cx| {
11835            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11836                s.move_with(|map, selection| {
11837                    if selection.is_empty() {
11838                        let cursor = if action.ignore_newlines {
11839                            movement::next_word_end(map, selection.head())
11840                        } else {
11841                            movement::next_word_end_or_newline(map, selection.head())
11842                        };
11843                        selection.set_head(cursor, SelectionGoal::None);
11844                    }
11845                });
11846            });
11847            this.insert("", window, cx);
11848        });
11849    }
11850
11851    pub fn delete_to_next_subword_end(
11852        &mut self,
11853        _: &DeleteToNextSubwordEnd,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11858        self.transact(window, cx, |this, window, cx| {
11859            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11860                s.move_with(|map, selection| {
11861                    if selection.is_empty() {
11862                        let cursor = movement::next_subword_end(map, selection.head());
11863                        selection.set_head(cursor, SelectionGoal::None);
11864                    }
11865                });
11866            });
11867            this.insert("", window, cx);
11868        });
11869    }
11870
11871    pub fn move_to_beginning_of_line(
11872        &mut self,
11873        action: &MoveToBeginningOfLine,
11874        window: &mut Window,
11875        cx: &mut Context<Self>,
11876    ) {
11877        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11878        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11879            s.move_cursors_with(|map, head, _| {
11880                (
11881                    movement::indented_line_beginning(
11882                        map,
11883                        head,
11884                        action.stop_at_soft_wraps,
11885                        action.stop_at_indent,
11886                    ),
11887                    SelectionGoal::None,
11888                )
11889            });
11890        })
11891    }
11892
11893    pub fn select_to_beginning_of_line(
11894        &mut self,
11895        action: &SelectToBeginningOfLine,
11896        window: &mut Window,
11897        cx: &mut Context<Self>,
11898    ) {
11899        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11900        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11901            s.move_heads_with(|map, head, _| {
11902                (
11903                    movement::indented_line_beginning(
11904                        map,
11905                        head,
11906                        action.stop_at_soft_wraps,
11907                        action.stop_at_indent,
11908                    ),
11909                    SelectionGoal::None,
11910                )
11911            });
11912        });
11913    }
11914
11915    pub fn delete_to_beginning_of_line(
11916        &mut self,
11917        action: &DeleteToBeginningOfLine,
11918        window: &mut Window,
11919        cx: &mut Context<Self>,
11920    ) {
11921        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11922        self.transact(window, cx, |this, window, cx| {
11923            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11924                s.move_with(|_, selection| {
11925                    selection.reversed = true;
11926                });
11927            });
11928
11929            this.select_to_beginning_of_line(
11930                &SelectToBeginningOfLine {
11931                    stop_at_soft_wraps: false,
11932                    stop_at_indent: action.stop_at_indent,
11933                },
11934                window,
11935                cx,
11936            );
11937            this.backspace(&Backspace, window, cx);
11938        });
11939    }
11940
11941    pub fn move_to_end_of_line(
11942        &mut self,
11943        action: &MoveToEndOfLine,
11944        window: &mut Window,
11945        cx: &mut Context<Self>,
11946    ) {
11947        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11948        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11949            s.move_cursors_with(|map, head, _| {
11950                (
11951                    movement::line_end(map, head, action.stop_at_soft_wraps),
11952                    SelectionGoal::None,
11953                )
11954            });
11955        })
11956    }
11957
11958    pub fn select_to_end_of_line(
11959        &mut self,
11960        action: &SelectToEndOfLine,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11965        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11966            s.move_heads_with(|map, head, _| {
11967                (
11968                    movement::line_end(map, head, action.stop_at_soft_wraps),
11969                    SelectionGoal::None,
11970                )
11971            });
11972        })
11973    }
11974
11975    pub fn delete_to_end_of_line(
11976        &mut self,
11977        _: &DeleteToEndOfLine,
11978        window: &mut Window,
11979        cx: &mut Context<Self>,
11980    ) {
11981        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11982        self.transact(window, cx, |this, window, cx| {
11983            this.select_to_end_of_line(
11984                &SelectToEndOfLine {
11985                    stop_at_soft_wraps: false,
11986                },
11987                window,
11988                cx,
11989            );
11990            this.delete(&Delete, window, cx);
11991        });
11992    }
11993
11994    pub fn cut_to_end_of_line(
11995        &mut self,
11996        _: &CutToEndOfLine,
11997        window: &mut Window,
11998        cx: &mut Context<Self>,
11999    ) {
12000        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12001        self.transact(window, cx, |this, window, cx| {
12002            this.select_to_end_of_line(
12003                &SelectToEndOfLine {
12004                    stop_at_soft_wraps: false,
12005                },
12006                window,
12007                cx,
12008            );
12009            this.cut(&Cut, window, cx);
12010        });
12011    }
12012
12013    pub fn move_to_start_of_paragraph(
12014        &mut self,
12015        _: &MoveToStartOfParagraph,
12016        window: &mut Window,
12017        cx: &mut Context<Self>,
12018    ) {
12019        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12020            cx.propagate();
12021            return;
12022        }
12023        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12024        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12025            s.move_with(|map, selection| {
12026                selection.collapse_to(
12027                    movement::start_of_paragraph(map, selection.head(), 1),
12028                    SelectionGoal::None,
12029                )
12030            });
12031        })
12032    }
12033
12034    pub fn move_to_end_of_paragraph(
12035        &mut self,
12036        _: &MoveToEndOfParagraph,
12037        window: &mut Window,
12038        cx: &mut Context<Self>,
12039    ) {
12040        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12041            cx.propagate();
12042            return;
12043        }
12044        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12045        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12046            s.move_with(|map, selection| {
12047                selection.collapse_to(
12048                    movement::end_of_paragraph(map, selection.head(), 1),
12049                    SelectionGoal::None,
12050                )
12051            });
12052        })
12053    }
12054
12055    pub fn select_to_start_of_paragraph(
12056        &mut self,
12057        _: &SelectToStartOfParagraph,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) {
12061        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12062            cx.propagate();
12063            return;
12064        }
12065        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12066        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12067            s.move_heads_with(|map, head, _| {
12068                (
12069                    movement::start_of_paragraph(map, head, 1),
12070                    SelectionGoal::None,
12071                )
12072            });
12073        })
12074    }
12075
12076    pub fn select_to_end_of_paragraph(
12077        &mut self,
12078        _: &SelectToEndOfParagraph,
12079        window: &mut Window,
12080        cx: &mut Context<Self>,
12081    ) {
12082        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12083            cx.propagate();
12084            return;
12085        }
12086        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12087        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12088            s.move_heads_with(|map, head, _| {
12089                (
12090                    movement::end_of_paragraph(map, head, 1),
12091                    SelectionGoal::None,
12092                )
12093            });
12094        })
12095    }
12096
12097    pub fn move_to_start_of_excerpt(
12098        &mut self,
12099        _: &MoveToStartOfExcerpt,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12104            cx.propagate();
12105            return;
12106        }
12107        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12108        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12109            s.move_with(|map, selection| {
12110                selection.collapse_to(
12111                    movement::start_of_excerpt(
12112                        map,
12113                        selection.head(),
12114                        workspace::searchable::Direction::Prev,
12115                    ),
12116                    SelectionGoal::None,
12117                )
12118            });
12119        })
12120    }
12121
12122    pub fn move_to_start_of_next_excerpt(
12123        &mut self,
12124        _: &MoveToStartOfNextExcerpt,
12125        window: &mut Window,
12126        cx: &mut Context<Self>,
12127    ) {
12128        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12129            cx.propagate();
12130            return;
12131        }
12132
12133        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12134            s.move_with(|map, selection| {
12135                selection.collapse_to(
12136                    movement::start_of_excerpt(
12137                        map,
12138                        selection.head(),
12139                        workspace::searchable::Direction::Next,
12140                    ),
12141                    SelectionGoal::None,
12142                )
12143            });
12144        })
12145    }
12146
12147    pub fn move_to_end_of_excerpt(
12148        &mut self,
12149        _: &MoveToEndOfExcerpt,
12150        window: &mut Window,
12151        cx: &mut Context<Self>,
12152    ) {
12153        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12154            cx.propagate();
12155            return;
12156        }
12157        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12158        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12159            s.move_with(|map, selection| {
12160                selection.collapse_to(
12161                    movement::end_of_excerpt(
12162                        map,
12163                        selection.head(),
12164                        workspace::searchable::Direction::Next,
12165                    ),
12166                    SelectionGoal::None,
12167                )
12168            });
12169        })
12170    }
12171
12172    pub fn move_to_end_of_previous_excerpt(
12173        &mut self,
12174        _: &MoveToEndOfPreviousExcerpt,
12175        window: &mut Window,
12176        cx: &mut Context<Self>,
12177    ) {
12178        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12179            cx.propagate();
12180            return;
12181        }
12182        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12183        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12184            s.move_with(|map, selection| {
12185                selection.collapse_to(
12186                    movement::end_of_excerpt(
12187                        map,
12188                        selection.head(),
12189                        workspace::searchable::Direction::Prev,
12190                    ),
12191                    SelectionGoal::None,
12192                )
12193            });
12194        })
12195    }
12196
12197    pub fn select_to_start_of_excerpt(
12198        &mut self,
12199        _: &SelectToStartOfExcerpt,
12200        window: &mut Window,
12201        cx: &mut Context<Self>,
12202    ) {
12203        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12204            cx.propagate();
12205            return;
12206        }
12207        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12208        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12209            s.move_heads_with(|map, head, _| {
12210                (
12211                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12212                    SelectionGoal::None,
12213                )
12214            });
12215        })
12216    }
12217
12218    pub fn select_to_start_of_next_excerpt(
12219        &mut self,
12220        _: &SelectToStartOfNextExcerpt,
12221        window: &mut Window,
12222        cx: &mut Context<Self>,
12223    ) {
12224        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12225            cx.propagate();
12226            return;
12227        }
12228        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12229        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12230            s.move_heads_with(|map, head, _| {
12231                (
12232                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12233                    SelectionGoal::None,
12234                )
12235            });
12236        })
12237    }
12238
12239    pub fn select_to_end_of_excerpt(
12240        &mut self,
12241        _: &SelectToEndOfExcerpt,
12242        window: &mut Window,
12243        cx: &mut Context<Self>,
12244    ) {
12245        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12246            cx.propagate();
12247            return;
12248        }
12249        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12250        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12251            s.move_heads_with(|map, head, _| {
12252                (
12253                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12254                    SelectionGoal::None,
12255                )
12256            });
12257        })
12258    }
12259
12260    pub fn select_to_end_of_previous_excerpt(
12261        &mut self,
12262        _: &SelectToEndOfPreviousExcerpt,
12263        window: &mut Window,
12264        cx: &mut Context<Self>,
12265    ) {
12266        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12267            cx.propagate();
12268            return;
12269        }
12270        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12271        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12272            s.move_heads_with(|map, head, _| {
12273                (
12274                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12275                    SelectionGoal::None,
12276                )
12277            });
12278        })
12279    }
12280
12281    pub fn move_to_beginning(
12282        &mut self,
12283        _: &MoveToBeginning,
12284        window: &mut Window,
12285        cx: &mut Context<Self>,
12286    ) {
12287        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12288            cx.propagate();
12289            return;
12290        }
12291        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12292        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12293            s.select_ranges(vec![0..0]);
12294        });
12295    }
12296
12297    pub fn select_to_beginning(
12298        &mut self,
12299        _: &SelectToBeginning,
12300        window: &mut Window,
12301        cx: &mut Context<Self>,
12302    ) {
12303        let mut selection = self.selections.last::<Point>(cx);
12304        selection.set_head(Point::zero(), SelectionGoal::None);
12305        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12307            s.select(vec![selection]);
12308        });
12309    }
12310
12311    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12312        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12313            cx.propagate();
12314            return;
12315        }
12316        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12317        let cursor = self.buffer.read(cx).read(cx).len();
12318        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12319            s.select_ranges(vec![cursor..cursor])
12320        });
12321    }
12322
12323    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12324        self.nav_history = nav_history;
12325    }
12326
12327    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12328        self.nav_history.as_ref()
12329    }
12330
12331    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12332        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12333    }
12334
12335    fn push_to_nav_history(
12336        &mut self,
12337        cursor_anchor: Anchor,
12338        new_position: Option<Point>,
12339        is_deactivate: bool,
12340        cx: &mut Context<Self>,
12341    ) {
12342        if let Some(nav_history) = self.nav_history.as_mut() {
12343            let buffer = self.buffer.read(cx).read(cx);
12344            let cursor_position = cursor_anchor.to_point(&buffer);
12345            let scroll_state = self.scroll_manager.anchor();
12346            let scroll_top_row = scroll_state.top_row(&buffer);
12347            drop(buffer);
12348
12349            if let Some(new_position) = new_position {
12350                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12351                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12352                    return;
12353                }
12354            }
12355
12356            nav_history.push(
12357                Some(NavigationData {
12358                    cursor_anchor,
12359                    cursor_position,
12360                    scroll_anchor: scroll_state,
12361                    scroll_top_row,
12362                }),
12363                cx,
12364            );
12365            cx.emit(EditorEvent::PushedToNavHistory {
12366                anchor: cursor_anchor,
12367                is_deactivate,
12368            })
12369        }
12370    }
12371
12372    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12373        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12374        let buffer = self.buffer.read(cx).snapshot(cx);
12375        let mut selection = self.selections.first::<usize>(cx);
12376        selection.set_head(buffer.len(), SelectionGoal::None);
12377        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12378            s.select(vec![selection]);
12379        });
12380    }
12381
12382    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12383        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12384        let end = self.buffer.read(cx).read(cx).len();
12385        self.change_selections(None, window, cx, |s| {
12386            s.select_ranges(vec![0..end]);
12387        });
12388    }
12389
12390    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12391        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12393        let mut selections = self.selections.all::<Point>(cx);
12394        let max_point = display_map.buffer_snapshot.max_point();
12395        for selection in &mut selections {
12396            let rows = selection.spanned_rows(true, &display_map);
12397            selection.start = Point::new(rows.start.0, 0);
12398            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12399            selection.reversed = false;
12400        }
12401        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12402            s.select(selections);
12403        });
12404    }
12405
12406    pub fn split_selection_into_lines(
12407        &mut self,
12408        _: &SplitSelectionIntoLines,
12409        window: &mut Window,
12410        cx: &mut Context<Self>,
12411    ) {
12412        let selections = self
12413            .selections
12414            .all::<Point>(cx)
12415            .into_iter()
12416            .map(|selection| selection.start..selection.end)
12417            .collect::<Vec<_>>();
12418        self.unfold_ranges(&selections, true, true, cx);
12419
12420        let mut new_selection_ranges = Vec::new();
12421        {
12422            let buffer = self.buffer.read(cx).read(cx);
12423            for selection in selections {
12424                for row in selection.start.row..selection.end.row {
12425                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12426                    new_selection_ranges.push(cursor..cursor);
12427                }
12428
12429                let is_multiline_selection = selection.start.row != selection.end.row;
12430                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12431                // so this action feels more ergonomic when paired with other selection operations
12432                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12433                if !should_skip_last {
12434                    new_selection_ranges.push(selection.end..selection.end);
12435                }
12436            }
12437        }
12438        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12439            s.select_ranges(new_selection_ranges);
12440        });
12441    }
12442
12443    pub fn add_selection_above(
12444        &mut self,
12445        _: &AddSelectionAbove,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        self.add_selection(true, window, cx);
12450    }
12451
12452    pub fn add_selection_below(
12453        &mut self,
12454        _: &AddSelectionBelow,
12455        window: &mut Window,
12456        cx: &mut Context<Self>,
12457    ) {
12458        self.add_selection(false, window, cx);
12459    }
12460
12461    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12462        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12463
12464        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12465        let mut selections = self.selections.all::<Point>(cx);
12466        let text_layout_details = self.text_layout_details(window);
12467        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12468            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12469            let range = oldest_selection.display_range(&display_map).sorted();
12470
12471            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12472            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12473            let positions = start_x.min(end_x)..start_x.max(end_x);
12474
12475            selections.clear();
12476            let mut stack = Vec::new();
12477            for row in range.start.row().0..=range.end.row().0 {
12478                if let Some(selection) = self.selections.build_columnar_selection(
12479                    &display_map,
12480                    DisplayRow(row),
12481                    &positions,
12482                    oldest_selection.reversed,
12483                    &text_layout_details,
12484                ) {
12485                    stack.push(selection.id);
12486                    selections.push(selection);
12487                }
12488            }
12489
12490            if above {
12491                stack.reverse();
12492            }
12493
12494            AddSelectionsState { above, stack }
12495        });
12496
12497        let last_added_selection = *state.stack.last().unwrap();
12498        let mut new_selections = Vec::new();
12499        if above == state.above {
12500            let end_row = if above {
12501                DisplayRow(0)
12502            } else {
12503                display_map.max_point().row()
12504            };
12505
12506            'outer: for selection in selections {
12507                if selection.id == last_added_selection {
12508                    let range = selection.display_range(&display_map).sorted();
12509                    debug_assert_eq!(range.start.row(), range.end.row());
12510                    let mut row = range.start.row();
12511                    let positions =
12512                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12513                            px(start)..px(end)
12514                        } else {
12515                            let start_x =
12516                                display_map.x_for_display_point(range.start, &text_layout_details);
12517                            let end_x =
12518                                display_map.x_for_display_point(range.end, &text_layout_details);
12519                            start_x.min(end_x)..start_x.max(end_x)
12520                        };
12521
12522                    while row != end_row {
12523                        if above {
12524                            row.0 -= 1;
12525                        } else {
12526                            row.0 += 1;
12527                        }
12528
12529                        if let Some(new_selection) = self.selections.build_columnar_selection(
12530                            &display_map,
12531                            row,
12532                            &positions,
12533                            selection.reversed,
12534                            &text_layout_details,
12535                        ) {
12536                            state.stack.push(new_selection.id);
12537                            if above {
12538                                new_selections.push(new_selection);
12539                                new_selections.push(selection);
12540                            } else {
12541                                new_selections.push(selection);
12542                                new_selections.push(new_selection);
12543                            }
12544
12545                            continue 'outer;
12546                        }
12547                    }
12548                }
12549
12550                new_selections.push(selection);
12551            }
12552        } else {
12553            new_selections = selections;
12554            new_selections.retain(|s| s.id != last_added_selection);
12555            state.stack.pop();
12556        }
12557
12558        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12559            s.select(new_selections);
12560        });
12561        if state.stack.len() > 1 {
12562            self.add_selections_state = Some(state);
12563        }
12564    }
12565
12566    fn select_match_ranges(
12567        &mut self,
12568        range: Range<usize>,
12569        reversed: bool,
12570        replace_newest: bool,
12571        auto_scroll: Option<Autoscroll>,
12572        window: &mut Window,
12573        cx: &mut Context<Editor>,
12574    ) {
12575        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12576        self.change_selections(auto_scroll, window, cx, |s| {
12577            if replace_newest {
12578                s.delete(s.newest_anchor().id);
12579            }
12580            if reversed {
12581                s.insert_range(range.end..range.start);
12582            } else {
12583                s.insert_range(range);
12584            }
12585        });
12586    }
12587
12588    pub fn select_next_match_internal(
12589        &mut self,
12590        display_map: &DisplaySnapshot,
12591        replace_newest: bool,
12592        autoscroll: Option<Autoscroll>,
12593        window: &mut Window,
12594        cx: &mut Context<Self>,
12595    ) -> Result<()> {
12596        let buffer = &display_map.buffer_snapshot;
12597        let mut selections = self.selections.all::<usize>(cx);
12598        if let Some(mut select_next_state) = self.select_next_state.take() {
12599            let query = &select_next_state.query;
12600            if !select_next_state.done {
12601                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12602                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12603                let mut next_selected_range = None;
12604
12605                let bytes_after_last_selection =
12606                    buffer.bytes_in_range(last_selection.end..buffer.len());
12607                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12608                let query_matches = query
12609                    .stream_find_iter(bytes_after_last_selection)
12610                    .map(|result| (last_selection.end, result))
12611                    .chain(
12612                        query
12613                            .stream_find_iter(bytes_before_first_selection)
12614                            .map(|result| (0, result)),
12615                    );
12616
12617                for (start_offset, query_match) in query_matches {
12618                    let query_match = query_match.unwrap(); // can only fail due to I/O
12619                    let offset_range =
12620                        start_offset + query_match.start()..start_offset + query_match.end();
12621                    let display_range = offset_range.start.to_display_point(display_map)
12622                        ..offset_range.end.to_display_point(display_map);
12623
12624                    if !select_next_state.wordwise
12625                        || (!movement::is_inside_word(display_map, display_range.start)
12626                            && !movement::is_inside_word(display_map, display_range.end))
12627                    {
12628                        // TODO: This is n^2, because we might check all the selections
12629                        if !selections
12630                            .iter()
12631                            .any(|selection| selection.range().overlaps(&offset_range))
12632                        {
12633                            next_selected_range = Some(offset_range);
12634                            break;
12635                        }
12636                    }
12637                }
12638
12639                if let Some(next_selected_range) = next_selected_range {
12640                    self.select_match_ranges(
12641                        next_selected_range,
12642                        last_selection.reversed,
12643                        replace_newest,
12644                        autoscroll,
12645                        window,
12646                        cx,
12647                    );
12648                } else {
12649                    select_next_state.done = true;
12650                }
12651            }
12652
12653            self.select_next_state = Some(select_next_state);
12654        } else {
12655            let mut only_carets = true;
12656            let mut same_text_selected = true;
12657            let mut selected_text = None;
12658
12659            let mut selections_iter = selections.iter().peekable();
12660            while let Some(selection) = selections_iter.next() {
12661                if selection.start != selection.end {
12662                    only_carets = false;
12663                }
12664
12665                if same_text_selected {
12666                    if selected_text.is_none() {
12667                        selected_text =
12668                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12669                    }
12670
12671                    if let Some(next_selection) = selections_iter.peek() {
12672                        if next_selection.range().len() == selection.range().len() {
12673                            let next_selected_text = buffer
12674                                .text_for_range(next_selection.range())
12675                                .collect::<String>();
12676                            if Some(next_selected_text) != selected_text {
12677                                same_text_selected = false;
12678                                selected_text = None;
12679                            }
12680                        } else {
12681                            same_text_selected = false;
12682                            selected_text = None;
12683                        }
12684                    }
12685                }
12686            }
12687
12688            if only_carets {
12689                for selection in &mut selections {
12690                    let word_range = movement::surrounding_word(
12691                        display_map,
12692                        selection.start.to_display_point(display_map),
12693                    );
12694                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12695                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12696                    selection.goal = SelectionGoal::None;
12697                    selection.reversed = false;
12698                    self.select_match_ranges(
12699                        selection.start..selection.end,
12700                        selection.reversed,
12701                        replace_newest,
12702                        autoscroll,
12703                        window,
12704                        cx,
12705                    );
12706                }
12707
12708                if selections.len() == 1 {
12709                    let selection = selections
12710                        .last()
12711                        .expect("ensured that there's only one selection");
12712                    let query = buffer
12713                        .text_for_range(selection.start..selection.end)
12714                        .collect::<String>();
12715                    let is_empty = query.is_empty();
12716                    let select_state = SelectNextState {
12717                        query: AhoCorasick::new(&[query])?,
12718                        wordwise: true,
12719                        done: is_empty,
12720                    };
12721                    self.select_next_state = Some(select_state);
12722                } else {
12723                    self.select_next_state = None;
12724                }
12725            } else if let Some(selected_text) = selected_text {
12726                self.select_next_state = Some(SelectNextState {
12727                    query: AhoCorasick::new(&[selected_text])?,
12728                    wordwise: false,
12729                    done: false,
12730                });
12731                self.select_next_match_internal(
12732                    display_map,
12733                    replace_newest,
12734                    autoscroll,
12735                    window,
12736                    cx,
12737                )?;
12738            }
12739        }
12740        Ok(())
12741    }
12742
12743    pub fn select_all_matches(
12744        &mut self,
12745        _action: &SelectAllMatches,
12746        window: &mut Window,
12747        cx: &mut Context<Self>,
12748    ) -> Result<()> {
12749        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12750
12751        self.push_to_selection_history();
12752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12753
12754        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12755        let Some(select_next_state) = self.select_next_state.as_mut() else {
12756            return Ok(());
12757        };
12758        if select_next_state.done {
12759            return Ok(());
12760        }
12761
12762        let mut new_selections = Vec::new();
12763
12764        let reversed = self.selections.oldest::<usize>(cx).reversed;
12765        let buffer = &display_map.buffer_snapshot;
12766        let query_matches = select_next_state
12767            .query
12768            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12769
12770        for query_match in query_matches.into_iter() {
12771            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12772            let offset_range = if reversed {
12773                query_match.end()..query_match.start()
12774            } else {
12775                query_match.start()..query_match.end()
12776            };
12777            let display_range = offset_range.start.to_display_point(&display_map)
12778                ..offset_range.end.to_display_point(&display_map);
12779
12780            if !select_next_state.wordwise
12781                || (!movement::is_inside_word(&display_map, display_range.start)
12782                    && !movement::is_inside_word(&display_map, display_range.end))
12783            {
12784                new_selections.push(offset_range.start..offset_range.end);
12785            }
12786        }
12787
12788        select_next_state.done = true;
12789        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12790        self.change_selections(None, window, cx, |selections| {
12791            selections.select_ranges(new_selections)
12792        });
12793
12794        Ok(())
12795    }
12796
12797    pub fn select_next(
12798        &mut self,
12799        action: &SelectNext,
12800        window: &mut Window,
12801        cx: &mut Context<Self>,
12802    ) -> Result<()> {
12803        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12804        self.push_to_selection_history();
12805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12806        self.select_next_match_internal(
12807            &display_map,
12808            action.replace_newest,
12809            Some(Autoscroll::newest()),
12810            window,
12811            cx,
12812        )?;
12813        Ok(())
12814    }
12815
12816    pub fn select_previous(
12817        &mut self,
12818        action: &SelectPrevious,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) -> Result<()> {
12822        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12823        self.push_to_selection_history();
12824        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12825        let buffer = &display_map.buffer_snapshot;
12826        let mut selections = self.selections.all::<usize>(cx);
12827        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12828            let query = &select_prev_state.query;
12829            if !select_prev_state.done {
12830                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12831                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12832                let mut next_selected_range = None;
12833                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12834                let bytes_before_last_selection =
12835                    buffer.reversed_bytes_in_range(0..last_selection.start);
12836                let bytes_after_first_selection =
12837                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12838                let query_matches = query
12839                    .stream_find_iter(bytes_before_last_selection)
12840                    .map(|result| (last_selection.start, result))
12841                    .chain(
12842                        query
12843                            .stream_find_iter(bytes_after_first_selection)
12844                            .map(|result| (buffer.len(), result)),
12845                    );
12846                for (end_offset, query_match) in query_matches {
12847                    let query_match = query_match.unwrap(); // can only fail due to I/O
12848                    let offset_range =
12849                        end_offset - query_match.end()..end_offset - query_match.start();
12850                    let display_range = offset_range.start.to_display_point(&display_map)
12851                        ..offset_range.end.to_display_point(&display_map);
12852
12853                    if !select_prev_state.wordwise
12854                        || (!movement::is_inside_word(&display_map, display_range.start)
12855                            && !movement::is_inside_word(&display_map, display_range.end))
12856                    {
12857                        next_selected_range = Some(offset_range);
12858                        break;
12859                    }
12860                }
12861
12862                if let Some(next_selected_range) = next_selected_range {
12863                    self.select_match_ranges(
12864                        next_selected_range,
12865                        last_selection.reversed,
12866                        action.replace_newest,
12867                        Some(Autoscroll::newest()),
12868                        window,
12869                        cx,
12870                    );
12871                } else {
12872                    select_prev_state.done = true;
12873                }
12874            }
12875
12876            self.select_prev_state = Some(select_prev_state);
12877        } else {
12878            let mut only_carets = true;
12879            let mut same_text_selected = true;
12880            let mut selected_text = None;
12881
12882            let mut selections_iter = selections.iter().peekable();
12883            while let Some(selection) = selections_iter.next() {
12884                if selection.start != selection.end {
12885                    only_carets = false;
12886                }
12887
12888                if same_text_selected {
12889                    if selected_text.is_none() {
12890                        selected_text =
12891                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12892                    }
12893
12894                    if let Some(next_selection) = selections_iter.peek() {
12895                        if next_selection.range().len() == selection.range().len() {
12896                            let next_selected_text = buffer
12897                                .text_for_range(next_selection.range())
12898                                .collect::<String>();
12899                            if Some(next_selected_text) != selected_text {
12900                                same_text_selected = false;
12901                                selected_text = None;
12902                            }
12903                        } else {
12904                            same_text_selected = false;
12905                            selected_text = None;
12906                        }
12907                    }
12908                }
12909            }
12910
12911            if only_carets {
12912                for selection in &mut selections {
12913                    let word_range = movement::surrounding_word(
12914                        &display_map,
12915                        selection.start.to_display_point(&display_map),
12916                    );
12917                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12918                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12919                    selection.goal = SelectionGoal::None;
12920                    selection.reversed = false;
12921                    self.select_match_ranges(
12922                        selection.start..selection.end,
12923                        selection.reversed,
12924                        action.replace_newest,
12925                        Some(Autoscroll::newest()),
12926                        window,
12927                        cx,
12928                    );
12929                }
12930                if selections.len() == 1 {
12931                    let selection = selections
12932                        .last()
12933                        .expect("ensured that there's only one selection");
12934                    let query = buffer
12935                        .text_for_range(selection.start..selection.end)
12936                        .collect::<String>();
12937                    let is_empty = query.is_empty();
12938                    let select_state = SelectNextState {
12939                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12940                        wordwise: true,
12941                        done: is_empty,
12942                    };
12943                    self.select_prev_state = Some(select_state);
12944                } else {
12945                    self.select_prev_state = None;
12946                }
12947            } else if let Some(selected_text) = selected_text {
12948                self.select_prev_state = Some(SelectNextState {
12949                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12950                    wordwise: false,
12951                    done: false,
12952                });
12953                self.select_previous(action, window, cx)?;
12954            }
12955        }
12956        Ok(())
12957    }
12958
12959    pub fn find_next_match(
12960        &mut self,
12961        _: &FindNextMatch,
12962        window: &mut Window,
12963        cx: &mut Context<Self>,
12964    ) -> Result<()> {
12965        let selections = self.selections.disjoint_anchors();
12966        match selections.first() {
12967            Some(first) if selections.len() >= 2 => {
12968                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12969                    s.select_ranges([first.range()]);
12970                });
12971            }
12972            _ => self.select_next(
12973                &SelectNext {
12974                    replace_newest: true,
12975                },
12976                window,
12977                cx,
12978            )?,
12979        }
12980        Ok(())
12981    }
12982
12983    pub fn find_previous_match(
12984        &mut self,
12985        _: &FindPreviousMatch,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) -> Result<()> {
12989        let selections = self.selections.disjoint_anchors();
12990        match selections.last() {
12991            Some(last) if selections.len() >= 2 => {
12992                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12993                    s.select_ranges([last.range()]);
12994                });
12995            }
12996            _ => self.select_previous(
12997                &SelectPrevious {
12998                    replace_newest: true,
12999                },
13000                window,
13001                cx,
13002            )?,
13003        }
13004        Ok(())
13005    }
13006
13007    pub fn toggle_comments(
13008        &mut self,
13009        action: &ToggleComments,
13010        window: &mut Window,
13011        cx: &mut Context<Self>,
13012    ) {
13013        if self.read_only(cx) {
13014            return;
13015        }
13016        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13017        let text_layout_details = &self.text_layout_details(window);
13018        self.transact(window, cx, |this, window, cx| {
13019            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13020            let mut edits = Vec::new();
13021            let mut selection_edit_ranges = Vec::new();
13022            let mut last_toggled_row = None;
13023            let snapshot = this.buffer.read(cx).read(cx);
13024            let empty_str: Arc<str> = Arc::default();
13025            let mut suffixes_inserted = Vec::new();
13026            let ignore_indent = action.ignore_indent;
13027
13028            fn comment_prefix_range(
13029                snapshot: &MultiBufferSnapshot,
13030                row: MultiBufferRow,
13031                comment_prefix: &str,
13032                comment_prefix_whitespace: &str,
13033                ignore_indent: bool,
13034            ) -> Range<Point> {
13035                let indent_size = if ignore_indent {
13036                    0
13037                } else {
13038                    snapshot.indent_size_for_line(row).len
13039                };
13040
13041                let start = Point::new(row.0, indent_size);
13042
13043                let mut line_bytes = snapshot
13044                    .bytes_in_range(start..snapshot.max_point())
13045                    .flatten()
13046                    .copied();
13047
13048                // If this line currently begins with the line comment prefix, then record
13049                // the range containing the prefix.
13050                if line_bytes
13051                    .by_ref()
13052                    .take(comment_prefix.len())
13053                    .eq(comment_prefix.bytes())
13054                {
13055                    // Include any whitespace that matches the comment prefix.
13056                    let matching_whitespace_len = line_bytes
13057                        .zip(comment_prefix_whitespace.bytes())
13058                        .take_while(|(a, b)| a == b)
13059                        .count() as u32;
13060                    let end = Point::new(
13061                        start.row,
13062                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13063                    );
13064                    start..end
13065                } else {
13066                    start..start
13067                }
13068            }
13069
13070            fn comment_suffix_range(
13071                snapshot: &MultiBufferSnapshot,
13072                row: MultiBufferRow,
13073                comment_suffix: &str,
13074                comment_suffix_has_leading_space: bool,
13075            ) -> Range<Point> {
13076                let end = Point::new(row.0, snapshot.line_len(row));
13077                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13078
13079                let mut line_end_bytes = snapshot
13080                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13081                    .flatten()
13082                    .copied();
13083
13084                let leading_space_len = if suffix_start_column > 0
13085                    && line_end_bytes.next() == Some(b' ')
13086                    && comment_suffix_has_leading_space
13087                {
13088                    1
13089                } else {
13090                    0
13091                };
13092
13093                // If this line currently begins with the line comment prefix, then record
13094                // the range containing the prefix.
13095                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13096                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13097                    start..end
13098                } else {
13099                    end..end
13100                }
13101            }
13102
13103            // TODO: Handle selections that cross excerpts
13104            for selection in &mut selections {
13105                let start_column = snapshot
13106                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13107                    .len;
13108                let language = if let Some(language) =
13109                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13110                {
13111                    language
13112                } else {
13113                    continue;
13114                };
13115
13116                selection_edit_ranges.clear();
13117
13118                // If multiple selections contain a given row, avoid processing that
13119                // row more than once.
13120                let mut start_row = MultiBufferRow(selection.start.row);
13121                if last_toggled_row == Some(start_row) {
13122                    start_row = start_row.next_row();
13123                }
13124                let end_row =
13125                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13126                        MultiBufferRow(selection.end.row - 1)
13127                    } else {
13128                        MultiBufferRow(selection.end.row)
13129                    };
13130                last_toggled_row = Some(end_row);
13131
13132                if start_row > end_row {
13133                    continue;
13134                }
13135
13136                // If the language has line comments, toggle those.
13137                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13138
13139                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13140                if ignore_indent {
13141                    full_comment_prefixes = full_comment_prefixes
13142                        .into_iter()
13143                        .map(|s| Arc::from(s.trim_end()))
13144                        .collect();
13145                }
13146
13147                if !full_comment_prefixes.is_empty() {
13148                    let first_prefix = full_comment_prefixes
13149                        .first()
13150                        .expect("prefixes is non-empty");
13151                    let prefix_trimmed_lengths = full_comment_prefixes
13152                        .iter()
13153                        .map(|p| p.trim_end_matches(' ').len())
13154                        .collect::<SmallVec<[usize; 4]>>();
13155
13156                    let mut all_selection_lines_are_comments = true;
13157
13158                    for row in start_row.0..=end_row.0 {
13159                        let row = MultiBufferRow(row);
13160                        if start_row < end_row && snapshot.is_line_blank(row) {
13161                            continue;
13162                        }
13163
13164                        let prefix_range = full_comment_prefixes
13165                            .iter()
13166                            .zip(prefix_trimmed_lengths.iter().copied())
13167                            .map(|(prefix, trimmed_prefix_len)| {
13168                                comment_prefix_range(
13169                                    snapshot.deref(),
13170                                    row,
13171                                    &prefix[..trimmed_prefix_len],
13172                                    &prefix[trimmed_prefix_len..],
13173                                    ignore_indent,
13174                                )
13175                            })
13176                            .max_by_key(|range| range.end.column - range.start.column)
13177                            .expect("prefixes is non-empty");
13178
13179                        if prefix_range.is_empty() {
13180                            all_selection_lines_are_comments = false;
13181                        }
13182
13183                        selection_edit_ranges.push(prefix_range);
13184                    }
13185
13186                    if all_selection_lines_are_comments {
13187                        edits.extend(
13188                            selection_edit_ranges
13189                                .iter()
13190                                .cloned()
13191                                .map(|range| (range, empty_str.clone())),
13192                        );
13193                    } else {
13194                        let min_column = selection_edit_ranges
13195                            .iter()
13196                            .map(|range| range.start.column)
13197                            .min()
13198                            .unwrap_or(0);
13199                        edits.extend(selection_edit_ranges.iter().map(|range| {
13200                            let position = Point::new(range.start.row, min_column);
13201                            (position..position, first_prefix.clone())
13202                        }));
13203                    }
13204                } else if let Some((full_comment_prefix, comment_suffix)) =
13205                    language.block_comment_delimiters()
13206                {
13207                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13208                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13209                    let prefix_range = comment_prefix_range(
13210                        snapshot.deref(),
13211                        start_row,
13212                        comment_prefix,
13213                        comment_prefix_whitespace,
13214                        ignore_indent,
13215                    );
13216                    let suffix_range = comment_suffix_range(
13217                        snapshot.deref(),
13218                        end_row,
13219                        comment_suffix.trim_start_matches(' '),
13220                        comment_suffix.starts_with(' '),
13221                    );
13222
13223                    if prefix_range.is_empty() || suffix_range.is_empty() {
13224                        edits.push((
13225                            prefix_range.start..prefix_range.start,
13226                            full_comment_prefix.clone(),
13227                        ));
13228                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13229                        suffixes_inserted.push((end_row, comment_suffix.len()));
13230                    } else {
13231                        edits.push((prefix_range, empty_str.clone()));
13232                        edits.push((suffix_range, empty_str.clone()));
13233                    }
13234                } else {
13235                    continue;
13236                }
13237            }
13238
13239            drop(snapshot);
13240            this.buffer.update(cx, |buffer, cx| {
13241                buffer.edit(edits, None, cx);
13242            });
13243
13244            // Adjust selections so that they end before any comment suffixes that
13245            // were inserted.
13246            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13247            let mut selections = this.selections.all::<Point>(cx);
13248            let snapshot = this.buffer.read(cx).read(cx);
13249            for selection in &mut selections {
13250                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13251                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13252                        Ordering::Less => {
13253                            suffixes_inserted.next();
13254                            continue;
13255                        }
13256                        Ordering::Greater => break,
13257                        Ordering::Equal => {
13258                            if selection.end.column == snapshot.line_len(row) {
13259                                if selection.is_empty() {
13260                                    selection.start.column -= suffix_len as u32;
13261                                }
13262                                selection.end.column -= suffix_len as u32;
13263                            }
13264                            break;
13265                        }
13266                    }
13267                }
13268            }
13269
13270            drop(snapshot);
13271            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13272                s.select(selections)
13273            });
13274
13275            let selections = this.selections.all::<Point>(cx);
13276            let selections_on_single_row = selections.windows(2).all(|selections| {
13277                selections[0].start.row == selections[1].start.row
13278                    && selections[0].end.row == selections[1].end.row
13279                    && selections[0].start.row == selections[0].end.row
13280            });
13281            let selections_selecting = selections
13282                .iter()
13283                .any(|selection| selection.start != selection.end);
13284            let advance_downwards = action.advance_downwards
13285                && selections_on_single_row
13286                && !selections_selecting
13287                && !matches!(this.mode, EditorMode::SingleLine { .. });
13288
13289            if advance_downwards {
13290                let snapshot = this.buffer.read(cx).snapshot(cx);
13291
13292                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13293                    s.move_cursors_with(|display_snapshot, display_point, _| {
13294                        let mut point = display_point.to_point(display_snapshot);
13295                        point.row += 1;
13296                        point = snapshot.clip_point(point, Bias::Left);
13297                        let display_point = point.to_display_point(display_snapshot);
13298                        let goal = SelectionGoal::HorizontalPosition(
13299                            display_snapshot
13300                                .x_for_display_point(display_point, text_layout_details)
13301                                .into(),
13302                        );
13303                        (display_point, goal)
13304                    })
13305                });
13306            }
13307        });
13308    }
13309
13310    pub fn select_enclosing_symbol(
13311        &mut self,
13312        _: &SelectEnclosingSymbol,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13317
13318        let buffer = self.buffer.read(cx).snapshot(cx);
13319        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13320
13321        fn update_selection(
13322            selection: &Selection<usize>,
13323            buffer_snap: &MultiBufferSnapshot,
13324        ) -> Option<Selection<usize>> {
13325            let cursor = selection.head();
13326            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13327            for symbol in symbols.iter().rev() {
13328                let start = symbol.range.start.to_offset(buffer_snap);
13329                let end = symbol.range.end.to_offset(buffer_snap);
13330                let new_range = start..end;
13331                if start < selection.start || end > selection.end {
13332                    return Some(Selection {
13333                        id: selection.id,
13334                        start: new_range.start,
13335                        end: new_range.end,
13336                        goal: SelectionGoal::None,
13337                        reversed: selection.reversed,
13338                    });
13339                }
13340            }
13341            None
13342        }
13343
13344        let mut selected_larger_symbol = false;
13345        let new_selections = old_selections
13346            .iter()
13347            .map(|selection| match update_selection(selection, &buffer) {
13348                Some(new_selection) => {
13349                    if new_selection.range() != selection.range() {
13350                        selected_larger_symbol = true;
13351                    }
13352                    new_selection
13353                }
13354                None => selection.clone(),
13355            })
13356            .collect::<Vec<_>>();
13357
13358        if selected_larger_symbol {
13359            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13360                s.select(new_selections);
13361            });
13362        }
13363    }
13364
13365    pub fn select_larger_syntax_node(
13366        &mut self,
13367        _: &SelectLargerSyntaxNode,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        let Some(visible_row_count) = self.visible_row_count() else {
13372            return;
13373        };
13374        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13375        if old_selections.is_empty() {
13376            return;
13377        }
13378
13379        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13380
13381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13382        let buffer = self.buffer.read(cx).snapshot(cx);
13383
13384        let mut selected_larger_node = false;
13385        let mut new_selections = old_selections
13386            .iter()
13387            .map(|selection| {
13388                let old_range = selection.start..selection.end;
13389
13390                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13391                    // manually select word at selection
13392                    if ["string_content", "inline"].contains(&node.kind()) {
13393                        let word_range = {
13394                            let display_point = buffer
13395                                .offset_to_point(old_range.start)
13396                                .to_display_point(&display_map);
13397                            let Range { start, end } =
13398                                movement::surrounding_word(&display_map, display_point);
13399                            start.to_point(&display_map).to_offset(&buffer)
13400                                ..end.to_point(&display_map).to_offset(&buffer)
13401                        };
13402                        // ignore if word is already selected
13403                        if !word_range.is_empty() && old_range != word_range {
13404                            let last_word_range = {
13405                                let display_point = buffer
13406                                    .offset_to_point(old_range.end)
13407                                    .to_display_point(&display_map);
13408                                let Range { start, end } =
13409                                    movement::surrounding_word(&display_map, display_point);
13410                                start.to_point(&display_map).to_offset(&buffer)
13411                                    ..end.to_point(&display_map).to_offset(&buffer)
13412                            };
13413                            // only select word if start and end point belongs to same word
13414                            if word_range == last_word_range {
13415                                selected_larger_node = true;
13416                                return Selection {
13417                                    id: selection.id,
13418                                    start: word_range.start,
13419                                    end: word_range.end,
13420                                    goal: SelectionGoal::None,
13421                                    reversed: selection.reversed,
13422                                };
13423                            }
13424                        }
13425                    }
13426                }
13427
13428                let mut new_range = old_range.clone();
13429                while let Some((_node, containing_range)) =
13430                    buffer.syntax_ancestor(new_range.clone())
13431                {
13432                    new_range = match containing_range {
13433                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13434                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13435                    };
13436                    if !display_map.intersects_fold(new_range.start)
13437                        && !display_map.intersects_fold(new_range.end)
13438                    {
13439                        break;
13440                    }
13441                }
13442
13443                selected_larger_node |= new_range != old_range;
13444                Selection {
13445                    id: selection.id,
13446                    start: new_range.start,
13447                    end: new_range.end,
13448                    goal: SelectionGoal::None,
13449                    reversed: selection.reversed,
13450                }
13451            })
13452            .collect::<Vec<_>>();
13453
13454        if !selected_larger_node {
13455            return; // don't put this call in the history
13456        }
13457
13458        // scroll based on transformation done to the last selection created by the user
13459        let (last_old, last_new) = old_selections
13460            .last()
13461            .zip(new_selections.last().cloned())
13462            .expect("old_selections isn't empty");
13463
13464        // revert selection
13465        let is_selection_reversed = {
13466            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13467            new_selections.last_mut().expect("checked above").reversed =
13468                should_newest_selection_be_reversed;
13469            should_newest_selection_be_reversed
13470        };
13471
13472        if selected_larger_node {
13473            self.select_syntax_node_history.disable_clearing = true;
13474            self.change_selections(None, window, cx, |s| {
13475                s.select(new_selections.clone());
13476            });
13477            self.select_syntax_node_history.disable_clearing = false;
13478        }
13479
13480        let start_row = last_new.start.to_display_point(&display_map).row().0;
13481        let end_row = last_new.end.to_display_point(&display_map).row().0;
13482        let selection_height = end_row - start_row + 1;
13483        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13484
13485        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13486        let scroll_behavior = if fits_on_the_screen {
13487            self.request_autoscroll(Autoscroll::fit(), cx);
13488            SelectSyntaxNodeScrollBehavior::FitSelection
13489        } else if is_selection_reversed {
13490            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13491            SelectSyntaxNodeScrollBehavior::CursorTop
13492        } else {
13493            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13494            SelectSyntaxNodeScrollBehavior::CursorBottom
13495        };
13496
13497        self.select_syntax_node_history.push((
13498            old_selections,
13499            scroll_behavior,
13500            is_selection_reversed,
13501        ));
13502    }
13503
13504    pub fn select_smaller_syntax_node(
13505        &mut self,
13506        _: &SelectSmallerSyntaxNode,
13507        window: &mut Window,
13508        cx: &mut Context<Self>,
13509    ) {
13510        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13511
13512        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13513            self.select_syntax_node_history.pop()
13514        {
13515            if let Some(selection) = selections.last_mut() {
13516                selection.reversed = is_selection_reversed;
13517            }
13518
13519            self.select_syntax_node_history.disable_clearing = true;
13520            self.change_selections(None, window, cx, |s| {
13521                s.select(selections.to_vec());
13522            });
13523            self.select_syntax_node_history.disable_clearing = false;
13524
13525            match scroll_behavior {
13526                SelectSyntaxNodeScrollBehavior::CursorTop => {
13527                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13528                }
13529                SelectSyntaxNodeScrollBehavior::FitSelection => {
13530                    self.request_autoscroll(Autoscroll::fit(), cx);
13531                }
13532                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13533                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13534                }
13535            }
13536        }
13537    }
13538
13539    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13540        if !EditorSettings::get_global(cx).gutter.runnables {
13541            self.clear_tasks();
13542            return Task::ready(());
13543        }
13544        let project = self.project.as_ref().map(Entity::downgrade);
13545        let task_sources = self.lsp_task_sources(cx);
13546        cx.spawn_in(window, async move |editor, cx| {
13547            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13548            let Some(project) = project.and_then(|p| p.upgrade()) else {
13549                return;
13550            };
13551            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13552                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13553            }) else {
13554                return;
13555            };
13556
13557            let hide_runnables = project
13558                .update(cx, |project, cx| {
13559                    // Do not display any test indicators in non-dev server remote projects.
13560                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13561                })
13562                .unwrap_or(true);
13563            if hide_runnables {
13564                return;
13565            }
13566            let new_rows =
13567                cx.background_spawn({
13568                    let snapshot = display_snapshot.clone();
13569                    async move {
13570                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13571                    }
13572                })
13573                    .await;
13574            let Ok(lsp_tasks) =
13575                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13576            else {
13577                return;
13578            };
13579            let lsp_tasks = lsp_tasks.await;
13580
13581            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13582                lsp_tasks
13583                    .into_iter()
13584                    .flat_map(|(kind, tasks)| {
13585                        tasks.into_iter().filter_map(move |(location, task)| {
13586                            Some((kind.clone(), location?, task))
13587                        })
13588                    })
13589                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13590                        let buffer = location.target.buffer;
13591                        let buffer_snapshot = buffer.read(cx).snapshot();
13592                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13593                            |(excerpt_id, snapshot, _)| {
13594                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13595                                    display_snapshot
13596                                        .buffer_snapshot
13597                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13598                                } else {
13599                                    None
13600                                }
13601                            },
13602                        );
13603                        if let Some(offset) = offset {
13604                            let task_buffer_range =
13605                                location.target.range.to_point(&buffer_snapshot);
13606                            let context_buffer_range =
13607                                task_buffer_range.to_offset(&buffer_snapshot);
13608                            let context_range = BufferOffset(context_buffer_range.start)
13609                                ..BufferOffset(context_buffer_range.end);
13610
13611                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13612                                .or_insert_with(|| RunnableTasks {
13613                                    templates: Vec::new(),
13614                                    offset,
13615                                    column: task_buffer_range.start.column,
13616                                    extra_variables: HashMap::default(),
13617                                    context_range,
13618                                })
13619                                .templates
13620                                .push((kind, task.original_task().clone()));
13621                        }
13622
13623                        acc
13624                    })
13625            }) else {
13626                return;
13627            };
13628
13629            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13630            editor
13631                .update(cx, |editor, _| {
13632                    editor.clear_tasks();
13633                    for (key, mut value) in rows {
13634                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13635                            value.templates.extend(lsp_tasks.templates);
13636                        }
13637
13638                        editor.insert_tasks(key, value);
13639                    }
13640                    for (key, value) in lsp_tasks_by_rows {
13641                        editor.insert_tasks(key, value);
13642                    }
13643                })
13644                .ok();
13645        })
13646    }
13647    fn fetch_runnable_ranges(
13648        snapshot: &DisplaySnapshot,
13649        range: Range<Anchor>,
13650    ) -> Vec<language::RunnableRange> {
13651        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13652    }
13653
13654    fn runnable_rows(
13655        project: Entity<Project>,
13656        snapshot: DisplaySnapshot,
13657        runnable_ranges: Vec<RunnableRange>,
13658        mut cx: AsyncWindowContext,
13659    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13660        runnable_ranges
13661            .into_iter()
13662            .filter_map(|mut runnable| {
13663                let tasks = cx
13664                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13665                    .ok()?;
13666                if tasks.is_empty() {
13667                    return None;
13668                }
13669
13670                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13671
13672                let row = snapshot
13673                    .buffer_snapshot
13674                    .buffer_line_for_row(MultiBufferRow(point.row))?
13675                    .1
13676                    .start
13677                    .row;
13678
13679                let context_range =
13680                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13681                Some((
13682                    (runnable.buffer_id, row),
13683                    RunnableTasks {
13684                        templates: tasks,
13685                        offset: snapshot
13686                            .buffer_snapshot
13687                            .anchor_before(runnable.run_range.start),
13688                        context_range,
13689                        column: point.column,
13690                        extra_variables: runnable.extra_captures,
13691                    },
13692                ))
13693            })
13694            .collect()
13695    }
13696
13697    fn templates_with_tags(
13698        project: &Entity<Project>,
13699        runnable: &mut Runnable,
13700        cx: &mut App,
13701    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13702        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13703            let (worktree_id, file) = project
13704                .buffer_for_id(runnable.buffer, cx)
13705                .and_then(|buffer| buffer.read(cx).file())
13706                .map(|file| (file.worktree_id(cx), file.clone()))
13707                .unzip();
13708
13709            (
13710                project.task_store().read(cx).task_inventory().cloned(),
13711                worktree_id,
13712                file,
13713            )
13714        });
13715
13716        let mut templates_with_tags = mem::take(&mut runnable.tags)
13717            .into_iter()
13718            .flat_map(|RunnableTag(tag)| {
13719                inventory
13720                    .as_ref()
13721                    .into_iter()
13722                    .flat_map(|inventory| {
13723                        inventory.read(cx).list_tasks(
13724                            file.clone(),
13725                            Some(runnable.language.clone()),
13726                            worktree_id,
13727                            cx,
13728                        )
13729                    })
13730                    .filter(move |(_, template)| {
13731                        template.tags.iter().any(|source_tag| source_tag == &tag)
13732                    })
13733            })
13734            .sorted_by_key(|(kind, _)| kind.to_owned())
13735            .collect::<Vec<_>>();
13736        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13737            // Strongest source wins; if we have worktree tag binding, prefer that to
13738            // global and language bindings;
13739            // if we have a global binding, prefer that to language binding.
13740            let first_mismatch = templates_with_tags
13741                .iter()
13742                .position(|(tag_source, _)| tag_source != leading_tag_source);
13743            if let Some(index) = first_mismatch {
13744                templates_with_tags.truncate(index);
13745            }
13746        }
13747
13748        templates_with_tags
13749    }
13750
13751    pub fn move_to_enclosing_bracket(
13752        &mut self,
13753        _: &MoveToEnclosingBracket,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13758        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13759            s.move_offsets_with(|snapshot, selection| {
13760                let Some(enclosing_bracket_ranges) =
13761                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13762                else {
13763                    return;
13764                };
13765
13766                let mut best_length = usize::MAX;
13767                let mut best_inside = false;
13768                let mut best_in_bracket_range = false;
13769                let mut best_destination = None;
13770                for (open, close) in enclosing_bracket_ranges {
13771                    let close = close.to_inclusive();
13772                    let length = close.end() - open.start;
13773                    let inside = selection.start >= open.end && selection.end <= *close.start();
13774                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13775                        || close.contains(&selection.head());
13776
13777                    // If best is next to a bracket and current isn't, skip
13778                    if !in_bracket_range && best_in_bracket_range {
13779                        continue;
13780                    }
13781
13782                    // Prefer smaller lengths unless best is inside and current isn't
13783                    if length > best_length && (best_inside || !inside) {
13784                        continue;
13785                    }
13786
13787                    best_length = length;
13788                    best_inside = inside;
13789                    best_in_bracket_range = in_bracket_range;
13790                    best_destination = Some(
13791                        if close.contains(&selection.start) && close.contains(&selection.end) {
13792                            if inside { open.end } else { open.start }
13793                        } else if inside {
13794                            *close.start()
13795                        } else {
13796                            *close.end()
13797                        },
13798                    );
13799                }
13800
13801                if let Some(destination) = best_destination {
13802                    selection.collapse_to(destination, SelectionGoal::None);
13803                }
13804            })
13805        });
13806    }
13807
13808    pub fn undo_selection(
13809        &mut self,
13810        _: &UndoSelection,
13811        window: &mut Window,
13812        cx: &mut Context<Self>,
13813    ) {
13814        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13815        self.end_selection(window, cx);
13816        self.selection_history.mode = SelectionHistoryMode::Undoing;
13817        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13818            self.change_selections(None, window, cx, |s| {
13819                s.select_anchors(entry.selections.to_vec())
13820            });
13821            self.select_next_state = entry.select_next_state;
13822            self.select_prev_state = entry.select_prev_state;
13823            self.add_selections_state = entry.add_selections_state;
13824            self.request_autoscroll(Autoscroll::newest(), cx);
13825        }
13826        self.selection_history.mode = SelectionHistoryMode::Normal;
13827    }
13828
13829    pub fn redo_selection(
13830        &mut self,
13831        _: &RedoSelection,
13832        window: &mut Window,
13833        cx: &mut Context<Self>,
13834    ) {
13835        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13836        self.end_selection(window, cx);
13837        self.selection_history.mode = SelectionHistoryMode::Redoing;
13838        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13839            self.change_selections(None, window, cx, |s| {
13840                s.select_anchors(entry.selections.to_vec())
13841            });
13842            self.select_next_state = entry.select_next_state;
13843            self.select_prev_state = entry.select_prev_state;
13844            self.add_selections_state = entry.add_selections_state;
13845            self.request_autoscroll(Autoscroll::newest(), cx);
13846        }
13847        self.selection_history.mode = SelectionHistoryMode::Normal;
13848    }
13849
13850    pub fn expand_excerpts(
13851        &mut self,
13852        action: &ExpandExcerpts,
13853        _: &mut Window,
13854        cx: &mut Context<Self>,
13855    ) {
13856        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13857    }
13858
13859    pub fn expand_excerpts_down(
13860        &mut self,
13861        action: &ExpandExcerptsDown,
13862        _: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) {
13865        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13866    }
13867
13868    pub fn expand_excerpts_up(
13869        &mut self,
13870        action: &ExpandExcerptsUp,
13871        _: &mut Window,
13872        cx: &mut Context<Self>,
13873    ) {
13874        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13875    }
13876
13877    pub fn expand_excerpts_for_direction(
13878        &mut self,
13879        lines: u32,
13880        direction: ExpandExcerptDirection,
13881
13882        cx: &mut Context<Self>,
13883    ) {
13884        let selections = self.selections.disjoint_anchors();
13885
13886        let lines = if lines == 0 {
13887            EditorSettings::get_global(cx).expand_excerpt_lines
13888        } else {
13889            lines
13890        };
13891
13892        self.buffer.update(cx, |buffer, cx| {
13893            let snapshot = buffer.snapshot(cx);
13894            let mut excerpt_ids = selections
13895                .iter()
13896                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13897                .collect::<Vec<_>>();
13898            excerpt_ids.sort();
13899            excerpt_ids.dedup();
13900            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13901        })
13902    }
13903
13904    pub fn expand_excerpt(
13905        &mut self,
13906        excerpt: ExcerptId,
13907        direction: ExpandExcerptDirection,
13908        window: &mut Window,
13909        cx: &mut Context<Self>,
13910    ) {
13911        let current_scroll_position = self.scroll_position(cx);
13912        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13913        let mut should_scroll_up = false;
13914
13915        if direction == ExpandExcerptDirection::Down {
13916            let multi_buffer = self.buffer.read(cx);
13917            let snapshot = multi_buffer.snapshot(cx);
13918            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13919                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13920                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13921                        let buffer_snapshot = buffer.read(cx).snapshot();
13922                        let excerpt_end_row =
13923                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13924                        let last_row = buffer_snapshot.max_point().row;
13925                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13926                        should_scroll_up = lines_below >= lines_to_expand;
13927                    }
13928                }
13929            }
13930        }
13931
13932        self.buffer.update(cx, |buffer, cx| {
13933            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13934        });
13935
13936        if should_scroll_up {
13937            let new_scroll_position =
13938                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13939            self.set_scroll_position(new_scroll_position, window, cx);
13940        }
13941    }
13942
13943    pub fn go_to_singleton_buffer_point(
13944        &mut self,
13945        point: Point,
13946        window: &mut Window,
13947        cx: &mut Context<Self>,
13948    ) {
13949        self.go_to_singleton_buffer_range(point..point, window, cx);
13950    }
13951
13952    pub fn go_to_singleton_buffer_range(
13953        &mut self,
13954        range: Range<Point>,
13955        window: &mut Window,
13956        cx: &mut Context<Self>,
13957    ) {
13958        let multibuffer = self.buffer().read(cx);
13959        let Some(buffer) = multibuffer.as_singleton() else {
13960            return;
13961        };
13962        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13963            return;
13964        };
13965        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13966            return;
13967        };
13968        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13969            s.select_anchor_ranges([start..end])
13970        });
13971    }
13972
13973    pub fn go_to_diagnostic(
13974        &mut self,
13975        _: &GoToDiagnostic,
13976        window: &mut Window,
13977        cx: &mut Context<Self>,
13978    ) {
13979        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13980        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13981    }
13982
13983    pub fn go_to_prev_diagnostic(
13984        &mut self,
13985        _: &GoToPreviousDiagnostic,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13990        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13991    }
13992
13993    pub fn go_to_diagnostic_impl(
13994        &mut self,
13995        direction: Direction,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) {
13999        let buffer = self.buffer.read(cx).snapshot(cx);
14000        let selection = self.selections.newest::<usize>(cx);
14001
14002        let mut active_group_id = None;
14003        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14004            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14005                active_group_id = Some(active_group.group_id);
14006            }
14007        }
14008
14009        fn filtered(
14010            snapshot: EditorSnapshot,
14011            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14012        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14013            diagnostics
14014                .filter(|entry| entry.range.start != entry.range.end)
14015                .filter(|entry| !entry.diagnostic.is_unnecessary)
14016                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14017        }
14018
14019        let snapshot = self.snapshot(window, cx);
14020        let before = filtered(
14021            snapshot.clone(),
14022            buffer
14023                .diagnostics_in_range(0..selection.start)
14024                .filter(|entry| entry.range.start <= selection.start),
14025        );
14026        let after = filtered(
14027            snapshot,
14028            buffer
14029                .diagnostics_in_range(selection.start..buffer.len())
14030                .filter(|entry| entry.range.start >= selection.start),
14031        );
14032
14033        let mut found: Option<DiagnosticEntry<usize>> = None;
14034        if direction == Direction::Prev {
14035            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14036            {
14037                for diagnostic in prev_diagnostics.into_iter().rev() {
14038                    if diagnostic.range.start != selection.start
14039                        || active_group_id
14040                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14041                    {
14042                        found = Some(diagnostic);
14043                        break 'outer;
14044                    }
14045                }
14046            }
14047        } else {
14048            for diagnostic in after.chain(before) {
14049                if diagnostic.range.start != selection.start
14050                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14051                {
14052                    found = Some(diagnostic);
14053                    break;
14054                }
14055            }
14056        }
14057        let Some(next_diagnostic) = found else {
14058            return;
14059        };
14060
14061        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14062            return;
14063        };
14064        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14065            s.select_ranges(vec![
14066                next_diagnostic.range.start..next_diagnostic.range.start,
14067            ])
14068        });
14069        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14070        self.refresh_inline_completion(false, true, window, cx);
14071    }
14072
14073    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14074        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14075        let snapshot = self.snapshot(window, cx);
14076        let selection = self.selections.newest::<Point>(cx);
14077        self.go_to_hunk_before_or_after_position(
14078            &snapshot,
14079            selection.head(),
14080            Direction::Next,
14081            window,
14082            cx,
14083        );
14084    }
14085
14086    pub fn go_to_hunk_before_or_after_position(
14087        &mut self,
14088        snapshot: &EditorSnapshot,
14089        position: Point,
14090        direction: Direction,
14091        window: &mut Window,
14092        cx: &mut Context<Editor>,
14093    ) {
14094        let row = if direction == Direction::Next {
14095            self.hunk_after_position(snapshot, position)
14096                .map(|hunk| hunk.row_range.start)
14097        } else {
14098            self.hunk_before_position(snapshot, position)
14099        };
14100
14101        if let Some(row) = row {
14102            let destination = Point::new(row.0, 0);
14103            let autoscroll = Autoscroll::center();
14104
14105            self.unfold_ranges(&[destination..destination], false, false, cx);
14106            self.change_selections(Some(autoscroll), window, cx, |s| {
14107                s.select_ranges([destination..destination]);
14108            });
14109        }
14110    }
14111
14112    fn hunk_after_position(
14113        &mut self,
14114        snapshot: &EditorSnapshot,
14115        position: Point,
14116    ) -> Option<MultiBufferDiffHunk> {
14117        snapshot
14118            .buffer_snapshot
14119            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14120            .find(|hunk| hunk.row_range.start.0 > position.row)
14121            .or_else(|| {
14122                snapshot
14123                    .buffer_snapshot
14124                    .diff_hunks_in_range(Point::zero()..position)
14125                    .find(|hunk| hunk.row_range.end.0 < position.row)
14126            })
14127    }
14128
14129    fn go_to_prev_hunk(
14130        &mut self,
14131        _: &GoToPreviousHunk,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14136        let snapshot = self.snapshot(window, cx);
14137        let selection = self.selections.newest::<Point>(cx);
14138        self.go_to_hunk_before_or_after_position(
14139            &snapshot,
14140            selection.head(),
14141            Direction::Prev,
14142            window,
14143            cx,
14144        );
14145    }
14146
14147    fn hunk_before_position(
14148        &mut self,
14149        snapshot: &EditorSnapshot,
14150        position: Point,
14151    ) -> Option<MultiBufferRow> {
14152        snapshot
14153            .buffer_snapshot
14154            .diff_hunk_before(position)
14155            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14156    }
14157
14158    fn go_to_next_change(
14159        &mut self,
14160        _: &GoToNextChange,
14161        window: &mut Window,
14162        cx: &mut Context<Self>,
14163    ) {
14164        if let Some(selections) = self
14165            .change_list
14166            .next_change(1, Direction::Next)
14167            .map(|s| s.to_vec())
14168        {
14169            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14170                let map = s.display_map();
14171                s.select_display_ranges(selections.iter().map(|a| {
14172                    let point = a.to_display_point(&map);
14173                    point..point
14174                }))
14175            })
14176        }
14177    }
14178
14179    fn go_to_previous_change(
14180        &mut self,
14181        _: &GoToPreviousChange,
14182        window: &mut Window,
14183        cx: &mut Context<Self>,
14184    ) {
14185        if let Some(selections) = self
14186            .change_list
14187            .next_change(1, Direction::Prev)
14188            .map(|s| s.to_vec())
14189        {
14190            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14191                let map = s.display_map();
14192                s.select_display_ranges(selections.iter().map(|a| {
14193                    let point = a.to_display_point(&map);
14194                    point..point
14195                }))
14196            })
14197        }
14198    }
14199
14200    fn go_to_line<T: 'static>(
14201        &mut self,
14202        position: Anchor,
14203        highlight_color: Option<Hsla>,
14204        window: &mut Window,
14205        cx: &mut Context<Self>,
14206    ) {
14207        let snapshot = self.snapshot(window, cx).display_snapshot;
14208        let position = position.to_point(&snapshot.buffer_snapshot);
14209        let start = snapshot
14210            .buffer_snapshot
14211            .clip_point(Point::new(position.row, 0), Bias::Left);
14212        let end = start + Point::new(1, 0);
14213        let start = snapshot.buffer_snapshot.anchor_before(start);
14214        let end = snapshot.buffer_snapshot.anchor_before(end);
14215
14216        self.highlight_rows::<T>(
14217            start..end,
14218            highlight_color
14219                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14220            Default::default(),
14221            cx,
14222        );
14223
14224        if self.buffer.read(cx).is_singleton() {
14225            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14226        }
14227    }
14228
14229    pub fn go_to_definition(
14230        &mut self,
14231        _: &GoToDefinition,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) -> Task<Result<Navigated>> {
14235        let definition =
14236            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14237        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14238        cx.spawn_in(window, async move |editor, cx| {
14239            if definition.await? == Navigated::Yes {
14240                return Ok(Navigated::Yes);
14241            }
14242            match fallback_strategy {
14243                GoToDefinitionFallback::None => Ok(Navigated::No),
14244                GoToDefinitionFallback::FindAllReferences => {
14245                    match editor.update_in(cx, |editor, window, cx| {
14246                        editor.find_all_references(&FindAllReferences, window, cx)
14247                    })? {
14248                        Some(references) => references.await,
14249                        None => Ok(Navigated::No),
14250                    }
14251                }
14252            }
14253        })
14254    }
14255
14256    pub fn go_to_declaration(
14257        &mut self,
14258        _: &GoToDeclaration,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) -> Task<Result<Navigated>> {
14262        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14263    }
14264
14265    pub fn go_to_declaration_split(
14266        &mut self,
14267        _: &GoToDeclaration,
14268        window: &mut Window,
14269        cx: &mut Context<Self>,
14270    ) -> Task<Result<Navigated>> {
14271        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14272    }
14273
14274    pub fn go_to_implementation(
14275        &mut self,
14276        _: &GoToImplementation,
14277        window: &mut Window,
14278        cx: &mut Context<Self>,
14279    ) -> Task<Result<Navigated>> {
14280        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14281    }
14282
14283    pub fn go_to_implementation_split(
14284        &mut self,
14285        _: &GoToImplementationSplit,
14286        window: &mut Window,
14287        cx: &mut Context<Self>,
14288    ) -> Task<Result<Navigated>> {
14289        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14290    }
14291
14292    pub fn go_to_type_definition(
14293        &mut self,
14294        _: &GoToTypeDefinition,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) -> Task<Result<Navigated>> {
14298        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14299    }
14300
14301    pub fn go_to_definition_split(
14302        &mut self,
14303        _: &GoToDefinitionSplit,
14304        window: &mut Window,
14305        cx: &mut Context<Self>,
14306    ) -> Task<Result<Navigated>> {
14307        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14308    }
14309
14310    pub fn go_to_type_definition_split(
14311        &mut self,
14312        _: &GoToTypeDefinitionSplit,
14313        window: &mut Window,
14314        cx: &mut Context<Self>,
14315    ) -> Task<Result<Navigated>> {
14316        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14317    }
14318
14319    fn go_to_definition_of_kind(
14320        &mut self,
14321        kind: GotoDefinitionKind,
14322        split: bool,
14323        window: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) -> Task<Result<Navigated>> {
14326        let Some(provider) = self.semantics_provider.clone() else {
14327            return Task::ready(Ok(Navigated::No));
14328        };
14329        let head = self.selections.newest::<usize>(cx).head();
14330        let buffer = self.buffer.read(cx);
14331        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14332            text_anchor
14333        } else {
14334            return Task::ready(Ok(Navigated::No));
14335        };
14336
14337        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14338            return Task::ready(Ok(Navigated::No));
14339        };
14340
14341        cx.spawn_in(window, async move |editor, cx| {
14342            let definitions = definitions.await?;
14343            let navigated = editor
14344                .update_in(cx, |editor, window, cx| {
14345                    editor.navigate_to_hover_links(
14346                        Some(kind),
14347                        definitions
14348                            .into_iter()
14349                            .filter(|location| {
14350                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14351                            })
14352                            .map(HoverLink::Text)
14353                            .collect::<Vec<_>>(),
14354                        split,
14355                        window,
14356                        cx,
14357                    )
14358                })?
14359                .await?;
14360            anyhow::Ok(navigated)
14361        })
14362    }
14363
14364    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14365        let selection = self.selections.newest_anchor();
14366        let head = selection.head();
14367        let tail = selection.tail();
14368
14369        let Some((buffer, start_position)) =
14370            self.buffer.read(cx).text_anchor_for_position(head, cx)
14371        else {
14372            return;
14373        };
14374
14375        let end_position = if head != tail {
14376            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14377                return;
14378            };
14379            Some(pos)
14380        } else {
14381            None
14382        };
14383
14384        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14385            let url = if let Some(end_pos) = end_position {
14386                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14387            } else {
14388                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14389            };
14390
14391            if let Some(url) = url {
14392                editor.update(cx, |_, cx| {
14393                    cx.open_url(&url);
14394                })
14395            } else {
14396                Ok(())
14397            }
14398        });
14399
14400        url_finder.detach();
14401    }
14402
14403    pub fn open_selected_filename(
14404        &mut self,
14405        _: &OpenSelectedFilename,
14406        window: &mut Window,
14407        cx: &mut Context<Self>,
14408    ) {
14409        let Some(workspace) = self.workspace() else {
14410            return;
14411        };
14412
14413        let position = self.selections.newest_anchor().head();
14414
14415        let Some((buffer, buffer_position)) =
14416            self.buffer.read(cx).text_anchor_for_position(position, cx)
14417        else {
14418            return;
14419        };
14420
14421        let project = self.project.clone();
14422
14423        cx.spawn_in(window, async move |_, cx| {
14424            let result = find_file(&buffer, project, buffer_position, cx).await;
14425
14426            if let Some((_, path)) = result {
14427                workspace
14428                    .update_in(cx, |workspace, window, cx| {
14429                        workspace.open_resolved_path(path, window, cx)
14430                    })?
14431                    .await?;
14432            }
14433            anyhow::Ok(())
14434        })
14435        .detach();
14436    }
14437
14438    pub(crate) fn navigate_to_hover_links(
14439        &mut self,
14440        kind: Option<GotoDefinitionKind>,
14441        mut definitions: Vec<HoverLink>,
14442        split: bool,
14443        window: &mut Window,
14444        cx: &mut Context<Editor>,
14445    ) -> Task<Result<Navigated>> {
14446        // If there is one definition, just open it directly
14447        if definitions.len() == 1 {
14448            let definition = definitions.pop().unwrap();
14449
14450            enum TargetTaskResult {
14451                Location(Option<Location>),
14452                AlreadyNavigated,
14453            }
14454
14455            let target_task = match definition {
14456                HoverLink::Text(link) => {
14457                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14458                }
14459                HoverLink::InlayHint(lsp_location, server_id) => {
14460                    let computation =
14461                        self.compute_target_location(lsp_location, server_id, window, cx);
14462                    cx.background_spawn(async move {
14463                        let location = computation.await?;
14464                        Ok(TargetTaskResult::Location(location))
14465                    })
14466                }
14467                HoverLink::Url(url) => {
14468                    cx.open_url(&url);
14469                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14470                }
14471                HoverLink::File(path) => {
14472                    if let Some(workspace) = self.workspace() {
14473                        cx.spawn_in(window, async move |_, cx| {
14474                            workspace
14475                                .update_in(cx, |workspace, window, cx| {
14476                                    workspace.open_resolved_path(path, window, cx)
14477                                })?
14478                                .await
14479                                .map(|_| TargetTaskResult::AlreadyNavigated)
14480                        })
14481                    } else {
14482                        Task::ready(Ok(TargetTaskResult::Location(None)))
14483                    }
14484                }
14485            };
14486            cx.spawn_in(window, async move |editor, cx| {
14487                let target = match target_task.await.context("target resolution task")? {
14488                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14489                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14490                    TargetTaskResult::Location(Some(target)) => target,
14491                };
14492
14493                editor.update_in(cx, |editor, window, cx| {
14494                    let Some(workspace) = editor.workspace() else {
14495                        return Navigated::No;
14496                    };
14497                    let pane = workspace.read(cx).active_pane().clone();
14498
14499                    let range = target.range.to_point(target.buffer.read(cx));
14500                    let range = editor.range_for_match(&range);
14501                    let range = collapse_multiline_range(range);
14502
14503                    if !split
14504                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14505                    {
14506                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14507                    } else {
14508                        window.defer(cx, move |window, cx| {
14509                            let target_editor: Entity<Self> =
14510                                workspace.update(cx, |workspace, cx| {
14511                                    let pane = if split {
14512                                        workspace.adjacent_pane(window, cx)
14513                                    } else {
14514                                        workspace.active_pane().clone()
14515                                    };
14516
14517                                    workspace.open_project_item(
14518                                        pane,
14519                                        target.buffer.clone(),
14520                                        true,
14521                                        true,
14522                                        window,
14523                                        cx,
14524                                    )
14525                                });
14526                            target_editor.update(cx, |target_editor, cx| {
14527                                // When selecting a definition in a different buffer, disable the nav history
14528                                // to avoid creating a history entry at the previous cursor location.
14529                                pane.update(cx, |pane, _| pane.disable_history());
14530                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14531                                pane.update(cx, |pane, _| pane.enable_history());
14532                            });
14533                        });
14534                    }
14535                    Navigated::Yes
14536                })
14537            })
14538        } else if !definitions.is_empty() {
14539            cx.spawn_in(window, async move |editor, cx| {
14540                let (title, location_tasks, workspace) = editor
14541                    .update_in(cx, |editor, window, cx| {
14542                        let tab_kind = match kind {
14543                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14544                            _ => "Definitions",
14545                        };
14546                        let title = definitions
14547                            .iter()
14548                            .find_map(|definition| match definition {
14549                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14550                                    let buffer = origin.buffer.read(cx);
14551                                    format!(
14552                                        "{} for {}",
14553                                        tab_kind,
14554                                        buffer
14555                                            .text_for_range(origin.range.clone())
14556                                            .collect::<String>()
14557                                    )
14558                                }),
14559                                HoverLink::InlayHint(_, _) => None,
14560                                HoverLink::Url(_) => None,
14561                                HoverLink::File(_) => None,
14562                            })
14563                            .unwrap_or(tab_kind.to_string());
14564                        let location_tasks = definitions
14565                            .into_iter()
14566                            .map(|definition| match definition {
14567                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14568                                HoverLink::InlayHint(lsp_location, server_id) => editor
14569                                    .compute_target_location(lsp_location, server_id, window, cx),
14570                                HoverLink::Url(_) => Task::ready(Ok(None)),
14571                                HoverLink::File(_) => Task::ready(Ok(None)),
14572                            })
14573                            .collect::<Vec<_>>();
14574                        (title, location_tasks, editor.workspace().clone())
14575                    })
14576                    .context("location tasks preparation")?;
14577
14578                let locations = future::join_all(location_tasks)
14579                    .await
14580                    .into_iter()
14581                    .filter_map(|location| location.transpose())
14582                    .collect::<Result<_>>()
14583                    .context("location tasks")?;
14584
14585                let Some(workspace) = workspace else {
14586                    return Ok(Navigated::No);
14587                };
14588                let opened = workspace
14589                    .update_in(cx, |workspace, window, cx| {
14590                        Self::open_locations_in_multibuffer(
14591                            workspace,
14592                            locations,
14593                            title,
14594                            split,
14595                            MultibufferSelectionMode::First,
14596                            window,
14597                            cx,
14598                        )
14599                    })
14600                    .ok();
14601
14602                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14603            })
14604        } else {
14605            Task::ready(Ok(Navigated::No))
14606        }
14607    }
14608
14609    fn compute_target_location(
14610        &self,
14611        lsp_location: lsp::Location,
14612        server_id: LanguageServerId,
14613        window: &mut Window,
14614        cx: &mut Context<Self>,
14615    ) -> Task<anyhow::Result<Option<Location>>> {
14616        let Some(project) = self.project.clone() else {
14617            return Task::ready(Ok(None));
14618        };
14619
14620        cx.spawn_in(window, async move |editor, cx| {
14621            let location_task = editor.update(cx, |_, cx| {
14622                project.update(cx, |project, cx| {
14623                    let language_server_name = project
14624                        .language_server_statuses(cx)
14625                        .find(|(id, _)| server_id == *id)
14626                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14627                    language_server_name.map(|language_server_name| {
14628                        project.open_local_buffer_via_lsp(
14629                            lsp_location.uri.clone(),
14630                            server_id,
14631                            language_server_name,
14632                            cx,
14633                        )
14634                    })
14635                })
14636            })?;
14637            let location = match location_task {
14638                Some(task) => Some({
14639                    let target_buffer_handle = task.await.context("open local buffer")?;
14640                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14641                        let target_start = target_buffer
14642                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14643                        let target_end = target_buffer
14644                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14645                        target_buffer.anchor_after(target_start)
14646                            ..target_buffer.anchor_before(target_end)
14647                    })?;
14648                    Location {
14649                        buffer: target_buffer_handle,
14650                        range,
14651                    }
14652                }),
14653                None => None,
14654            };
14655            Ok(location)
14656        })
14657    }
14658
14659    pub fn find_all_references(
14660        &mut self,
14661        _: &FindAllReferences,
14662        window: &mut Window,
14663        cx: &mut Context<Self>,
14664    ) -> Option<Task<Result<Navigated>>> {
14665        let selection = self.selections.newest::<usize>(cx);
14666        let multi_buffer = self.buffer.read(cx);
14667        let head = selection.head();
14668
14669        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14670        let head_anchor = multi_buffer_snapshot.anchor_at(
14671            head,
14672            if head < selection.tail() {
14673                Bias::Right
14674            } else {
14675                Bias::Left
14676            },
14677        );
14678
14679        match self
14680            .find_all_references_task_sources
14681            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14682        {
14683            Ok(_) => {
14684                log::info!(
14685                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14686                );
14687                return None;
14688            }
14689            Err(i) => {
14690                self.find_all_references_task_sources.insert(i, head_anchor);
14691            }
14692        }
14693
14694        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14695        let workspace = self.workspace()?;
14696        let project = workspace.read(cx).project().clone();
14697        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14698        Some(cx.spawn_in(window, async move |editor, cx| {
14699            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14700                if let Ok(i) = editor
14701                    .find_all_references_task_sources
14702                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14703                {
14704                    editor.find_all_references_task_sources.remove(i);
14705                }
14706            });
14707
14708            let locations = references.await?;
14709            if locations.is_empty() {
14710                return anyhow::Ok(Navigated::No);
14711            }
14712
14713            workspace.update_in(cx, |workspace, window, cx| {
14714                let title = locations
14715                    .first()
14716                    .as_ref()
14717                    .map(|location| {
14718                        let buffer = location.buffer.read(cx);
14719                        format!(
14720                            "References to `{}`",
14721                            buffer
14722                                .text_for_range(location.range.clone())
14723                                .collect::<String>()
14724                        )
14725                    })
14726                    .unwrap();
14727                Self::open_locations_in_multibuffer(
14728                    workspace,
14729                    locations,
14730                    title,
14731                    false,
14732                    MultibufferSelectionMode::First,
14733                    window,
14734                    cx,
14735                );
14736                Navigated::Yes
14737            })
14738        }))
14739    }
14740
14741    /// Opens a multibuffer with the given project locations in it
14742    pub fn open_locations_in_multibuffer(
14743        workspace: &mut Workspace,
14744        mut locations: Vec<Location>,
14745        title: String,
14746        split: bool,
14747        multibuffer_selection_mode: MultibufferSelectionMode,
14748        window: &mut Window,
14749        cx: &mut Context<Workspace>,
14750    ) {
14751        // If there are multiple definitions, open them in a multibuffer
14752        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14753        let mut locations = locations.into_iter().peekable();
14754        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14755        let capability = workspace.project().read(cx).capability();
14756
14757        let excerpt_buffer = cx.new(|cx| {
14758            let mut multibuffer = MultiBuffer::new(capability);
14759            while let Some(location) = locations.next() {
14760                let buffer = location.buffer.read(cx);
14761                let mut ranges_for_buffer = Vec::new();
14762                let range = location.range.to_point(buffer);
14763                ranges_for_buffer.push(range.clone());
14764
14765                while let Some(next_location) = locations.peek() {
14766                    if next_location.buffer == location.buffer {
14767                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14768                        locations.next();
14769                    } else {
14770                        break;
14771                    }
14772                }
14773
14774                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14775                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14776                    PathKey::for_buffer(&location.buffer, cx),
14777                    location.buffer.clone(),
14778                    ranges_for_buffer,
14779                    DEFAULT_MULTIBUFFER_CONTEXT,
14780                    cx,
14781                );
14782                ranges.extend(new_ranges)
14783            }
14784
14785            multibuffer.with_title(title)
14786        });
14787
14788        let editor = cx.new(|cx| {
14789            Editor::for_multibuffer(
14790                excerpt_buffer,
14791                Some(workspace.project().clone()),
14792                window,
14793                cx,
14794            )
14795        });
14796        editor.update(cx, |editor, cx| {
14797            match multibuffer_selection_mode {
14798                MultibufferSelectionMode::First => {
14799                    if let Some(first_range) = ranges.first() {
14800                        editor.change_selections(None, window, cx, |selections| {
14801                            selections.clear_disjoint();
14802                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14803                        });
14804                    }
14805                    editor.highlight_background::<Self>(
14806                        &ranges,
14807                        |theme| theme.editor_highlighted_line_background,
14808                        cx,
14809                    );
14810                }
14811                MultibufferSelectionMode::All => {
14812                    editor.change_selections(None, window, cx, |selections| {
14813                        selections.clear_disjoint();
14814                        selections.select_anchor_ranges(ranges);
14815                    });
14816                }
14817            }
14818            editor.register_buffers_with_language_servers(cx);
14819        });
14820
14821        let item = Box::new(editor);
14822        let item_id = item.item_id();
14823
14824        if split {
14825            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14826        } else {
14827            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14828                let (preview_item_id, preview_item_idx) =
14829                    workspace.active_pane().read_with(cx, |pane, _| {
14830                        (pane.preview_item_id(), pane.preview_item_idx())
14831                    });
14832
14833                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14834
14835                if let Some(preview_item_id) = preview_item_id {
14836                    workspace.active_pane().update(cx, |pane, cx| {
14837                        pane.remove_item(preview_item_id, false, false, window, cx);
14838                    });
14839                }
14840            } else {
14841                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14842            }
14843        }
14844        workspace.active_pane().update(cx, |pane, cx| {
14845            pane.set_preview_item_id(Some(item_id), cx);
14846        });
14847    }
14848
14849    pub fn rename(
14850        &mut self,
14851        _: &Rename,
14852        window: &mut Window,
14853        cx: &mut Context<Self>,
14854    ) -> Option<Task<Result<()>>> {
14855        use language::ToOffset as _;
14856
14857        let provider = self.semantics_provider.clone()?;
14858        let selection = self.selections.newest_anchor().clone();
14859        let (cursor_buffer, cursor_buffer_position) = self
14860            .buffer
14861            .read(cx)
14862            .text_anchor_for_position(selection.head(), cx)?;
14863        let (tail_buffer, cursor_buffer_position_end) = self
14864            .buffer
14865            .read(cx)
14866            .text_anchor_for_position(selection.tail(), cx)?;
14867        if tail_buffer != cursor_buffer {
14868            return None;
14869        }
14870
14871        let snapshot = cursor_buffer.read(cx).snapshot();
14872        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14873        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14874        let prepare_rename = provider
14875            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14876            .unwrap_or_else(|| Task::ready(Ok(None)));
14877        drop(snapshot);
14878
14879        Some(cx.spawn_in(window, async move |this, cx| {
14880            let rename_range = if let Some(range) = prepare_rename.await? {
14881                Some(range)
14882            } else {
14883                this.update(cx, |this, cx| {
14884                    let buffer = this.buffer.read(cx).snapshot(cx);
14885                    let mut buffer_highlights = this
14886                        .document_highlights_for_position(selection.head(), &buffer)
14887                        .filter(|highlight| {
14888                            highlight.start.excerpt_id == selection.head().excerpt_id
14889                                && highlight.end.excerpt_id == selection.head().excerpt_id
14890                        });
14891                    buffer_highlights
14892                        .next()
14893                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14894                })?
14895            };
14896            if let Some(rename_range) = rename_range {
14897                this.update_in(cx, |this, window, cx| {
14898                    let snapshot = cursor_buffer.read(cx).snapshot();
14899                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14900                    let cursor_offset_in_rename_range =
14901                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14902                    let cursor_offset_in_rename_range_end =
14903                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14904
14905                    this.take_rename(false, window, cx);
14906                    let buffer = this.buffer.read(cx).read(cx);
14907                    let cursor_offset = selection.head().to_offset(&buffer);
14908                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14909                    let rename_end = rename_start + rename_buffer_range.len();
14910                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14911                    let mut old_highlight_id = None;
14912                    let old_name: Arc<str> = buffer
14913                        .chunks(rename_start..rename_end, true)
14914                        .map(|chunk| {
14915                            if old_highlight_id.is_none() {
14916                                old_highlight_id = chunk.syntax_highlight_id;
14917                            }
14918                            chunk.text
14919                        })
14920                        .collect::<String>()
14921                        .into();
14922
14923                    drop(buffer);
14924
14925                    // Position the selection in the rename editor so that it matches the current selection.
14926                    this.show_local_selections = false;
14927                    let rename_editor = cx.new(|cx| {
14928                        let mut editor = Editor::single_line(window, cx);
14929                        editor.buffer.update(cx, |buffer, cx| {
14930                            buffer.edit([(0..0, old_name.clone())], None, cx)
14931                        });
14932                        let rename_selection_range = match cursor_offset_in_rename_range
14933                            .cmp(&cursor_offset_in_rename_range_end)
14934                        {
14935                            Ordering::Equal => {
14936                                editor.select_all(&SelectAll, window, cx);
14937                                return editor;
14938                            }
14939                            Ordering::Less => {
14940                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14941                            }
14942                            Ordering::Greater => {
14943                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14944                            }
14945                        };
14946                        if rename_selection_range.end > old_name.len() {
14947                            editor.select_all(&SelectAll, window, cx);
14948                        } else {
14949                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14950                                s.select_ranges([rename_selection_range]);
14951                            });
14952                        }
14953                        editor
14954                    });
14955                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14956                        if e == &EditorEvent::Focused {
14957                            cx.emit(EditorEvent::FocusedIn)
14958                        }
14959                    })
14960                    .detach();
14961
14962                    let write_highlights =
14963                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14964                    let read_highlights =
14965                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14966                    let ranges = write_highlights
14967                        .iter()
14968                        .flat_map(|(_, ranges)| ranges.iter())
14969                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14970                        .cloned()
14971                        .collect();
14972
14973                    this.highlight_text::<Rename>(
14974                        ranges,
14975                        HighlightStyle {
14976                            fade_out: Some(0.6),
14977                            ..Default::default()
14978                        },
14979                        cx,
14980                    );
14981                    let rename_focus_handle = rename_editor.focus_handle(cx);
14982                    window.focus(&rename_focus_handle);
14983                    let block_id = this.insert_blocks(
14984                        [BlockProperties {
14985                            style: BlockStyle::Flex,
14986                            placement: BlockPlacement::Below(range.start),
14987                            height: Some(1),
14988                            render: Arc::new({
14989                                let rename_editor = rename_editor.clone();
14990                                move |cx: &mut BlockContext| {
14991                                    let mut text_style = cx.editor_style.text.clone();
14992                                    if let Some(highlight_style) = old_highlight_id
14993                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14994                                    {
14995                                        text_style = text_style.highlight(highlight_style);
14996                                    }
14997                                    div()
14998                                        .block_mouse_down()
14999                                        .pl(cx.anchor_x)
15000                                        .child(EditorElement::new(
15001                                            &rename_editor,
15002                                            EditorStyle {
15003                                                background: cx.theme().system().transparent,
15004                                                local_player: cx.editor_style.local_player,
15005                                                text: text_style,
15006                                                scrollbar_width: cx.editor_style.scrollbar_width,
15007                                                syntax: cx.editor_style.syntax.clone(),
15008                                                status: cx.editor_style.status.clone(),
15009                                                inlay_hints_style: HighlightStyle {
15010                                                    font_weight: Some(FontWeight::BOLD),
15011                                                    ..make_inlay_hints_style(cx.app)
15012                                                },
15013                                                inline_completion_styles: make_suggestion_styles(
15014                                                    cx.app,
15015                                                ),
15016                                                ..EditorStyle::default()
15017                                            },
15018                                        ))
15019                                        .into_any_element()
15020                                }
15021                            }),
15022                            priority: 0,
15023                            render_in_minimap: true,
15024                        }],
15025                        Some(Autoscroll::fit()),
15026                        cx,
15027                    )[0];
15028                    this.pending_rename = Some(RenameState {
15029                        range,
15030                        old_name,
15031                        editor: rename_editor,
15032                        block_id,
15033                    });
15034                })?;
15035            }
15036
15037            Ok(())
15038        }))
15039    }
15040
15041    pub fn confirm_rename(
15042        &mut self,
15043        _: &ConfirmRename,
15044        window: &mut Window,
15045        cx: &mut Context<Self>,
15046    ) -> Option<Task<Result<()>>> {
15047        let rename = self.take_rename(false, window, cx)?;
15048        let workspace = self.workspace()?.downgrade();
15049        let (buffer, start) = self
15050            .buffer
15051            .read(cx)
15052            .text_anchor_for_position(rename.range.start, cx)?;
15053        let (end_buffer, _) = self
15054            .buffer
15055            .read(cx)
15056            .text_anchor_for_position(rename.range.end, cx)?;
15057        if buffer != end_buffer {
15058            return None;
15059        }
15060
15061        let old_name = rename.old_name;
15062        let new_name = rename.editor.read(cx).text(cx);
15063
15064        let rename = self.semantics_provider.as_ref()?.perform_rename(
15065            &buffer,
15066            start,
15067            new_name.clone(),
15068            cx,
15069        )?;
15070
15071        Some(cx.spawn_in(window, async move |editor, cx| {
15072            let project_transaction = rename.await?;
15073            Self::open_project_transaction(
15074                &editor,
15075                workspace,
15076                project_transaction,
15077                format!("Rename: {}{}", old_name, new_name),
15078                cx,
15079            )
15080            .await?;
15081
15082            editor.update(cx, |editor, cx| {
15083                editor.refresh_document_highlights(cx);
15084            })?;
15085            Ok(())
15086        }))
15087    }
15088
15089    fn take_rename(
15090        &mut self,
15091        moving_cursor: bool,
15092        window: &mut Window,
15093        cx: &mut Context<Self>,
15094    ) -> Option<RenameState> {
15095        let rename = self.pending_rename.take()?;
15096        if rename.editor.focus_handle(cx).is_focused(window) {
15097            window.focus(&self.focus_handle);
15098        }
15099
15100        self.remove_blocks(
15101            [rename.block_id].into_iter().collect(),
15102            Some(Autoscroll::fit()),
15103            cx,
15104        );
15105        self.clear_highlights::<Rename>(cx);
15106        self.show_local_selections = true;
15107
15108        if moving_cursor {
15109            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15110                editor.selections.newest::<usize>(cx).head()
15111            });
15112
15113            // Update the selection to match the position of the selection inside
15114            // the rename editor.
15115            let snapshot = self.buffer.read(cx).read(cx);
15116            let rename_range = rename.range.to_offset(&snapshot);
15117            let cursor_in_editor = snapshot
15118                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15119                .min(rename_range.end);
15120            drop(snapshot);
15121
15122            self.change_selections(None, window, cx, |s| {
15123                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15124            });
15125        } else {
15126            self.refresh_document_highlights(cx);
15127        }
15128
15129        Some(rename)
15130    }
15131
15132    pub fn pending_rename(&self) -> Option<&RenameState> {
15133        self.pending_rename.as_ref()
15134    }
15135
15136    fn format(
15137        &mut self,
15138        _: &Format,
15139        window: &mut Window,
15140        cx: &mut Context<Self>,
15141    ) -> Option<Task<Result<()>>> {
15142        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15143
15144        let project = match &self.project {
15145            Some(project) => project.clone(),
15146            None => return None,
15147        };
15148
15149        Some(self.perform_format(
15150            project,
15151            FormatTrigger::Manual,
15152            FormatTarget::Buffers,
15153            window,
15154            cx,
15155        ))
15156    }
15157
15158    fn format_selections(
15159        &mut self,
15160        _: &FormatSelections,
15161        window: &mut Window,
15162        cx: &mut Context<Self>,
15163    ) -> Option<Task<Result<()>>> {
15164        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15165
15166        let project = match &self.project {
15167            Some(project) => project.clone(),
15168            None => return None,
15169        };
15170
15171        let ranges = self
15172            .selections
15173            .all_adjusted(cx)
15174            .into_iter()
15175            .map(|selection| selection.range())
15176            .collect_vec();
15177
15178        Some(self.perform_format(
15179            project,
15180            FormatTrigger::Manual,
15181            FormatTarget::Ranges(ranges),
15182            window,
15183            cx,
15184        ))
15185    }
15186
15187    fn perform_format(
15188        &mut self,
15189        project: Entity<Project>,
15190        trigger: FormatTrigger,
15191        target: FormatTarget,
15192        window: &mut Window,
15193        cx: &mut Context<Self>,
15194    ) -> Task<Result<()>> {
15195        let buffer = self.buffer.clone();
15196        let (buffers, target) = match target {
15197            FormatTarget::Buffers => {
15198                let mut buffers = buffer.read(cx).all_buffers();
15199                if trigger == FormatTrigger::Save {
15200                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15201                }
15202                (buffers, LspFormatTarget::Buffers)
15203            }
15204            FormatTarget::Ranges(selection_ranges) => {
15205                let multi_buffer = buffer.read(cx);
15206                let snapshot = multi_buffer.read(cx);
15207                let mut buffers = HashSet::default();
15208                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15209                    BTreeMap::new();
15210                for selection_range in selection_ranges {
15211                    for (buffer, buffer_range, _) in
15212                        snapshot.range_to_buffer_ranges(selection_range)
15213                    {
15214                        let buffer_id = buffer.remote_id();
15215                        let start = buffer.anchor_before(buffer_range.start);
15216                        let end = buffer.anchor_after(buffer_range.end);
15217                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15218                        buffer_id_to_ranges
15219                            .entry(buffer_id)
15220                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15221                            .or_insert_with(|| vec![start..end]);
15222                    }
15223                }
15224                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15225            }
15226        };
15227
15228        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15229        let selections_prev = transaction_id_prev
15230            .and_then(|transaction_id_prev| {
15231                // default to selections as they were after the last edit, if we have them,
15232                // instead of how they are now.
15233                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15234                // will take you back to where you made the last edit, instead of staying where you scrolled
15235                self.selection_history
15236                    .transaction(transaction_id_prev)
15237                    .map(|t| t.0.clone())
15238            })
15239            .unwrap_or_else(|| {
15240                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15241                self.selections.disjoint_anchors()
15242            });
15243
15244        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15245        let format = project.update(cx, |project, cx| {
15246            project.format(buffers, target, true, trigger, cx)
15247        });
15248
15249        cx.spawn_in(window, async move |editor, cx| {
15250            let transaction = futures::select_biased! {
15251                transaction = format.log_err().fuse() => transaction,
15252                () = timeout => {
15253                    log::warn!("timed out waiting for formatting");
15254                    None
15255                }
15256            };
15257
15258            buffer
15259                .update(cx, |buffer, cx| {
15260                    if let Some(transaction) = transaction {
15261                        if !buffer.is_singleton() {
15262                            buffer.push_transaction(&transaction.0, cx);
15263                        }
15264                    }
15265                    cx.notify();
15266                })
15267                .ok();
15268
15269            if let Some(transaction_id_now) =
15270                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15271            {
15272                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15273                if has_new_transaction {
15274                    _ = editor.update(cx, |editor, _| {
15275                        editor
15276                            .selection_history
15277                            .insert_transaction(transaction_id_now, selections_prev);
15278                    });
15279                }
15280            }
15281
15282            Ok(())
15283        })
15284    }
15285
15286    fn organize_imports(
15287        &mut self,
15288        _: &OrganizeImports,
15289        window: &mut Window,
15290        cx: &mut Context<Self>,
15291    ) -> Option<Task<Result<()>>> {
15292        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15293        let project = match &self.project {
15294            Some(project) => project.clone(),
15295            None => return None,
15296        };
15297        Some(self.perform_code_action_kind(
15298            project,
15299            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15300            window,
15301            cx,
15302        ))
15303    }
15304
15305    fn perform_code_action_kind(
15306        &mut self,
15307        project: Entity<Project>,
15308        kind: CodeActionKind,
15309        window: &mut Window,
15310        cx: &mut Context<Self>,
15311    ) -> Task<Result<()>> {
15312        let buffer = self.buffer.clone();
15313        let buffers = buffer.read(cx).all_buffers();
15314        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15315        let apply_action = project.update(cx, |project, cx| {
15316            project.apply_code_action_kind(buffers, kind, true, cx)
15317        });
15318        cx.spawn_in(window, async move |_, cx| {
15319            let transaction = futures::select_biased! {
15320                () = timeout => {
15321                    log::warn!("timed out waiting for executing code action");
15322                    None
15323                }
15324                transaction = apply_action.log_err().fuse() => transaction,
15325            };
15326            buffer
15327                .update(cx, |buffer, cx| {
15328                    // check if we need this
15329                    if let Some(transaction) = transaction {
15330                        if !buffer.is_singleton() {
15331                            buffer.push_transaction(&transaction.0, cx);
15332                        }
15333                    }
15334                    cx.notify();
15335                })
15336                .ok();
15337            Ok(())
15338        })
15339    }
15340
15341    fn restart_language_server(
15342        &mut self,
15343        _: &RestartLanguageServer,
15344        _: &mut Window,
15345        cx: &mut Context<Self>,
15346    ) {
15347        if let Some(project) = self.project.clone() {
15348            self.buffer.update(cx, |multi_buffer, cx| {
15349                project.update(cx, |project, cx| {
15350                    project.restart_language_servers_for_buffers(
15351                        multi_buffer.all_buffers().into_iter().collect(),
15352                        cx,
15353                    );
15354                });
15355            })
15356        }
15357    }
15358
15359    fn stop_language_server(
15360        &mut self,
15361        _: &StopLanguageServer,
15362        _: &mut Window,
15363        cx: &mut Context<Self>,
15364    ) {
15365        if let Some(project) = self.project.clone() {
15366            self.buffer.update(cx, |multi_buffer, cx| {
15367                project.update(cx, |project, cx| {
15368                    project.stop_language_servers_for_buffers(
15369                        multi_buffer.all_buffers().into_iter().collect(),
15370                        cx,
15371                    );
15372                    cx.emit(project::Event::RefreshInlayHints);
15373                });
15374            });
15375        }
15376    }
15377
15378    fn cancel_language_server_work(
15379        workspace: &mut Workspace,
15380        _: &actions::CancelLanguageServerWork,
15381        _: &mut Window,
15382        cx: &mut Context<Workspace>,
15383    ) {
15384        let project = workspace.project();
15385        let buffers = workspace
15386            .active_item(cx)
15387            .and_then(|item| item.act_as::<Editor>(cx))
15388            .map_or(HashSet::default(), |editor| {
15389                editor.read(cx).buffer.read(cx).all_buffers()
15390            });
15391        project.update(cx, |project, cx| {
15392            project.cancel_language_server_work_for_buffers(buffers, cx);
15393        });
15394    }
15395
15396    fn show_character_palette(
15397        &mut self,
15398        _: &ShowCharacterPalette,
15399        window: &mut Window,
15400        _: &mut Context<Self>,
15401    ) {
15402        window.show_character_palette();
15403    }
15404
15405    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15406        if self.mode.is_minimap() {
15407            return;
15408        }
15409
15410        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15411            let buffer = self.buffer.read(cx).snapshot(cx);
15412            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15413            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15414            let is_valid = buffer
15415                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15416                .any(|entry| {
15417                    entry.diagnostic.is_primary
15418                        && !entry.range.is_empty()
15419                        && entry.range.start == primary_range_start
15420                        && entry.diagnostic.message == active_diagnostics.active_message
15421                });
15422
15423            if !is_valid {
15424                self.dismiss_diagnostics(cx);
15425            }
15426        }
15427    }
15428
15429    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15430        match &self.active_diagnostics {
15431            ActiveDiagnostic::Group(group) => Some(group),
15432            _ => None,
15433        }
15434    }
15435
15436    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15437        self.dismiss_diagnostics(cx);
15438        self.active_diagnostics = ActiveDiagnostic::All;
15439    }
15440
15441    fn activate_diagnostics(
15442        &mut self,
15443        buffer_id: BufferId,
15444        diagnostic: DiagnosticEntry<usize>,
15445        window: &mut Window,
15446        cx: &mut Context<Self>,
15447    ) {
15448        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15449            return;
15450        }
15451        self.dismiss_diagnostics(cx);
15452        let snapshot = self.snapshot(window, cx);
15453        let buffer = self.buffer.read(cx).snapshot(cx);
15454        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15455            return;
15456        };
15457
15458        let diagnostic_group = buffer
15459            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15460            .collect::<Vec<_>>();
15461
15462        let blocks =
15463            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15464
15465        let blocks = self.display_map.update(cx, |display_map, cx| {
15466            display_map.insert_blocks(blocks, cx).into_iter().collect()
15467        });
15468        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15469            active_range: buffer.anchor_before(diagnostic.range.start)
15470                ..buffer.anchor_after(diagnostic.range.end),
15471            active_message: diagnostic.diagnostic.message.clone(),
15472            group_id: diagnostic.diagnostic.group_id,
15473            blocks,
15474        });
15475        cx.notify();
15476    }
15477
15478    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15479        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15480            return;
15481        };
15482
15483        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15484        if let ActiveDiagnostic::Group(group) = prev {
15485            self.display_map.update(cx, |display_map, cx| {
15486                display_map.remove_blocks(group.blocks, cx);
15487            });
15488            cx.notify();
15489        }
15490    }
15491
15492    /// Disable inline diagnostics rendering for this editor.
15493    pub fn disable_inline_diagnostics(&mut self) {
15494        self.inline_diagnostics_enabled = false;
15495        self.inline_diagnostics_update = Task::ready(());
15496        self.inline_diagnostics.clear();
15497    }
15498
15499    pub fn diagnostics_enabled(&self) -> bool {
15500        self.mode.is_full()
15501    }
15502
15503    pub fn inline_diagnostics_enabled(&self) -> bool {
15504        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15505    }
15506
15507    pub fn show_inline_diagnostics(&self) -> bool {
15508        self.show_inline_diagnostics
15509    }
15510
15511    pub fn toggle_inline_diagnostics(
15512        &mut self,
15513        _: &ToggleInlineDiagnostics,
15514        window: &mut Window,
15515        cx: &mut Context<Editor>,
15516    ) {
15517        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15518        self.refresh_inline_diagnostics(false, window, cx);
15519    }
15520
15521    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15522        self.diagnostics_max_severity = severity;
15523        self.display_map.update(cx, |display_map, _| {
15524            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15525        });
15526    }
15527
15528    pub fn toggle_diagnostics(
15529        &mut self,
15530        _: &ToggleDiagnostics,
15531        window: &mut Window,
15532        cx: &mut Context<Editor>,
15533    ) {
15534        if !self.diagnostics_enabled() {
15535            return;
15536        }
15537
15538        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15539            EditorSettings::get_global(cx)
15540                .diagnostics_max_severity
15541                .filter(|severity| severity != &DiagnosticSeverity::Off)
15542                .unwrap_or(DiagnosticSeverity::Hint)
15543        } else {
15544            DiagnosticSeverity::Off
15545        };
15546        self.set_max_diagnostics_severity(new_severity, cx);
15547        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15548            self.active_diagnostics = ActiveDiagnostic::None;
15549            self.inline_diagnostics_update = Task::ready(());
15550            self.inline_diagnostics.clear();
15551        } else {
15552            self.refresh_inline_diagnostics(false, window, cx);
15553        }
15554
15555        cx.notify();
15556    }
15557
15558    pub fn toggle_minimap(
15559        &mut self,
15560        _: &ToggleMinimap,
15561        window: &mut Window,
15562        cx: &mut Context<Editor>,
15563    ) {
15564        if self.supports_minimap(cx) {
15565            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15566        }
15567    }
15568
15569    fn refresh_inline_diagnostics(
15570        &mut self,
15571        debounce: bool,
15572        window: &mut Window,
15573        cx: &mut Context<Self>,
15574    ) {
15575        let max_severity = ProjectSettings::get_global(cx)
15576            .diagnostics
15577            .inline
15578            .max_severity
15579            .unwrap_or(self.diagnostics_max_severity);
15580
15581        if !self.inline_diagnostics_enabled()
15582            || !self.show_inline_diagnostics
15583            || max_severity == DiagnosticSeverity::Off
15584        {
15585            self.inline_diagnostics_update = Task::ready(());
15586            self.inline_diagnostics.clear();
15587            return;
15588        }
15589
15590        let debounce_ms = ProjectSettings::get_global(cx)
15591            .diagnostics
15592            .inline
15593            .update_debounce_ms;
15594        let debounce = if debounce && debounce_ms > 0 {
15595            Some(Duration::from_millis(debounce_ms))
15596        } else {
15597            None
15598        };
15599        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15600            let editor = editor.upgrade().unwrap();
15601
15602            if let Some(debounce) = debounce {
15603                cx.background_executor().timer(debounce).await;
15604            }
15605            let Some(snapshot) = editor
15606                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15607                .ok()
15608            else {
15609                return;
15610            };
15611
15612            let new_inline_diagnostics = cx
15613                .background_spawn(async move {
15614                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15615                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15616                        let message = diagnostic_entry
15617                            .diagnostic
15618                            .message
15619                            .split_once('\n')
15620                            .map(|(line, _)| line)
15621                            .map(SharedString::new)
15622                            .unwrap_or_else(|| {
15623                                SharedString::from(diagnostic_entry.diagnostic.message)
15624                            });
15625                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15626                        let (Ok(i) | Err(i)) = inline_diagnostics
15627                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15628                        inline_diagnostics.insert(
15629                            i,
15630                            (
15631                                start_anchor,
15632                                InlineDiagnostic {
15633                                    message,
15634                                    group_id: diagnostic_entry.diagnostic.group_id,
15635                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15636                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15637                                    severity: diagnostic_entry.diagnostic.severity,
15638                                },
15639                            ),
15640                        );
15641                    }
15642                    inline_diagnostics
15643                })
15644                .await;
15645
15646            editor
15647                .update(cx, |editor, cx| {
15648                    editor.inline_diagnostics = new_inline_diagnostics;
15649                    cx.notify();
15650                })
15651                .ok();
15652        });
15653    }
15654
15655    pub fn set_selections_from_remote(
15656        &mut self,
15657        selections: Vec<Selection<Anchor>>,
15658        pending_selection: Option<Selection<Anchor>>,
15659        window: &mut Window,
15660        cx: &mut Context<Self>,
15661    ) {
15662        let old_cursor_position = self.selections.newest_anchor().head();
15663        self.selections.change_with(cx, |s| {
15664            s.select_anchors(selections);
15665            if let Some(pending_selection) = pending_selection {
15666                s.set_pending(pending_selection, SelectMode::Character);
15667            } else {
15668                s.clear_pending();
15669            }
15670        });
15671        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15672    }
15673
15674    fn push_to_selection_history(&mut self) {
15675        self.selection_history.push(SelectionHistoryEntry {
15676            selections: self.selections.disjoint_anchors(),
15677            select_next_state: self.select_next_state.clone(),
15678            select_prev_state: self.select_prev_state.clone(),
15679            add_selections_state: self.add_selections_state.clone(),
15680        });
15681    }
15682
15683    pub fn transact(
15684        &mut self,
15685        window: &mut Window,
15686        cx: &mut Context<Self>,
15687        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15688    ) -> Option<TransactionId> {
15689        self.start_transaction_at(Instant::now(), window, cx);
15690        update(self, window, cx);
15691        self.end_transaction_at(Instant::now(), cx)
15692    }
15693
15694    pub fn start_transaction_at(
15695        &mut self,
15696        now: Instant,
15697        window: &mut Window,
15698        cx: &mut Context<Self>,
15699    ) {
15700        self.end_selection(window, cx);
15701        if let Some(tx_id) = self
15702            .buffer
15703            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15704        {
15705            self.selection_history
15706                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15707            cx.emit(EditorEvent::TransactionBegun {
15708                transaction_id: tx_id,
15709            })
15710        }
15711    }
15712
15713    pub fn end_transaction_at(
15714        &mut self,
15715        now: Instant,
15716        cx: &mut Context<Self>,
15717    ) -> Option<TransactionId> {
15718        if let Some(transaction_id) = self
15719            .buffer
15720            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15721        {
15722            if let Some((_, end_selections)) =
15723                self.selection_history.transaction_mut(transaction_id)
15724            {
15725                *end_selections = Some(self.selections.disjoint_anchors());
15726            } else {
15727                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15728            }
15729
15730            cx.emit(EditorEvent::Edited { transaction_id });
15731            Some(transaction_id)
15732        } else {
15733            None
15734        }
15735    }
15736
15737    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15738        if self.selection_mark_mode {
15739            self.change_selections(None, window, cx, |s| {
15740                s.move_with(|_, sel| {
15741                    sel.collapse_to(sel.head(), SelectionGoal::None);
15742                });
15743            })
15744        }
15745        self.selection_mark_mode = true;
15746        cx.notify();
15747    }
15748
15749    pub fn swap_selection_ends(
15750        &mut self,
15751        _: &actions::SwapSelectionEnds,
15752        window: &mut Window,
15753        cx: &mut Context<Self>,
15754    ) {
15755        self.change_selections(None, window, cx, |s| {
15756            s.move_with(|_, sel| {
15757                if sel.start != sel.end {
15758                    sel.reversed = !sel.reversed
15759                }
15760            });
15761        });
15762        self.request_autoscroll(Autoscroll::newest(), cx);
15763        cx.notify();
15764    }
15765
15766    pub fn toggle_fold(
15767        &mut self,
15768        _: &actions::ToggleFold,
15769        window: &mut Window,
15770        cx: &mut Context<Self>,
15771    ) {
15772        if self.is_singleton(cx) {
15773            let selection = self.selections.newest::<Point>(cx);
15774
15775            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15776            let range = if selection.is_empty() {
15777                let point = selection.head().to_display_point(&display_map);
15778                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15779                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15780                    .to_point(&display_map);
15781                start..end
15782            } else {
15783                selection.range()
15784            };
15785            if display_map.folds_in_range(range).next().is_some() {
15786                self.unfold_lines(&Default::default(), window, cx)
15787            } else {
15788                self.fold(&Default::default(), window, cx)
15789            }
15790        } else {
15791            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15792            let buffer_ids: HashSet<_> = self
15793                .selections
15794                .disjoint_anchor_ranges()
15795                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15796                .collect();
15797
15798            let should_unfold = buffer_ids
15799                .iter()
15800                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15801
15802            for buffer_id in buffer_ids {
15803                if should_unfold {
15804                    self.unfold_buffer(buffer_id, cx);
15805                } else {
15806                    self.fold_buffer(buffer_id, cx);
15807                }
15808            }
15809        }
15810    }
15811
15812    pub fn toggle_fold_recursive(
15813        &mut self,
15814        _: &actions::ToggleFoldRecursive,
15815        window: &mut Window,
15816        cx: &mut Context<Self>,
15817    ) {
15818        let selection = self.selections.newest::<Point>(cx);
15819
15820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15821        let range = if selection.is_empty() {
15822            let point = selection.head().to_display_point(&display_map);
15823            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15824            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15825                .to_point(&display_map);
15826            start..end
15827        } else {
15828            selection.range()
15829        };
15830        if display_map.folds_in_range(range).next().is_some() {
15831            self.unfold_recursive(&Default::default(), window, cx)
15832        } else {
15833            self.fold_recursive(&Default::default(), window, cx)
15834        }
15835    }
15836
15837    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15838        if self.is_singleton(cx) {
15839            let mut to_fold = Vec::new();
15840            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15841            let selections = self.selections.all_adjusted(cx);
15842
15843            for selection in selections {
15844                let range = selection.range().sorted();
15845                let buffer_start_row = range.start.row;
15846
15847                if range.start.row != range.end.row {
15848                    let mut found = false;
15849                    let mut row = range.start.row;
15850                    while row <= range.end.row {
15851                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15852                        {
15853                            found = true;
15854                            row = crease.range().end.row + 1;
15855                            to_fold.push(crease);
15856                        } else {
15857                            row += 1
15858                        }
15859                    }
15860                    if found {
15861                        continue;
15862                    }
15863                }
15864
15865                for row in (0..=range.start.row).rev() {
15866                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15867                        if crease.range().end.row >= buffer_start_row {
15868                            to_fold.push(crease);
15869                            if row <= range.start.row {
15870                                break;
15871                            }
15872                        }
15873                    }
15874                }
15875            }
15876
15877            self.fold_creases(to_fold, true, window, cx);
15878        } else {
15879            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15880            let buffer_ids = self
15881                .selections
15882                .disjoint_anchor_ranges()
15883                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15884                .collect::<HashSet<_>>();
15885            for buffer_id in buffer_ids {
15886                self.fold_buffer(buffer_id, cx);
15887            }
15888        }
15889    }
15890
15891    fn fold_at_level(
15892        &mut self,
15893        fold_at: &FoldAtLevel,
15894        window: &mut Window,
15895        cx: &mut Context<Self>,
15896    ) {
15897        if !self.buffer.read(cx).is_singleton() {
15898            return;
15899        }
15900
15901        let fold_at_level = fold_at.0;
15902        let snapshot = self.buffer.read(cx).snapshot(cx);
15903        let mut to_fold = Vec::new();
15904        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15905
15906        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15907            while start_row < end_row {
15908                match self
15909                    .snapshot(window, cx)
15910                    .crease_for_buffer_row(MultiBufferRow(start_row))
15911                {
15912                    Some(crease) => {
15913                        let nested_start_row = crease.range().start.row + 1;
15914                        let nested_end_row = crease.range().end.row;
15915
15916                        if current_level < fold_at_level {
15917                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15918                        } else if current_level == fold_at_level {
15919                            to_fold.push(crease);
15920                        }
15921
15922                        start_row = nested_end_row + 1;
15923                    }
15924                    None => start_row += 1,
15925                }
15926            }
15927        }
15928
15929        self.fold_creases(to_fold, true, window, cx);
15930    }
15931
15932    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15933        if self.buffer.read(cx).is_singleton() {
15934            let mut fold_ranges = Vec::new();
15935            let snapshot = self.buffer.read(cx).snapshot(cx);
15936
15937            for row in 0..snapshot.max_row().0 {
15938                if let Some(foldable_range) = self
15939                    .snapshot(window, cx)
15940                    .crease_for_buffer_row(MultiBufferRow(row))
15941                {
15942                    fold_ranges.push(foldable_range);
15943                }
15944            }
15945
15946            self.fold_creases(fold_ranges, true, window, cx);
15947        } else {
15948            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15949                editor
15950                    .update_in(cx, |editor, _, cx| {
15951                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15952                            editor.fold_buffer(buffer_id, cx);
15953                        }
15954                    })
15955                    .ok();
15956            });
15957        }
15958    }
15959
15960    pub fn fold_function_bodies(
15961        &mut self,
15962        _: &actions::FoldFunctionBodies,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        let snapshot = self.buffer.read(cx).snapshot(cx);
15967
15968        let ranges = snapshot
15969            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15970            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15971            .collect::<Vec<_>>();
15972
15973        let creases = ranges
15974            .into_iter()
15975            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15976            .collect();
15977
15978        self.fold_creases(creases, true, window, cx);
15979    }
15980
15981    pub fn fold_recursive(
15982        &mut self,
15983        _: &actions::FoldRecursive,
15984        window: &mut Window,
15985        cx: &mut Context<Self>,
15986    ) {
15987        let mut to_fold = Vec::new();
15988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15989        let selections = self.selections.all_adjusted(cx);
15990
15991        for selection in selections {
15992            let range = selection.range().sorted();
15993            let buffer_start_row = range.start.row;
15994
15995            if range.start.row != range.end.row {
15996                let mut found = false;
15997                for row in range.start.row..=range.end.row {
15998                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15999                        found = true;
16000                        to_fold.push(crease);
16001                    }
16002                }
16003                if found {
16004                    continue;
16005                }
16006            }
16007
16008            for row in (0..=range.start.row).rev() {
16009                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16010                    if crease.range().end.row >= buffer_start_row {
16011                        to_fold.push(crease);
16012                    } else {
16013                        break;
16014                    }
16015                }
16016            }
16017        }
16018
16019        self.fold_creases(to_fold, true, window, cx);
16020    }
16021
16022    pub fn fold_at(
16023        &mut self,
16024        buffer_row: MultiBufferRow,
16025        window: &mut Window,
16026        cx: &mut Context<Self>,
16027    ) {
16028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16029
16030        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16031            let autoscroll = self
16032                .selections
16033                .all::<Point>(cx)
16034                .iter()
16035                .any(|selection| crease.range().overlaps(&selection.range()));
16036
16037            self.fold_creases(vec![crease], autoscroll, window, cx);
16038        }
16039    }
16040
16041    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16042        if self.is_singleton(cx) {
16043            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16044            let buffer = &display_map.buffer_snapshot;
16045            let selections = self.selections.all::<Point>(cx);
16046            let ranges = selections
16047                .iter()
16048                .map(|s| {
16049                    let range = s.display_range(&display_map).sorted();
16050                    let mut start = range.start.to_point(&display_map);
16051                    let mut end = range.end.to_point(&display_map);
16052                    start.column = 0;
16053                    end.column = buffer.line_len(MultiBufferRow(end.row));
16054                    start..end
16055                })
16056                .collect::<Vec<_>>();
16057
16058            self.unfold_ranges(&ranges, true, true, cx);
16059        } else {
16060            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16061            let buffer_ids = self
16062                .selections
16063                .disjoint_anchor_ranges()
16064                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16065                .collect::<HashSet<_>>();
16066            for buffer_id in buffer_ids {
16067                self.unfold_buffer(buffer_id, cx);
16068            }
16069        }
16070    }
16071
16072    pub fn unfold_recursive(
16073        &mut self,
16074        _: &UnfoldRecursive,
16075        _window: &mut Window,
16076        cx: &mut Context<Self>,
16077    ) {
16078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16079        let selections = self.selections.all::<Point>(cx);
16080        let ranges = selections
16081            .iter()
16082            .map(|s| {
16083                let mut range = s.display_range(&display_map).sorted();
16084                *range.start.column_mut() = 0;
16085                *range.end.column_mut() = display_map.line_len(range.end.row());
16086                let start = range.start.to_point(&display_map);
16087                let end = range.end.to_point(&display_map);
16088                start..end
16089            })
16090            .collect::<Vec<_>>();
16091
16092        self.unfold_ranges(&ranges, true, true, cx);
16093    }
16094
16095    pub fn unfold_at(
16096        &mut self,
16097        buffer_row: MultiBufferRow,
16098        _window: &mut Window,
16099        cx: &mut Context<Self>,
16100    ) {
16101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16102
16103        let intersection_range = Point::new(buffer_row.0, 0)
16104            ..Point::new(
16105                buffer_row.0,
16106                display_map.buffer_snapshot.line_len(buffer_row),
16107            );
16108
16109        let autoscroll = self
16110            .selections
16111            .all::<Point>(cx)
16112            .iter()
16113            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16114
16115        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16116    }
16117
16118    pub fn unfold_all(
16119        &mut self,
16120        _: &actions::UnfoldAll,
16121        _window: &mut Window,
16122        cx: &mut Context<Self>,
16123    ) {
16124        if self.buffer.read(cx).is_singleton() {
16125            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16126            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16127        } else {
16128            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16129                editor
16130                    .update(cx, |editor, cx| {
16131                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16132                            editor.unfold_buffer(buffer_id, cx);
16133                        }
16134                    })
16135                    .ok();
16136            });
16137        }
16138    }
16139
16140    pub fn fold_selected_ranges(
16141        &mut self,
16142        _: &FoldSelectedRanges,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) {
16146        let selections = self.selections.all_adjusted(cx);
16147        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16148        let ranges = selections
16149            .into_iter()
16150            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16151            .collect::<Vec<_>>();
16152        self.fold_creases(ranges, true, window, cx);
16153    }
16154
16155    pub fn fold_ranges<T: ToOffset + Clone>(
16156        &mut self,
16157        ranges: Vec<Range<T>>,
16158        auto_scroll: bool,
16159        window: &mut Window,
16160        cx: &mut Context<Self>,
16161    ) {
16162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16163        let ranges = ranges
16164            .into_iter()
16165            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16166            .collect::<Vec<_>>();
16167        self.fold_creases(ranges, auto_scroll, window, cx);
16168    }
16169
16170    pub fn fold_creases<T: ToOffset + Clone>(
16171        &mut self,
16172        creases: Vec<Crease<T>>,
16173        auto_scroll: bool,
16174        _window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) {
16177        if creases.is_empty() {
16178            return;
16179        }
16180
16181        let mut buffers_affected = HashSet::default();
16182        let multi_buffer = self.buffer().read(cx);
16183        for crease in &creases {
16184            if let Some((_, buffer, _)) =
16185                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16186            {
16187                buffers_affected.insert(buffer.read(cx).remote_id());
16188            };
16189        }
16190
16191        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16192
16193        if auto_scroll {
16194            self.request_autoscroll(Autoscroll::fit(), cx);
16195        }
16196
16197        cx.notify();
16198
16199        self.scrollbar_marker_state.dirty = true;
16200        self.folds_did_change(cx);
16201    }
16202
16203    /// Removes any folds whose ranges intersect any of the given ranges.
16204    pub fn unfold_ranges<T: ToOffset + Clone>(
16205        &mut self,
16206        ranges: &[Range<T>],
16207        inclusive: bool,
16208        auto_scroll: bool,
16209        cx: &mut Context<Self>,
16210    ) {
16211        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16212            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16213        });
16214        self.folds_did_change(cx);
16215    }
16216
16217    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16218        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16219            return;
16220        }
16221        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16222        self.display_map.update(cx, |display_map, cx| {
16223            display_map.fold_buffers([buffer_id], cx)
16224        });
16225        cx.emit(EditorEvent::BufferFoldToggled {
16226            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16227            folded: true,
16228        });
16229        cx.notify();
16230    }
16231
16232    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16233        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16234            return;
16235        }
16236        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16237        self.display_map.update(cx, |display_map, cx| {
16238            display_map.unfold_buffers([buffer_id], cx);
16239        });
16240        cx.emit(EditorEvent::BufferFoldToggled {
16241            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16242            folded: false,
16243        });
16244        cx.notify();
16245    }
16246
16247    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16248        self.display_map.read(cx).is_buffer_folded(buffer)
16249    }
16250
16251    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16252        self.display_map.read(cx).folded_buffers()
16253    }
16254
16255    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16256        self.display_map.update(cx, |display_map, cx| {
16257            display_map.disable_header_for_buffer(buffer_id, cx);
16258        });
16259        cx.notify();
16260    }
16261
16262    /// Removes any folds with the given ranges.
16263    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16264        &mut self,
16265        ranges: &[Range<T>],
16266        type_id: TypeId,
16267        auto_scroll: bool,
16268        cx: &mut Context<Self>,
16269    ) {
16270        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16271            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16272        });
16273        self.folds_did_change(cx);
16274    }
16275
16276    fn remove_folds_with<T: ToOffset + Clone>(
16277        &mut self,
16278        ranges: &[Range<T>],
16279        auto_scroll: bool,
16280        cx: &mut Context<Self>,
16281        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16282    ) {
16283        if ranges.is_empty() {
16284            return;
16285        }
16286
16287        let mut buffers_affected = HashSet::default();
16288        let multi_buffer = self.buffer().read(cx);
16289        for range in ranges {
16290            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16291                buffers_affected.insert(buffer.read(cx).remote_id());
16292            };
16293        }
16294
16295        self.display_map.update(cx, update);
16296
16297        if auto_scroll {
16298            self.request_autoscroll(Autoscroll::fit(), cx);
16299        }
16300
16301        cx.notify();
16302        self.scrollbar_marker_state.dirty = true;
16303        self.active_indent_guides_state.dirty = true;
16304    }
16305
16306    pub fn update_fold_widths(
16307        &mut self,
16308        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16309        cx: &mut Context<Self>,
16310    ) -> bool {
16311        self.display_map
16312            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16313    }
16314
16315    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16316        self.display_map.read(cx).fold_placeholder.clone()
16317    }
16318
16319    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16320        self.buffer.update(cx, |buffer, cx| {
16321            buffer.set_all_diff_hunks_expanded(cx);
16322        });
16323    }
16324
16325    pub fn expand_all_diff_hunks(
16326        &mut self,
16327        _: &ExpandAllDiffHunks,
16328        _window: &mut Window,
16329        cx: &mut Context<Self>,
16330    ) {
16331        self.buffer.update(cx, |buffer, cx| {
16332            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16333        });
16334    }
16335
16336    pub fn toggle_selected_diff_hunks(
16337        &mut self,
16338        _: &ToggleSelectedDiffHunks,
16339        _window: &mut Window,
16340        cx: &mut Context<Self>,
16341    ) {
16342        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16343        self.toggle_diff_hunks_in_ranges(ranges, cx);
16344    }
16345
16346    pub fn diff_hunks_in_ranges<'a>(
16347        &'a self,
16348        ranges: &'a [Range<Anchor>],
16349        buffer: &'a MultiBufferSnapshot,
16350    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16351        ranges.iter().flat_map(move |range| {
16352            let end_excerpt_id = range.end.excerpt_id;
16353            let range = range.to_point(buffer);
16354            let mut peek_end = range.end;
16355            if range.end.row < buffer.max_row().0 {
16356                peek_end = Point::new(range.end.row + 1, 0);
16357            }
16358            buffer
16359                .diff_hunks_in_range(range.start..peek_end)
16360                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16361        })
16362    }
16363
16364    pub fn has_stageable_diff_hunks_in_ranges(
16365        &self,
16366        ranges: &[Range<Anchor>],
16367        snapshot: &MultiBufferSnapshot,
16368    ) -> bool {
16369        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16370        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16371    }
16372
16373    pub fn toggle_staged_selected_diff_hunks(
16374        &mut self,
16375        _: &::git::ToggleStaged,
16376        _: &mut Window,
16377        cx: &mut Context<Self>,
16378    ) {
16379        let snapshot = self.buffer.read(cx).snapshot(cx);
16380        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16381        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16382        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16383    }
16384
16385    pub fn set_render_diff_hunk_controls(
16386        &mut self,
16387        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16388        cx: &mut Context<Self>,
16389    ) {
16390        self.render_diff_hunk_controls = render_diff_hunk_controls;
16391        cx.notify();
16392    }
16393
16394    pub fn stage_and_next(
16395        &mut self,
16396        _: &::git::StageAndNext,
16397        window: &mut Window,
16398        cx: &mut Context<Self>,
16399    ) {
16400        self.do_stage_or_unstage_and_next(true, window, cx);
16401    }
16402
16403    pub fn unstage_and_next(
16404        &mut self,
16405        _: &::git::UnstageAndNext,
16406        window: &mut Window,
16407        cx: &mut Context<Self>,
16408    ) {
16409        self.do_stage_or_unstage_and_next(false, window, cx);
16410    }
16411
16412    pub fn stage_or_unstage_diff_hunks(
16413        &mut self,
16414        stage: bool,
16415        ranges: Vec<Range<Anchor>>,
16416        cx: &mut Context<Self>,
16417    ) {
16418        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16419        cx.spawn(async move |this, cx| {
16420            task.await?;
16421            this.update(cx, |this, cx| {
16422                let snapshot = this.buffer.read(cx).snapshot(cx);
16423                let chunk_by = this
16424                    .diff_hunks_in_ranges(&ranges, &snapshot)
16425                    .chunk_by(|hunk| hunk.buffer_id);
16426                for (buffer_id, hunks) in &chunk_by {
16427                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16428                }
16429            })
16430        })
16431        .detach_and_log_err(cx);
16432    }
16433
16434    fn save_buffers_for_ranges_if_needed(
16435        &mut self,
16436        ranges: &[Range<Anchor>],
16437        cx: &mut Context<Editor>,
16438    ) -> Task<Result<()>> {
16439        let multibuffer = self.buffer.read(cx);
16440        let snapshot = multibuffer.read(cx);
16441        let buffer_ids: HashSet<_> = ranges
16442            .iter()
16443            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16444            .collect();
16445        drop(snapshot);
16446
16447        let mut buffers = HashSet::default();
16448        for buffer_id in buffer_ids {
16449            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16450                let buffer = buffer_entity.read(cx);
16451                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16452                {
16453                    buffers.insert(buffer_entity);
16454                }
16455            }
16456        }
16457
16458        if let Some(project) = &self.project {
16459            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16460        } else {
16461            Task::ready(Ok(()))
16462        }
16463    }
16464
16465    fn do_stage_or_unstage_and_next(
16466        &mut self,
16467        stage: bool,
16468        window: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) {
16471        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16472
16473        if ranges.iter().any(|range| range.start != range.end) {
16474            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16475            return;
16476        }
16477
16478        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16479        let snapshot = self.snapshot(window, cx);
16480        let position = self.selections.newest::<Point>(cx).head();
16481        let mut row = snapshot
16482            .buffer_snapshot
16483            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16484            .find(|hunk| hunk.row_range.start.0 > position.row)
16485            .map(|hunk| hunk.row_range.start);
16486
16487        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16488        // Outside of the project diff editor, wrap around to the beginning.
16489        if !all_diff_hunks_expanded {
16490            row = row.or_else(|| {
16491                snapshot
16492                    .buffer_snapshot
16493                    .diff_hunks_in_range(Point::zero()..position)
16494                    .find(|hunk| hunk.row_range.end.0 < position.row)
16495                    .map(|hunk| hunk.row_range.start)
16496            });
16497        }
16498
16499        if let Some(row) = row {
16500            let destination = Point::new(row.0, 0);
16501            let autoscroll = Autoscroll::center();
16502
16503            self.unfold_ranges(&[destination..destination], false, false, cx);
16504            self.change_selections(Some(autoscroll), window, cx, |s| {
16505                s.select_ranges([destination..destination]);
16506            });
16507        }
16508    }
16509
16510    fn do_stage_or_unstage(
16511        &self,
16512        stage: bool,
16513        buffer_id: BufferId,
16514        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16515        cx: &mut App,
16516    ) -> Option<()> {
16517        let project = self.project.as_ref()?;
16518        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16519        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16520        let buffer_snapshot = buffer.read(cx).snapshot();
16521        let file_exists = buffer_snapshot
16522            .file()
16523            .is_some_and(|file| file.disk_state().exists());
16524        diff.update(cx, |diff, cx| {
16525            diff.stage_or_unstage_hunks(
16526                stage,
16527                &hunks
16528                    .map(|hunk| buffer_diff::DiffHunk {
16529                        buffer_range: hunk.buffer_range,
16530                        diff_base_byte_range: hunk.diff_base_byte_range,
16531                        secondary_status: hunk.secondary_status,
16532                        range: Point::zero()..Point::zero(), // unused
16533                    })
16534                    .collect::<Vec<_>>(),
16535                &buffer_snapshot,
16536                file_exists,
16537                cx,
16538            )
16539        });
16540        None
16541    }
16542
16543    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16544        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16545        self.buffer
16546            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16547    }
16548
16549    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16550        self.buffer.update(cx, |buffer, cx| {
16551            let ranges = vec![Anchor::min()..Anchor::max()];
16552            if !buffer.all_diff_hunks_expanded()
16553                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16554            {
16555                buffer.collapse_diff_hunks(ranges, cx);
16556                true
16557            } else {
16558                false
16559            }
16560        })
16561    }
16562
16563    fn toggle_diff_hunks_in_ranges(
16564        &mut self,
16565        ranges: Vec<Range<Anchor>>,
16566        cx: &mut Context<Editor>,
16567    ) {
16568        self.buffer.update(cx, |buffer, cx| {
16569            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16570            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16571        })
16572    }
16573
16574    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16575        self.buffer.update(cx, |buffer, cx| {
16576            let snapshot = buffer.snapshot(cx);
16577            let excerpt_id = range.end.excerpt_id;
16578            let point_range = range.to_point(&snapshot);
16579            let expand = !buffer.single_hunk_is_expanded(range, cx);
16580            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16581        })
16582    }
16583
16584    pub(crate) fn apply_all_diff_hunks(
16585        &mut self,
16586        _: &ApplyAllDiffHunks,
16587        window: &mut Window,
16588        cx: &mut Context<Self>,
16589    ) {
16590        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16591
16592        let buffers = self.buffer.read(cx).all_buffers();
16593        for branch_buffer in buffers {
16594            branch_buffer.update(cx, |branch_buffer, cx| {
16595                branch_buffer.merge_into_base(Vec::new(), cx);
16596            });
16597        }
16598
16599        if let Some(project) = self.project.clone() {
16600            self.save(true, project, window, cx).detach_and_log_err(cx);
16601        }
16602    }
16603
16604    pub(crate) fn apply_selected_diff_hunks(
16605        &mut self,
16606        _: &ApplyDiffHunk,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) {
16610        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16611        let snapshot = self.snapshot(window, cx);
16612        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16613        let mut ranges_by_buffer = HashMap::default();
16614        self.transact(window, cx, |editor, _window, cx| {
16615            for hunk in hunks {
16616                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16617                    ranges_by_buffer
16618                        .entry(buffer.clone())
16619                        .or_insert_with(Vec::new)
16620                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16621                }
16622            }
16623
16624            for (buffer, ranges) in ranges_by_buffer {
16625                buffer.update(cx, |buffer, cx| {
16626                    buffer.merge_into_base(ranges, cx);
16627                });
16628            }
16629        });
16630
16631        if let Some(project) = self.project.clone() {
16632            self.save(true, project, window, cx).detach_and_log_err(cx);
16633        }
16634    }
16635
16636    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16637        if hovered != self.gutter_hovered {
16638            self.gutter_hovered = hovered;
16639            cx.notify();
16640        }
16641    }
16642
16643    pub fn insert_blocks(
16644        &mut self,
16645        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16646        autoscroll: Option<Autoscroll>,
16647        cx: &mut Context<Self>,
16648    ) -> Vec<CustomBlockId> {
16649        let blocks = self
16650            .display_map
16651            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16652        if let Some(autoscroll) = autoscroll {
16653            self.request_autoscroll(autoscroll, cx);
16654        }
16655        cx.notify();
16656        blocks
16657    }
16658
16659    pub fn resize_blocks(
16660        &mut self,
16661        heights: HashMap<CustomBlockId, u32>,
16662        autoscroll: Option<Autoscroll>,
16663        cx: &mut Context<Self>,
16664    ) {
16665        self.display_map
16666            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16667        if let Some(autoscroll) = autoscroll {
16668            self.request_autoscroll(autoscroll, cx);
16669        }
16670        cx.notify();
16671    }
16672
16673    pub fn replace_blocks(
16674        &mut self,
16675        renderers: HashMap<CustomBlockId, RenderBlock>,
16676        autoscroll: Option<Autoscroll>,
16677        cx: &mut Context<Self>,
16678    ) {
16679        self.display_map
16680            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16681        if let Some(autoscroll) = autoscroll {
16682            self.request_autoscroll(autoscroll, cx);
16683        }
16684        cx.notify();
16685    }
16686
16687    pub fn remove_blocks(
16688        &mut self,
16689        block_ids: HashSet<CustomBlockId>,
16690        autoscroll: Option<Autoscroll>,
16691        cx: &mut Context<Self>,
16692    ) {
16693        self.display_map.update(cx, |display_map, cx| {
16694            display_map.remove_blocks(block_ids, cx)
16695        });
16696        if let Some(autoscroll) = autoscroll {
16697            self.request_autoscroll(autoscroll, cx);
16698        }
16699        cx.notify();
16700    }
16701
16702    pub fn row_for_block(
16703        &self,
16704        block_id: CustomBlockId,
16705        cx: &mut Context<Self>,
16706    ) -> Option<DisplayRow> {
16707        self.display_map
16708            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16709    }
16710
16711    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16712        self.focused_block = Some(focused_block);
16713    }
16714
16715    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16716        self.focused_block.take()
16717    }
16718
16719    pub fn insert_creases(
16720        &mut self,
16721        creases: impl IntoIterator<Item = Crease<Anchor>>,
16722        cx: &mut Context<Self>,
16723    ) -> Vec<CreaseId> {
16724        self.display_map
16725            .update(cx, |map, cx| map.insert_creases(creases, cx))
16726    }
16727
16728    pub fn remove_creases(
16729        &mut self,
16730        ids: impl IntoIterator<Item = CreaseId>,
16731        cx: &mut Context<Self>,
16732    ) -> Vec<(CreaseId, Range<Anchor>)> {
16733        self.display_map
16734            .update(cx, |map, cx| map.remove_creases(ids, cx))
16735    }
16736
16737    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16738        self.display_map
16739            .update(cx, |map, cx| map.snapshot(cx))
16740            .longest_row()
16741    }
16742
16743    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16744        self.display_map
16745            .update(cx, |map, cx| map.snapshot(cx))
16746            .max_point()
16747    }
16748
16749    pub fn text(&self, cx: &App) -> String {
16750        self.buffer.read(cx).read(cx).text()
16751    }
16752
16753    pub fn is_empty(&self, cx: &App) -> bool {
16754        self.buffer.read(cx).read(cx).is_empty()
16755    }
16756
16757    pub fn text_option(&self, cx: &App) -> Option<String> {
16758        let text = self.text(cx);
16759        let text = text.trim();
16760
16761        if text.is_empty() {
16762            return None;
16763        }
16764
16765        Some(text.to_string())
16766    }
16767
16768    pub fn set_text(
16769        &mut self,
16770        text: impl Into<Arc<str>>,
16771        window: &mut Window,
16772        cx: &mut Context<Self>,
16773    ) {
16774        self.transact(window, cx, |this, _, cx| {
16775            this.buffer
16776                .read(cx)
16777                .as_singleton()
16778                .expect("you can only call set_text on editors for singleton buffers")
16779                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16780        });
16781    }
16782
16783    pub fn display_text(&self, cx: &mut App) -> String {
16784        self.display_map
16785            .update(cx, |map, cx| map.snapshot(cx))
16786            .text()
16787    }
16788
16789    fn create_minimap(
16790        &self,
16791        minimap_settings: MinimapSettings,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) -> Option<Entity<Self>> {
16795        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16796            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16797    }
16798
16799    fn initialize_new_minimap(
16800        &self,
16801        minimap_settings: MinimapSettings,
16802        window: &mut Window,
16803        cx: &mut Context<Self>,
16804    ) -> Entity<Self> {
16805        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16806
16807        let mut minimap = Editor::new_internal(
16808            EditorMode::Minimap {
16809                parent: cx.weak_entity(),
16810            },
16811            self.buffer.clone(),
16812            self.project.clone(),
16813            Some(self.display_map.clone()),
16814            window,
16815            cx,
16816        );
16817        minimap.scroll_manager.clone_state(&self.scroll_manager);
16818        minimap.set_text_style_refinement(TextStyleRefinement {
16819            font_size: Some(MINIMAP_FONT_SIZE),
16820            font_weight: Some(MINIMAP_FONT_WEIGHT),
16821            ..Default::default()
16822        });
16823        minimap.update_minimap_configuration(minimap_settings, cx);
16824        cx.new(|_| minimap)
16825    }
16826
16827    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16828        let current_line_highlight = minimap_settings
16829            .current_line_highlight
16830            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16831        self.set_current_line_highlight(Some(current_line_highlight));
16832    }
16833
16834    pub fn minimap(&self) -> Option<&Entity<Self>> {
16835        self.minimap
16836            .as_ref()
16837            .filter(|_| self.minimap_visibility.visible())
16838    }
16839
16840    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16841        let mut wrap_guides = smallvec![];
16842
16843        if self.show_wrap_guides == Some(false) {
16844            return wrap_guides;
16845        }
16846
16847        let settings = self.buffer.read(cx).language_settings(cx);
16848        if settings.show_wrap_guides {
16849            match self.soft_wrap_mode(cx) {
16850                SoftWrap::Column(soft_wrap) => {
16851                    wrap_guides.push((soft_wrap as usize, true));
16852                }
16853                SoftWrap::Bounded(soft_wrap) => {
16854                    wrap_guides.push((soft_wrap as usize, true));
16855                }
16856                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16857            }
16858            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16859        }
16860
16861        wrap_guides
16862    }
16863
16864    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16865        let settings = self.buffer.read(cx).language_settings(cx);
16866        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16867        match mode {
16868            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16869                SoftWrap::None
16870            }
16871            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16872            language_settings::SoftWrap::PreferredLineLength => {
16873                SoftWrap::Column(settings.preferred_line_length)
16874            }
16875            language_settings::SoftWrap::Bounded => {
16876                SoftWrap::Bounded(settings.preferred_line_length)
16877            }
16878        }
16879    }
16880
16881    pub fn set_soft_wrap_mode(
16882        &mut self,
16883        mode: language_settings::SoftWrap,
16884
16885        cx: &mut Context<Self>,
16886    ) {
16887        self.soft_wrap_mode_override = Some(mode);
16888        cx.notify();
16889    }
16890
16891    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16892        self.hard_wrap = hard_wrap;
16893        cx.notify();
16894    }
16895
16896    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16897        self.text_style_refinement = Some(style);
16898    }
16899
16900    /// called by the Element so we know what style we were most recently rendered with.
16901    pub(crate) fn set_style(
16902        &mut self,
16903        style: EditorStyle,
16904        window: &mut Window,
16905        cx: &mut Context<Self>,
16906    ) {
16907        // We intentionally do not inform the display map about the minimap style
16908        // so that wrapping is not recalculated and stays consistent for the editor
16909        // and its linked minimap.
16910        if !self.mode.is_minimap() {
16911            let rem_size = window.rem_size();
16912            self.display_map.update(cx, |map, cx| {
16913                map.set_font(
16914                    style.text.font(),
16915                    style.text.font_size.to_pixels(rem_size),
16916                    cx,
16917                )
16918            });
16919        }
16920        self.style = Some(style);
16921    }
16922
16923    pub fn style(&self) -> Option<&EditorStyle> {
16924        self.style.as_ref()
16925    }
16926
16927    // Called by the element. This method is not designed to be called outside of the editor
16928    // element's layout code because it does not notify when rewrapping is computed synchronously.
16929    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16930        self.display_map
16931            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16932    }
16933
16934    pub fn set_soft_wrap(&mut self) {
16935        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16936    }
16937
16938    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16939        if self.soft_wrap_mode_override.is_some() {
16940            self.soft_wrap_mode_override.take();
16941        } else {
16942            let soft_wrap = match self.soft_wrap_mode(cx) {
16943                SoftWrap::GitDiff => return,
16944                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16945                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16946                    language_settings::SoftWrap::None
16947                }
16948            };
16949            self.soft_wrap_mode_override = Some(soft_wrap);
16950        }
16951        cx.notify();
16952    }
16953
16954    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16955        let Some(workspace) = self.workspace() else {
16956            return;
16957        };
16958        let fs = workspace.read(cx).app_state().fs.clone();
16959        let current_show = TabBarSettings::get_global(cx).show;
16960        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16961            setting.show = Some(!current_show);
16962        });
16963    }
16964
16965    pub fn toggle_indent_guides(
16966        &mut self,
16967        _: &ToggleIndentGuides,
16968        _: &mut Window,
16969        cx: &mut Context<Self>,
16970    ) {
16971        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16972            self.buffer
16973                .read(cx)
16974                .language_settings(cx)
16975                .indent_guides
16976                .enabled
16977        });
16978        self.show_indent_guides = Some(!currently_enabled);
16979        cx.notify();
16980    }
16981
16982    fn should_show_indent_guides(&self) -> Option<bool> {
16983        self.show_indent_guides
16984    }
16985
16986    pub fn toggle_line_numbers(
16987        &mut self,
16988        _: &ToggleLineNumbers,
16989        _: &mut Window,
16990        cx: &mut Context<Self>,
16991    ) {
16992        let mut editor_settings = EditorSettings::get_global(cx).clone();
16993        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16994        EditorSettings::override_global(editor_settings, cx);
16995    }
16996
16997    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16998        if let Some(show_line_numbers) = self.show_line_numbers {
16999            return show_line_numbers;
17000        }
17001        EditorSettings::get_global(cx).gutter.line_numbers
17002    }
17003
17004    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17005        self.use_relative_line_numbers
17006            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17007    }
17008
17009    pub fn toggle_relative_line_numbers(
17010        &mut self,
17011        _: &ToggleRelativeLineNumbers,
17012        _: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) {
17015        let is_relative = self.should_use_relative_line_numbers(cx);
17016        self.set_relative_line_number(Some(!is_relative), cx)
17017    }
17018
17019    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17020        self.use_relative_line_numbers = is_relative;
17021        cx.notify();
17022    }
17023
17024    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17025        self.show_gutter = show_gutter;
17026        cx.notify();
17027    }
17028
17029    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17030        self.show_scrollbars = ScrollbarAxes {
17031            horizontal: show,
17032            vertical: show,
17033        };
17034        cx.notify();
17035    }
17036
17037    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17038        self.show_scrollbars.vertical = show;
17039        cx.notify();
17040    }
17041
17042    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17043        self.show_scrollbars.horizontal = show;
17044        cx.notify();
17045    }
17046
17047    pub fn set_minimap_visibility(
17048        &mut self,
17049        minimap_visibility: MinimapVisibility,
17050        window: &mut Window,
17051        cx: &mut Context<Self>,
17052    ) {
17053        if self.minimap_visibility != minimap_visibility {
17054            if minimap_visibility.visible() && self.minimap.is_none() {
17055                let minimap_settings = EditorSettings::get_global(cx).minimap;
17056                self.minimap =
17057                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17058            }
17059            self.minimap_visibility = minimap_visibility;
17060            cx.notify();
17061        }
17062    }
17063
17064    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17065        self.set_show_scrollbars(false, cx);
17066        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17067    }
17068
17069    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17070        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17071    }
17072
17073    /// Normally the text in full mode and auto height editors is padded on the
17074    /// left side by roughly half a character width for improved hit testing.
17075    ///
17076    /// Use this method to disable this for cases where this is not wanted (e.g.
17077    /// if you want to align the editor text with some other text above or below)
17078    /// or if you want to add this padding to single-line editors.
17079    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17080        self.offset_content = offset_content;
17081        cx.notify();
17082    }
17083
17084    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17085        self.show_line_numbers = Some(show_line_numbers);
17086        cx.notify();
17087    }
17088
17089    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17090        self.disable_expand_excerpt_buttons = true;
17091        cx.notify();
17092    }
17093
17094    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17095        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17096        cx.notify();
17097    }
17098
17099    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17100        self.show_code_actions = Some(show_code_actions);
17101        cx.notify();
17102    }
17103
17104    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17105        self.show_runnables = Some(show_runnables);
17106        cx.notify();
17107    }
17108
17109    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17110        self.show_breakpoints = Some(show_breakpoints);
17111        cx.notify();
17112    }
17113
17114    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17115        if self.display_map.read(cx).masked != masked {
17116            self.display_map.update(cx, |map, _| map.masked = masked);
17117        }
17118        cx.notify()
17119    }
17120
17121    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17122        self.show_wrap_guides = Some(show_wrap_guides);
17123        cx.notify();
17124    }
17125
17126    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17127        self.show_indent_guides = Some(show_indent_guides);
17128        cx.notify();
17129    }
17130
17131    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17132        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17133            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17134                if let Some(dir) = file.abs_path(cx).parent() {
17135                    return Some(dir.to_owned());
17136                }
17137            }
17138
17139            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17140                return Some(project_path.path.to_path_buf());
17141            }
17142        }
17143
17144        None
17145    }
17146
17147    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17148        self.active_excerpt(cx)?
17149            .1
17150            .read(cx)
17151            .file()
17152            .and_then(|f| f.as_local())
17153    }
17154
17155    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17156        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17157            let buffer = buffer.read(cx);
17158            if let Some(project_path) = buffer.project_path(cx) {
17159                let project = self.project.as_ref()?.read(cx);
17160                project.absolute_path(&project_path, cx)
17161            } else {
17162                buffer
17163                    .file()
17164                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17165            }
17166        })
17167    }
17168
17169    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17170        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17171            let project_path = buffer.read(cx).project_path(cx)?;
17172            let project = self.project.as_ref()?.read(cx);
17173            let entry = project.entry_for_path(&project_path, cx)?;
17174            let path = entry.path.to_path_buf();
17175            Some(path)
17176        })
17177    }
17178
17179    pub fn reveal_in_finder(
17180        &mut self,
17181        _: &RevealInFileManager,
17182        _window: &mut Window,
17183        cx: &mut Context<Self>,
17184    ) {
17185        if let Some(target) = self.target_file(cx) {
17186            cx.reveal_path(&target.abs_path(cx));
17187        }
17188    }
17189
17190    pub fn copy_path(
17191        &mut self,
17192        _: &zed_actions::workspace::CopyPath,
17193        _window: &mut Window,
17194        cx: &mut Context<Self>,
17195    ) {
17196        if let Some(path) = self.target_file_abs_path(cx) {
17197            if let Some(path) = path.to_str() {
17198                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17199            }
17200        }
17201    }
17202
17203    pub fn copy_relative_path(
17204        &mut self,
17205        _: &zed_actions::workspace::CopyRelativePath,
17206        _window: &mut Window,
17207        cx: &mut Context<Self>,
17208    ) {
17209        if let Some(path) = self.target_file_path(cx) {
17210            if let Some(path) = path.to_str() {
17211                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17212            }
17213        }
17214    }
17215
17216    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17217        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17218            buffer.read(cx).project_path(cx)
17219        } else {
17220            None
17221        }
17222    }
17223
17224    // Returns true if the editor handled a go-to-line request
17225    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17226        maybe!({
17227            let breakpoint_store = self.breakpoint_store.as_ref()?;
17228
17229            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17230            else {
17231                self.clear_row_highlights::<ActiveDebugLine>();
17232                return None;
17233            };
17234
17235            let position = active_stack_frame.position;
17236            let buffer_id = position.buffer_id?;
17237            let snapshot = self
17238                .project
17239                .as_ref()?
17240                .read(cx)
17241                .buffer_for_id(buffer_id, cx)?
17242                .read(cx)
17243                .snapshot();
17244
17245            let mut handled = false;
17246            for (id, ExcerptRange { context, .. }) in
17247                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17248            {
17249                if context.start.cmp(&position, &snapshot).is_ge()
17250                    || context.end.cmp(&position, &snapshot).is_lt()
17251                {
17252                    continue;
17253                }
17254                let snapshot = self.buffer.read(cx).snapshot(cx);
17255                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17256
17257                handled = true;
17258                self.clear_row_highlights::<ActiveDebugLine>();
17259
17260                self.go_to_line::<ActiveDebugLine>(
17261                    multibuffer_anchor,
17262                    Some(cx.theme().colors().editor_debugger_active_line_background),
17263                    window,
17264                    cx,
17265                );
17266
17267                cx.notify();
17268            }
17269
17270            handled.then_some(())
17271        })
17272        .is_some()
17273    }
17274
17275    pub fn copy_file_name_without_extension(
17276        &mut self,
17277        _: &CopyFileNameWithoutExtension,
17278        _: &mut Window,
17279        cx: &mut Context<Self>,
17280    ) {
17281        if let Some(file) = self.target_file(cx) {
17282            if let Some(file_stem) = file.path().file_stem() {
17283                if let Some(name) = file_stem.to_str() {
17284                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17285                }
17286            }
17287        }
17288    }
17289
17290    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17291        if let Some(file) = self.target_file(cx) {
17292            if let Some(file_name) = file.path().file_name() {
17293                if let Some(name) = file_name.to_str() {
17294                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17295                }
17296            }
17297        }
17298    }
17299
17300    pub fn toggle_git_blame(
17301        &mut self,
17302        _: &::git::Blame,
17303        window: &mut Window,
17304        cx: &mut Context<Self>,
17305    ) {
17306        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17307
17308        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17309            self.start_git_blame(true, window, cx);
17310        }
17311
17312        cx.notify();
17313    }
17314
17315    pub fn toggle_git_blame_inline(
17316        &mut self,
17317        _: &ToggleGitBlameInline,
17318        window: &mut Window,
17319        cx: &mut Context<Self>,
17320    ) {
17321        self.toggle_git_blame_inline_internal(true, window, cx);
17322        cx.notify();
17323    }
17324
17325    pub fn open_git_blame_commit(
17326        &mut self,
17327        _: &OpenGitBlameCommit,
17328        window: &mut Window,
17329        cx: &mut Context<Self>,
17330    ) {
17331        self.open_git_blame_commit_internal(window, cx);
17332    }
17333
17334    fn open_git_blame_commit_internal(
17335        &mut self,
17336        window: &mut Window,
17337        cx: &mut Context<Self>,
17338    ) -> Option<()> {
17339        let blame = self.blame.as_ref()?;
17340        let snapshot = self.snapshot(window, cx);
17341        let cursor = self.selections.newest::<Point>(cx).head();
17342        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17343        let blame_entry = blame
17344            .update(cx, |blame, cx| {
17345                blame
17346                    .blame_for_rows(
17347                        &[RowInfo {
17348                            buffer_id: Some(buffer.remote_id()),
17349                            buffer_row: Some(point.row),
17350                            ..Default::default()
17351                        }],
17352                        cx,
17353                    )
17354                    .next()
17355            })
17356            .flatten()?;
17357        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17358        let repo = blame.read(cx).repository(cx)?;
17359        let workspace = self.workspace()?.downgrade();
17360        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17361        None
17362    }
17363
17364    pub fn git_blame_inline_enabled(&self) -> bool {
17365        self.git_blame_inline_enabled
17366    }
17367
17368    pub fn toggle_selection_menu(
17369        &mut self,
17370        _: &ToggleSelectionMenu,
17371        _: &mut Window,
17372        cx: &mut Context<Self>,
17373    ) {
17374        self.show_selection_menu = self
17375            .show_selection_menu
17376            .map(|show_selections_menu| !show_selections_menu)
17377            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17378
17379        cx.notify();
17380    }
17381
17382    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17383        self.show_selection_menu
17384            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17385    }
17386
17387    fn start_git_blame(
17388        &mut self,
17389        user_triggered: bool,
17390        window: &mut Window,
17391        cx: &mut Context<Self>,
17392    ) {
17393        if let Some(project) = self.project.as_ref() {
17394            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17395                return;
17396            };
17397
17398            if buffer.read(cx).file().is_none() {
17399                return;
17400            }
17401
17402            let focused = self.focus_handle(cx).contains_focused(window, cx);
17403
17404            let project = project.clone();
17405            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17406            self.blame_subscription =
17407                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17408            self.blame = Some(blame);
17409        }
17410    }
17411
17412    fn toggle_git_blame_inline_internal(
17413        &mut self,
17414        user_triggered: bool,
17415        window: &mut Window,
17416        cx: &mut Context<Self>,
17417    ) {
17418        if self.git_blame_inline_enabled {
17419            self.git_blame_inline_enabled = false;
17420            self.show_git_blame_inline = false;
17421            self.show_git_blame_inline_delay_task.take();
17422        } else {
17423            self.git_blame_inline_enabled = true;
17424            self.start_git_blame_inline(user_triggered, window, cx);
17425        }
17426
17427        cx.notify();
17428    }
17429
17430    fn start_git_blame_inline(
17431        &mut self,
17432        user_triggered: bool,
17433        window: &mut Window,
17434        cx: &mut Context<Self>,
17435    ) {
17436        self.start_git_blame(user_triggered, window, cx);
17437
17438        if ProjectSettings::get_global(cx)
17439            .git
17440            .inline_blame_delay()
17441            .is_some()
17442        {
17443            self.start_inline_blame_timer(window, cx);
17444        } else {
17445            self.show_git_blame_inline = true
17446        }
17447    }
17448
17449    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17450        self.blame.as_ref()
17451    }
17452
17453    pub fn show_git_blame_gutter(&self) -> bool {
17454        self.show_git_blame_gutter
17455    }
17456
17457    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17458        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17459    }
17460
17461    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17462        self.show_git_blame_inline
17463            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17464            && !self.newest_selection_head_on_empty_line(cx)
17465            && self.has_blame_entries(cx)
17466    }
17467
17468    fn has_blame_entries(&self, cx: &App) -> bool {
17469        self.blame()
17470            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17471    }
17472
17473    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17474        let cursor_anchor = self.selections.newest_anchor().head();
17475
17476        let snapshot = self.buffer.read(cx).snapshot(cx);
17477        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17478
17479        snapshot.line_len(buffer_row) == 0
17480    }
17481
17482    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17483        let buffer_and_selection = maybe!({
17484            let selection = self.selections.newest::<Point>(cx);
17485            let selection_range = selection.range();
17486
17487            let multi_buffer = self.buffer().read(cx);
17488            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17489            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17490
17491            let (buffer, range, _) = if selection.reversed {
17492                buffer_ranges.first()
17493            } else {
17494                buffer_ranges.last()
17495            }?;
17496
17497            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17498                ..text::ToPoint::to_point(&range.end, &buffer).row;
17499            Some((
17500                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17501                selection,
17502            ))
17503        });
17504
17505        let Some((buffer, selection)) = buffer_and_selection else {
17506            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17507        };
17508
17509        let Some(project) = self.project.as_ref() else {
17510            return Task::ready(Err(anyhow!("editor does not have project")));
17511        };
17512
17513        project.update(cx, |project, cx| {
17514            project.get_permalink_to_line(&buffer, selection, cx)
17515        })
17516    }
17517
17518    pub fn copy_permalink_to_line(
17519        &mut self,
17520        _: &CopyPermalinkToLine,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) {
17524        let permalink_task = self.get_permalink_to_line(cx);
17525        let workspace = self.workspace();
17526
17527        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17528            Ok(permalink) => {
17529                cx.update(|_, cx| {
17530                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17531                })
17532                .ok();
17533            }
17534            Err(err) => {
17535                let message = format!("Failed to copy permalink: {err}");
17536
17537                anyhow::Result::<()>::Err(err).log_err();
17538
17539                if let Some(workspace) = workspace {
17540                    workspace
17541                        .update_in(cx, |workspace, _, cx| {
17542                            struct CopyPermalinkToLine;
17543
17544                            workspace.show_toast(
17545                                Toast::new(
17546                                    NotificationId::unique::<CopyPermalinkToLine>(),
17547                                    message,
17548                                ),
17549                                cx,
17550                            )
17551                        })
17552                        .ok();
17553                }
17554            }
17555        })
17556        .detach();
17557    }
17558
17559    pub fn copy_file_location(
17560        &mut self,
17561        _: &CopyFileLocation,
17562        _: &mut Window,
17563        cx: &mut Context<Self>,
17564    ) {
17565        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17566        if let Some(file) = self.target_file(cx) {
17567            if let Some(path) = file.path().to_str() {
17568                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17569            }
17570        }
17571    }
17572
17573    pub fn open_permalink_to_line(
17574        &mut self,
17575        _: &OpenPermalinkToLine,
17576        window: &mut Window,
17577        cx: &mut Context<Self>,
17578    ) {
17579        let permalink_task = self.get_permalink_to_line(cx);
17580        let workspace = self.workspace();
17581
17582        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17583            Ok(permalink) => {
17584                cx.update(|_, cx| {
17585                    cx.open_url(permalink.as_ref());
17586                })
17587                .ok();
17588            }
17589            Err(err) => {
17590                let message = format!("Failed to open permalink: {err}");
17591
17592                anyhow::Result::<()>::Err(err).log_err();
17593
17594                if let Some(workspace) = workspace {
17595                    workspace
17596                        .update(cx, |workspace, cx| {
17597                            struct OpenPermalinkToLine;
17598
17599                            workspace.show_toast(
17600                                Toast::new(
17601                                    NotificationId::unique::<OpenPermalinkToLine>(),
17602                                    message,
17603                                ),
17604                                cx,
17605                            )
17606                        })
17607                        .ok();
17608                }
17609            }
17610        })
17611        .detach();
17612    }
17613
17614    pub fn insert_uuid_v4(
17615        &mut self,
17616        _: &InsertUuidV4,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        self.insert_uuid(UuidVersion::V4, window, cx);
17621    }
17622
17623    pub fn insert_uuid_v7(
17624        &mut self,
17625        _: &InsertUuidV7,
17626        window: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        self.insert_uuid(UuidVersion::V7, window, cx);
17630    }
17631
17632    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17633        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17634        self.transact(window, cx, |this, window, cx| {
17635            let edits = this
17636                .selections
17637                .all::<Point>(cx)
17638                .into_iter()
17639                .map(|selection| {
17640                    let uuid = match version {
17641                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17642                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17643                    };
17644
17645                    (selection.range(), uuid.to_string())
17646                });
17647            this.edit(edits, cx);
17648            this.refresh_inline_completion(true, false, window, cx);
17649        });
17650    }
17651
17652    pub fn open_selections_in_multibuffer(
17653        &mut self,
17654        _: &OpenSelectionsInMultibuffer,
17655        window: &mut Window,
17656        cx: &mut Context<Self>,
17657    ) {
17658        let multibuffer = self.buffer.read(cx);
17659
17660        let Some(buffer) = multibuffer.as_singleton() else {
17661            return;
17662        };
17663
17664        let Some(workspace) = self.workspace() else {
17665            return;
17666        };
17667
17668        let locations = self
17669            .selections
17670            .disjoint_anchors()
17671            .iter()
17672            .map(|selection| {
17673                let range = if selection.reversed {
17674                    selection.end.text_anchor..selection.start.text_anchor
17675                } else {
17676                    selection.start.text_anchor..selection.end.text_anchor
17677                };
17678                Location {
17679                    buffer: buffer.clone(),
17680                    range,
17681                }
17682            })
17683            .collect::<Vec<_>>();
17684
17685        let title = multibuffer.title(cx).to_string();
17686
17687        cx.spawn_in(window, async move |_, cx| {
17688            workspace.update_in(cx, |workspace, window, cx| {
17689                Self::open_locations_in_multibuffer(
17690                    workspace,
17691                    locations,
17692                    format!("Selections for '{title}'"),
17693                    false,
17694                    MultibufferSelectionMode::All,
17695                    window,
17696                    cx,
17697                );
17698            })
17699        })
17700        .detach();
17701    }
17702
17703    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17704    /// last highlight added will be used.
17705    ///
17706    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17707    pub fn highlight_rows<T: 'static>(
17708        &mut self,
17709        range: Range<Anchor>,
17710        color: Hsla,
17711        options: RowHighlightOptions,
17712        cx: &mut Context<Self>,
17713    ) {
17714        let snapshot = self.buffer().read(cx).snapshot(cx);
17715        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17716        let ix = row_highlights.binary_search_by(|highlight| {
17717            Ordering::Equal
17718                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17719                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17720        });
17721
17722        if let Err(mut ix) = ix {
17723            let index = post_inc(&mut self.highlight_order);
17724
17725            // If this range intersects with the preceding highlight, then merge it with
17726            // the preceding highlight. Otherwise insert a new highlight.
17727            let mut merged = false;
17728            if ix > 0 {
17729                let prev_highlight = &mut row_highlights[ix - 1];
17730                if prev_highlight
17731                    .range
17732                    .end
17733                    .cmp(&range.start, &snapshot)
17734                    .is_ge()
17735                {
17736                    ix -= 1;
17737                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17738                        prev_highlight.range.end = range.end;
17739                    }
17740                    merged = true;
17741                    prev_highlight.index = index;
17742                    prev_highlight.color = color;
17743                    prev_highlight.options = options;
17744                }
17745            }
17746
17747            if !merged {
17748                row_highlights.insert(
17749                    ix,
17750                    RowHighlight {
17751                        range: range.clone(),
17752                        index,
17753                        color,
17754                        options,
17755                        type_id: TypeId::of::<T>(),
17756                    },
17757                );
17758            }
17759
17760            // If any of the following highlights intersect with this one, merge them.
17761            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17762                let highlight = &row_highlights[ix];
17763                if next_highlight
17764                    .range
17765                    .start
17766                    .cmp(&highlight.range.end, &snapshot)
17767                    .is_le()
17768                {
17769                    if next_highlight
17770                        .range
17771                        .end
17772                        .cmp(&highlight.range.end, &snapshot)
17773                        .is_gt()
17774                    {
17775                        row_highlights[ix].range.end = next_highlight.range.end;
17776                    }
17777                    row_highlights.remove(ix + 1);
17778                } else {
17779                    break;
17780                }
17781            }
17782        }
17783    }
17784
17785    /// Remove any highlighted row ranges of the given type that intersect the
17786    /// given ranges.
17787    pub fn remove_highlighted_rows<T: 'static>(
17788        &mut self,
17789        ranges_to_remove: Vec<Range<Anchor>>,
17790        cx: &mut Context<Self>,
17791    ) {
17792        let snapshot = self.buffer().read(cx).snapshot(cx);
17793        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17794        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17795        row_highlights.retain(|highlight| {
17796            while let Some(range_to_remove) = ranges_to_remove.peek() {
17797                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17798                    Ordering::Less | Ordering::Equal => {
17799                        ranges_to_remove.next();
17800                    }
17801                    Ordering::Greater => {
17802                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17803                            Ordering::Less | Ordering::Equal => {
17804                                return false;
17805                            }
17806                            Ordering::Greater => break,
17807                        }
17808                    }
17809                }
17810            }
17811
17812            true
17813        })
17814    }
17815
17816    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17817    pub fn clear_row_highlights<T: 'static>(&mut self) {
17818        self.highlighted_rows.remove(&TypeId::of::<T>());
17819    }
17820
17821    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17822    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17823        self.highlighted_rows
17824            .get(&TypeId::of::<T>())
17825            .map_or(&[] as &[_], |vec| vec.as_slice())
17826            .iter()
17827            .map(|highlight| (highlight.range.clone(), highlight.color))
17828    }
17829
17830    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17831    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17832    /// Allows to ignore certain kinds of highlights.
17833    pub fn highlighted_display_rows(
17834        &self,
17835        window: &mut Window,
17836        cx: &mut App,
17837    ) -> BTreeMap<DisplayRow, LineHighlight> {
17838        let snapshot = self.snapshot(window, cx);
17839        let mut used_highlight_orders = HashMap::default();
17840        self.highlighted_rows
17841            .iter()
17842            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17843            .fold(
17844                BTreeMap::<DisplayRow, LineHighlight>::new(),
17845                |mut unique_rows, highlight| {
17846                    let start = highlight.range.start.to_display_point(&snapshot);
17847                    let end = highlight.range.end.to_display_point(&snapshot);
17848                    let start_row = start.row().0;
17849                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17850                        && end.column() == 0
17851                    {
17852                        end.row().0.saturating_sub(1)
17853                    } else {
17854                        end.row().0
17855                    };
17856                    for row in start_row..=end_row {
17857                        let used_index =
17858                            used_highlight_orders.entry(row).or_insert(highlight.index);
17859                        if highlight.index >= *used_index {
17860                            *used_index = highlight.index;
17861                            unique_rows.insert(
17862                                DisplayRow(row),
17863                                LineHighlight {
17864                                    include_gutter: highlight.options.include_gutter,
17865                                    border: None,
17866                                    background: highlight.color.into(),
17867                                    type_id: Some(highlight.type_id),
17868                                },
17869                            );
17870                        }
17871                    }
17872                    unique_rows
17873                },
17874            )
17875    }
17876
17877    pub fn highlighted_display_row_for_autoscroll(
17878        &self,
17879        snapshot: &DisplaySnapshot,
17880    ) -> Option<DisplayRow> {
17881        self.highlighted_rows
17882            .values()
17883            .flat_map(|highlighted_rows| highlighted_rows.iter())
17884            .filter_map(|highlight| {
17885                if highlight.options.autoscroll {
17886                    Some(highlight.range.start.to_display_point(snapshot).row())
17887                } else {
17888                    None
17889                }
17890            })
17891            .min()
17892    }
17893
17894    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17895        self.highlight_background::<SearchWithinRange>(
17896            ranges,
17897            |colors| colors.editor_document_highlight_read_background,
17898            cx,
17899        )
17900    }
17901
17902    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17903        self.breadcrumb_header = Some(new_header);
17904    }
17905
17906    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17907        self.clear_background_highlights::<SearchWithinRange>(cx);
17908    }
17909
17910    pub fn highlight_background<T: 'static>(
17911        &mut self,
17912        ranges: &[Range<Anchor>],
17913        color_fetcher: fn(&ThemeColors) -> Hsla,
17914        cx: &mut Context<Self>,
17915    ) {
17916        self.background_highlights
17917            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17918        self.scrollbar_marker_state.dirty = true;
17919        cx.notify();
17920    }
17921
17922    pub fn clear_background_highlights<T: 'static>(
17923        &mut self,
17924        cx: &mut Context<Self>,
17925    ) -> Option<BackgroundHighlight> {
17926        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17927        if !text_highlights.1.is_empty() {
17928            self.scrollbar_marker_state.dirty = true;
17929            cx.notify();
17930        }
17931        Some(text_highlights)
17932    }
17933
17934    pub fn highlight_gutter<T: 'static>(
17935        &mut self,
17936        ranges: &[Range<Anchor>],
17937        color_fetcher: fn(&App) -> Hsla,
17938        cx: &mut Context<Self>,
17939    ) {
17940        self.gutter_highlights
17941            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17942        cx.notify();
17943    }
17944
17945    pub fn clear_gutter_highlights<T: 'static>(
17946        &mut self,
17947        cx: &mut Context<Self>,
17948    ) -> Option<GutterHighlight> {
17949        cx.notify();
17950        self.gutter_highlights.remove(&TypeId::of::<T>())
17951    }
17952
17953    #[cfg(feature = "test-support")]
17954    pub fn all_text_background_highlights(
17955        &self,
17956        window: &mut Window,
17957        cx: &mut Context<Self>,
17958    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17959        let snapshot = self.snapshot(window, cx);
17960        let buffer = &snapshot.buffer_snapshot;
17961        let start = buffer.anchor_before(0);
17962        let end = buffer.anchor_after(buffer.len());
17963        let theme = cx.theme().colors();
17964        self.background_highlights_in_range(start..end, &snapshot, theme)
17965    }
17966
17967    #[cfg(feature = "test-support")]
17968    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17969        let snapshot = self.buffer().read(cx).snapshot(cx);
17970
17971        let highlights = self
17972            .background_highlights
17973            .get(&TypeId::of::<items::BufferSearchHighlights>());
17974
17975        if let Some((_color, ranges)) = highlights {
17976            ranges
17977                .iter()
17978                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17979                .collect_vec()
17980        } else {
17981            vec![]
17982        }
17983    }
17984
17985    fn document_highlights_for_position<'a>(
17986        &'a self,
17987        position: Anchor,
17988        buffer: &'a MultiBufferSnapshot,
17989    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17990        let read_highlights = self
17991            .background_highlights
17992            .get(&TypeId::of::<DocumentHighlightRead>())
17993            .map(|h| &h.1);
17994        let write_highlights = self
17995            .background_highlights
17996            .get(&TypeId::of::<DocumentHighlightWrite>())
17997            .map(|h| &h.1);
17998        let left_position = position.bias_left(buffer);
17999        let right_position = position.bias_right(buffer);
18000        read_highlights
18001            .into_iter()
18002            .chain(write_highlights)
18003            .flat_map(move |ranges| {
18004                let start_ix = match ranges.binary_search_by(|probe| {
18005                    let cmp = probe.end.cmp(&left_position, buffer);
18006                    if cmp.is_ge() {
18007                        Ordering::Greater
18008                    } else {
18009                        Ordering::Less
18010                    }
18011                }) {
18012                    Ok(i) | Err(i) => i,
18013                };
18014
18015                ranges[start_ix..]
18016                    .iter()
18017                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18018            })
18019    }
18020
18021    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18022        self.background_highlights
18023            .get(&TypeId::of::<T>())
18024            .map_or(false, |(_, highlights)| !highlights.is_empty())
18025    }
18026
18027    pub fn background_highlights_in_range(
18028        &self,
18029        search_range: Range<Anchor>,
18030        display_snapshot: &DisplaySnapshot,
18031        theme: &ThemeColors,
18032    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18033        let mut results = Vec::new();
18034        for (color_fetcher, ranges) in self.background_highlights.values() {
18035            let color = color_fetcher(theme);
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            for range in &ranges[start_ix..] {
18049                if range
18050                    .start
18051                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18052                    .is_ge()
18053                {
18054                    break;
18055                }
18056
18057                let start = range.start.to_display_point(display_snapshot);
18058                let end = range.end.to_display_point(display_snapshot);
18059                results.push((start..end, color))
18060            }
18061        }
18062        results
18063    }
18064
18065    pub fn background_highlight_row_ranges<T: 'static>(
18066        &self,
18067        search_range: Range<Anchor>,
18068        display_snapshot: &DisplaySnapshot,
18069        count: usize,
18070    ) -> Vec<RangeInclusive<DisplayPoint>> {
18071        let mut results = Vec::new();
18072        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18073            return vec![];
18074        };
18075
18076        let start_ix = match ranges.binary_search_by(|probe| {
18077            let cmp = probe
18078                .end
18079                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18080            if cmp.is_gt() {
18081                Ordering::Greater
18082            } else {
18083                Ordering::Less
18084            }
18085        }) {
18086            Ok(i) | Err(i) => i,
18087        };
18088        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18089            if let (Some(start_display), Some(end_display)) = (start, end) {
18090                results.push(
18091                    start_display.to_display_point(display_snapshot)
18092                        ..=end_display.to_display_point(display_snapshot),
18093                );
18094            }
18095        };
18096        let mut start_row: Option<Point> = None;
18097        let mut end_row: Option<Point> = None;
18098        if ranges.len() > count {
18099            return Vec::new();
18100        }
18101        for range in &ranges[start_ix..] {
18102            if range
18103                .start
18104                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18105                .is_ge()
18106            {
18107                break;
18108            }
18109            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18110            if let Some(current_row) = &end_row {
18111                if end.row == current_row.row {
18112                    continue;
18113                }
18114            }
18115            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18116            if start_row.is_none() {
18117                assert_eq!(end_row, None);
18118                start_row = Some(start);
18119                end_row = Some(end);
18120                continue;
18121            }
18122            if let Some(current_end) = end_row.as_mut() {
18123                if start.row > current_end.row + 1 {
18124                    push_region(start_row, end_row);
18125                    start_row = Some(start);
18126                    end_row = Some(end);
18127                } else {
18128                    // Merge two hunks.
18129                    *current_end = end;
18130                }
18131            } else {
18132                unreachable!();
18133            }
18134        }
18135        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18136        push_region(start_row, end_row);
18137        results
18138    }
18139
18140    pub fn gutter_highlights_in_range(
18141        &self,
18142        search_range: Range<Anchor>,
18143        display_snapshot: &DisplaySnapshot,
18144        cx: &App,
18145    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18146        let mut results = Vec::new();
18147        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18148            let color = color_fetcher(cx);
18149            let start_ix = match ranges.binary_search_by(|probe| {
18150                let cmp = probe
18151                    .end
18152                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18153                if cmp.is_gt() {
18154                    Ordering::Greater
18155                } else {
18156                    Ordering::Less
18157                }
18158            }) {
18159                Ok(i) | Err(i) => i,
18160            };
18161            for range in &ranges[start_ix..] {
18162                if range
18163                    .start
18164                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18165                    .is_ge()
18166                {
18167                    break;
18168                }
18169
18170                let start = range.start.to_display_point(display_snapshot);
18171                let end = range.end.to_display_point(display_snapshot);
18172                results.push((start..end, color))
18173            }
18174        }
18175        results
18176    }
18177
18178    /// Get the text ranges corresponding to the redaction query
18179    pub fn redacted_ranges(
18180        &self,
18181        search_range: Range<Anchor>,
18182        display_snapshot: &DisplaySnapshot,
18183        cx: &App,
18184    ) -> Vec<Range<DisplayPoint>> {
18185        display_snapshot
18186            .buffer_snapshot
18187            .redacted_ranges(search_range, |file| {
18188                if let Some(file) = file {
18189                    file.is_private()
18190                        && EditorSettings::get(
18191                            Some(SettingsLocation {
18192                                worktree_id: file.worktree_id(cx),
18193                                path: file.path().as_ref(),
18194                            }),
18195                            cx,
18196                        )
18197                        .redact_private_values
18198                } else {
18199                    false
18200                }
18201            })
18202            .map(|range| {
18203                range.start.to_display_point(display_snapshot)
18204                    ..range.end.to_display_point(display_snapshot)
18205            })
18206            .collect()
18207    }
18208
18209    pub fn highlight_text<T: 'static>(
18210        &mut self,
18211        ranges: Vec<Range<Anchor>>,
18212        style: HighlightStyle,
18213        cx: &mut Context<Self>,
18214    ) {
18215        self.display_map.update(cx, |map, _| {
18216            map.highlight_text(TypeId::of::<T>(), ranges, style)
18217        });
18218        cx.notify();
18219    }
18220
18221    pub(crate) fn highlight_inlays<T: 'static>(
18222        &mut self,
18223        highlights: Vec<InlayHighlight>,
18224        style: HighlightStyle,
18225        cx: &mut Context<Self>,
18226    ) {
18227        self.display_map.update(cx, |map, _| {
18228            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18229        });
18230        cx.notify();
18231    }
18232
18233    pub fn text_highlights<'a, T: 'static>(
18234        &'a self,
18235        cx: &'a App,
18236    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18237        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18238    }
18239
18240    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18241        let cleared = self
18242            .display_map
18243            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18244        if cleared {
18245            cx.notify();
18246        }
18247    }
18248
18249    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18250        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18251            && self.focus_handle.is_focused(window)
18252    }
18253
18254    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18255        self.show_cursor_when_unfocused = is_enabled;
18256        cx.notify();
18257    }
18258
18259    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18260        cx.notify();
18261    }
18262
18263    fn on_debug_session_event(
18264        &mut self,
18265        _session: Entity<Session>,
18266        event: &SessionEvent,
18267        cx: &mut Context<Self>,
18268    ) {
18269        match event {
18270            SessionEvent::InvalidateInlineValue => {
18271                self.refresh_inline_values(cx);
18272            }
18273            _ => {}
18274        }
18275    }
18276
18277    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18278        let Some(project) = self.project.clone() else {
18279            return;
18280        };
18281
18282        if !self.inline_value_cache.enabled {
18283            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18284            self.splice_inlays(&inlays, Vec::new(), cx);
18285            return;
18286        }
18287
18288        let current_execution_position = self
18289            .highlighted_rows
18290            .get(&TypeId::of::<ActiveDebugLine>())
18291            .and_then(|lines| lines.last().map(|line| line.range.start));
18292
18293        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18294            let inline_values = editor
18295                .update(cx, |editor, cx| {
18296                    let Some(current_execution_position) = current_execution_position else {
18297                        return Some(Task::ready(Ok(Vec::new())));
18298                    };
18299
18300                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18301                        let snapshot = buffer.snapshot(cx);
18302
18303                        let excerpt = snapshot.excerpt_containing(
18304                            current_execution_position..current_execution_position,
18305                        )?;
18306
18307                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18308                    })?;
18309
18310                    let range =
18311                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18312
18313                    project.inline_values(buffer, range, cx)
18314                })
18315                .ok()
18316                .flatten()?
18317                .await
18318                .context("refreshing debugger inlays")
18319                .log_err()?;
18320
18321            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18322
18323            for (buffer_id, inline_value) in inline_values
18324                .into_iter()
18325                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18326            {
18327                buffer_inline_values
18328                    .entry(buffer_id)
18329                    .or_default()
18330                    .push(inline_value);
18331            }
18332
18333            editor
18334                .update(cx, |editor, cx| {
18335                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18336                    let mut new_inlays = Vec::default();
18337
18338                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18339                        let buffer_id = buffer_snapshot.remote_id();
18340                        buffer_inline_values
18341                            .get(&buffer_id)
18342                            .into_iter()
18343                            .flatten()
18344                            .for_each(|hint| {
18345                                let inlay = Inlay::debugger_hint(
18346                                    post_inc(&mut editor.next_inlay_id),
18347                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18348                                    hint.text(),
18349                                );
18350
18351                                new_inlays.push(inlay);
18352                            });
18353                    }
18354
18355                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18356                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18357
18358                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18359                })
18360                .ok()?;
18361            Some(())
18362        });
18363    }
18364
18365    fn on_buffer_event(
18366        &mut self,
18367        multibuffer: &Entity<MultiBuffer>,
18368        event: &multi_buffer::Event,
18369        window: &mut Window,
18370        cx: &mut Context<Self>,
18371    ) {
18372        match event {
18373            multi_buffer::Event::Edited {
18374                singleton_buffer_edited,
18375                edited_buffer: buffer_edited,
18376            } => {
18377                self.scrollbar_marker_state.dirty = true;
18378                self.active_indent_guides_state.dirty = true;
18379                self.refresh_active_diagnostics(cx);
18380                self.refresh_code_actions(window, cx);
18381                self.refresh_selected_text_highlights(true, window, cx);
18382                refresh_matching_bracket_highlights(self, window, cx);
18383                if self.has_active_inline_completion() {
18384                    self.update_visible_inline_completion(window, cx);
18385                }
18386                if let Some(buffer) = buffer_edited {
18387                    let buffer_id = buffer.read(cx).remote_id();
18388                    if !self.registered_buffers.contains_key(&buffer_id) {
18389                        if let Some(project) = self.project.as_ref() {
18390                            project.update(cx, |project, cx| {
18391                                self.registered_buffers.insert(
18392                                    buffer_id,
18393                                    project.register_buffer_with_language_servers(&buffer, cx),
18394                                );
18395                            })
18396                        }
18397                    }
18398                }
18399                cx.emit(EditorEvent::BufferEdited);
18400                cx.emit(SearchEvent::MatchesInvalidated);
18401                if *singleton_buffer_edited {
18402                    if let Some(project) = &self.project {
18403                        #[allow(clippy::mutable_key_type)]
18404                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18405                            multibuffer
18406                                .all_buffers()
18407                                .into_iter()
18408                                .filter_map(|buffer| {
18409                                    buffer.update(cx, |buffer, cx| {
18410                                        let language = buffer.language()?;
18411                                        let should_discard = project.update(cx, |project, cx| {
18412                                            project.is_local()
18413                                                && !project.has_language_servers_for(buffer, cx)
18414                                        });
18415                                        should_discard.not().then_some(language.clone())
18416                                    })
18417                                })
18418                                .collect::<HashSet<_>>()
18419                        });
18420                        if !languages_affected.is_empty() {
18421                            self.refresh_inlay_hints(
18422                                InlayHintRefreshReason::BufferEdited(languages_affected),
18423                                cx,
18424                            );
18425                        }
18426                    }
18427                }
18428
18429                let Some(project) = &self.project else { return };
18430                let (telemetry, is_via_ssh) = {
18431                    let project = project.read(cx);
18432                    let telemetry = project.client().telemetry().clone();
18433                    let is_via_ssh = project.is_via_ssh();
18434                    (telemetry, is_via_ssh)
18435                };
18436                refresh_linked_ranges(self, window, cx);
18437                telemetry.log_edit_event("editor", is_via_ssh);
18438            }
18439            multi_buffer::Event::ExcerptsAdded {
18440                buffer,
18441                predecessor,
18442                excerpts,
18443            } => {
18444                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18445                let buffer_id = buffer.read(cx).remote_id();
18446                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18447                    if let Some(project) = &self.project {
18448                        update_uncommitted_diff_for_buffer(
18449                            cx.entity(),
18450                            project,
18451                            [buffer.clone()],
18452                            self.buffer.clone(),
18453                            cx,
18454                        )
18455                        .detach();
18456                    }
18457                }
18458                cx.emit(EditorEvent::ExcerptsAdded {
18459                    buffer: buffer.clone(),
18460                    predecessor: *predecessor,
18461                    excerpts: excerpts.clone(),
18462                });
18463                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18464            }
18465            multi_buffer::Event::ExcerptsRemoved {
18466                ids,
18467                removed_buffer_ids,
18468            } => {
18469                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18470                let buffer = self.buffer.read(cx);
18471                self.registered_buffers
18472                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18473                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18474                cx.emit(EditorEvent::ExcerptsRemoved {
18475                    ids: ids.clone(),
18476                    removed_buffer_ids: removed_buffer_ids.clone(),
18477                })
18478            }
18479            multi_buffer::Event::ExcerptsEdited {
18480                excerpt_ids,
18481                buffer_ids,
18482            } => {
18483                self.display_map.update(cx, |map, cx| {
18484                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18485                });
18486                cx.emit(EditorEvent::ExcerptsEdited {
18487                    ids: excerpt_ids.clone(),
18488                })
18489            }
18490            multi_buffer::Event::ExcerptsExpanded { ids } => {
18491                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18492                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18493            }
18494            multi_buffer::Event::Reparsed(buffer_id) => {
18495                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18496                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18497
18498                cx.emit(EditorEvent::Reparsed(*buffer_id));
18499            }
18500            multi_buffer::Event::DiffHunksToggled => {
18501                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18502            }
18503            multi_buffer::Event::LanguageChanged(buffer_id) => {
18504                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18505                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18506                cx.emit(EditorEvent::Reparsed(*buffer_id));
18507                cx.notify();
18508            }
18509            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18510            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18511            multi_buffer::Event::FileHandleChanged
18512            | multi_buffer::Event::Reloaded
18513            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18514            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18515            multi_buffer::Event::DiagnosticsUpdated => {
18516                self.refresh_active_diagnostics(cx);
18517                self.refresh_inline_diagnostics(true, window, cx);
18518                self.scrollbar_marker_state.dirty = true;
18519                cx.notify();
18520            }
18521            _ => {}
18522        };
18523    }
18524
18525    pub fn start_temporary_diff_override(&mut self) {
18526        self.load_diff_task.take();
18527        self.temporary_diff_override = true;
18528    }
18529
18530    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18531        self.temporary_diff_override = false;
18532        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18533        self.buffer.update(cx, |buffer, cx| {
18534            buffer.set_all_diff_hunks_collapsed(cx);
18535        });
18536
18537        if let Some(project) = self.project.clone() {
18538            self.load_diff_task = Some(
18539                update_uncommitted_diff_for_buffer(
18540                    cx.entity(),
18541                    &project,
18542                    self.buffer.read(cx).all_buffers(),
18543                    self.buffer.clone(),
18544                    cx,
18545                )
18546                .shared(),
18547            );
18548        }
18549    }
18550
18551    fn on_display_map_changed(
18552        &mut self,
18553        _: Entity<DisplayMap>,
18554        _: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        cx.notify();
18558    }
18559
18560    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18561        let new_severity = if self.diagnostics_enabled() {
18562            EditorSettings::get_global(cx)
18563                .diagnostics_max_severity
18564                .unwrap_or(DiagnosticSeverity::Hint)
18565        } else {
18566            DiagnosticSeverity::Off
18567        };
18568        self.set_max_diagnostics_severity(new_severity, cx);
18569        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18570        self.update_edit_prediction_settings(cx);
18571        self.refresh_inline_completion(true, false, window, cx);
18572        self.refresh_inlay_hints(
18573            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18574                self.selections.newest_anchor().head(),
18575                &self.buffer.read(cx).snapshot(cx),
18576                cx,
18577            )),
18578            cx,
18579        );
18580
18581        let old_cursor_shape = self.cursor_shape;
18582
18583        {
18584            let editor_settings = EditorSettings::get_global(cx);
18585            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18586            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18587            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18588            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18589        }
18590
18591        if old_cursor_shape != self.cursor_shape {
18592            cx.emit(EditorEvent::CursorShapeChanged);
18593        }
18594
18595        let project_settings = ProjectSettings::get_global(cx);
18596        self.serialize_dirty_buffers =
18597            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18598
18599        if self.mode.is_full() {
18600            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18601            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18602            if self.show_inline_diagnostics != show_inline_diagnostics {
18603                self.show_inline_diagnostics = show_inline_diagnostics;
18604                self.refresh_inline_diagnostics(false, window, cx);
18605            }
18606
18607            if self.git_blame_inline_enabled != inline_blame_enabled {
18608                self.toggle_git_blame_inline_internal(false, window, cx);
18609            }
18610
18611            let minimap_settings = EditorSettings::get_global(cx).minimap;
18612            if self.minimap_visibility.settings_visibility() != minimap_settings.minimap_enabled() {
18613                self.set_minimap_visibility(
18614                    MinimapVisibility::for_mode(self.mode(), cx),
18615                    window,
18616                    cx,
18617                );
18618            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18619                minimap_entity.update(cx, |minimap_editor, cx| {
18620                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18621                })
18622            }
18623        }
18624
18625        cx.notify();
18626    }
18627
18628    pub fn set_searchable(&mut self, searchable: bool) {
18629        self.searchable = searchable;
18630    }
18631
18632    pub fn searchable(&self) -> bool {
18633        self.searchable
18634    }
18635
18636    fn open_proposed_changes_editor(
18637        &mut self,
18638        _: &OpenProposedChangesEditor,
18639        window: &mut Window,
18640        cx: &mut Context<Self>,
18641    ) {
18642        let Some(workspace) = self.workspace() else {
18643            cx.propagate();
18644            return;
18645        };
18646
18647        let selections = self.selections.all::<usize>(cx);
18648        let multi_buffer = self.buffer.read(cx);
18649        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18650        let mut new_selections_by_buffer = HashMap::default();
18651        for selection in selections {
18652            for (buffer, range, _) in
18653                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18654            {
18655                let mut range = range.to_point(buffer);
18656                range.start.column = 0;
18657                range.end.column = buffer.line_len(range.end.row);
18658                new_selections_by_buffer
18659                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18660                    .or_insert(Vec::new())
18661                    .push(range)
18662            }
18663        }
18664
18665        let proposed_changes_buffers = new_selections_by_buffer
18666            .into_iter()
18667            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18668            .collect::<Vec<_>>();
18669        let proposed_changes_editor = cx.new(|cx| {
18670            ProposedChangesEditor::new(
18671                "Proposed changes",
18672                proposed_changes_buffers,
18673                self.project.clone(),
18674                window,
18675                cx,
18676            )
18677        });
18678
18679        window.defer(cx, move |window, cx| {
18680            workspace.update(cx, |workspace, cx| {
18681                workspace.active_pane().update(cx, |pane, cx| {
18682                    pane.add_item(
18683                        Box::new(proposed_changes_editor),
18684                        true,
18685                        true,
18686                        None,
18687                        window,
18688                        cx,
18689                    );
18690                });
18691            });
18692        });
18693    }
18694
18695    pub fn open_excerpts_in_split(
18696        &mut self,
18697        _: &OpenExcerptsSplit,
18698        window: &mut Window,
18699        cx: &mut Context<Self>,
18700    ) {
18701        self.open_excerpts_common(None, true, window, cx)
18702    }
18703
18704    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18705        self.open_excerpts_common(None, false, window, cx)
18706    }
18707
18708    fn open_excerpts_common(
18709        &mut self,
18710        jump_data: Option<JumpData>,
18711        split: bool,
18712        window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        let Some(workspace) = self.workspace() else {
18716            cx.propagate();
18717            return;
18718        };
18719
18720        if self.buffer.read(cx).is_singleton() {
18721            cx.propagate();
18722            return;
18723        }
18724
18725        let mut new_selections_by_buffer = HashMap::default();
18726        match &jump_data {
18727            Some(JumpData::MultiBufferPoint {
18728                excerpt_id,
18729                position,
18730                anchor,
18731                line_offset_from_top,
18732            }) => {
18733                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18734                if let Some(buffer) = multi_buffer_snapshot
18735                    .buffer_id_for_excerpt(*excerpt_id)
18736                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18737                {
18738                    let buffer_snapshot = buffer.read(cx).snapshot();
18739                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18740                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18741                    } else {
18742                        buffer_snapshot.clip_point(*position, Bias::Left)
18743                    };
18744                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18745                    new_selections_by_buffer.insert(
18746                        buffer,
18747                        (
18748                            vec![jump_to_offset..jump_to_offset],
18749                            Some(*line_offset_from_top),
18750                        ),
18751                    );
18752                }
18753            }
18754            Some(JumpData::MultiBufferRow {
18755                row,
18756                line_offset_from_top,
18757            }) => {
18758                let point = MultiBufferPoint::new(row.0, 0);
18759                if let Some((buffer, buffer_point, _)) =
18760                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18761                {
18762                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18763                    new_selections_by_buffer
18764                        .entry(buffer)
18765                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18766                        .0
18767                        .push(buffer_offset..buffer_offset)
18768                }
18769            }
18770            None => {
18771                let selections = self.selections.all::<usize>(cx);
18772                let multi_buffer = self.buffer.read(cx);
18773                for selection in selections {
18774                    for (snapshot, range, _, anchor) in multi_buffer
18775                        .snapshot(cx)
18776                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18777                    {
18778                        if let Some(anchor) = anchor {
18779                            // selection is in a deleted hunk
18780                            let Some(buffer_id) = anchor.buffer_id else {
18781                                continue;
18782                            };
18783                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18784                                continue;
18785                            };
18786                            let offset = text::ToOffset::to_offset(
18787                                &anchor.text_anchor,
18788                                &buffer_handle.read(cx).snapshot(),
18789                            );
18790                            let range = offset..offset;
18791                            new_selections_by_buffer
18792                                .entry(buffer_handle)
18793                                .or_insert((Vec::new(), None))
18794                                .0
18795                                .push(range)
18796                        } else {
18797                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18798                            else {
18799                                continue;
18800                            };
18801                            new_selections_by_buffer
18802                                .entry(buffer_handle)
18803                                .or_insert((Vec::new(), None))
18804                                .0
18805                                .push(range)
18806                        }
18807                    }
18808                }
18809            }
18810        }
18811
18812        new_selections_by_buffer
18813            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18814
18815        if new_selections_by_buffer.is_empty() {
18816            return;
18817        }
18818
18819        // We defer the pane interaction because we ourselves are a workspace item
18820        // and activating a new item causes the pane to call a method on us reentrantly,
18821        // which panics if we're on the stack.
18822        window.defer(cx, move |window, cx| {
18823            workspace.update(cx, |workspace, cx| {
18824                let pane = if split {
18825                    workspace.adjacent_pane(window, cx)
18826                } else {
18827                    workspace.active_pane().clone()
18828                };
18829
18830                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18831                    let editor = buffer
18832                        .read(cx)
18833                        .file()
18834                        .is_none()
18835                        .then(|| {
18836                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18837                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18838                            // Instead, we try to activate the existing editor in the pane first.
18839                            let (editor, pane_item_index) =
18840                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18841                                    let editor = item.downcast::<Editor>()?;
18842                                    let singleton_buffer =
18843                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18844                                    if singleton_buffer == buffer {
18845                                        Some((editor, i))
18846                                    } else {
18847                                        None
18848                                    }
18849                                })?;
18850                            pane.update(cx, |pane, cx| {
18851                                pane.activate_item(pane_item_index, true, true, window, cx)
18852                            });
18853                            Some(editor)
18854                        })
18855                        .flatten()
18856                        .unwrap_or_else(|| {
18857                            workspace.open_project_item::<Self>(
18858                                pane.clone(),
18859                                buffer,
18860                                true,
18861                                true,
18862                                window,
18863                                cx,
18864                            )
18865                        });
18866
18867                    editor.update(cx, |editor, cx| {
18868                        let autoscroll = match scroll_offset {
18869                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18870                            None => Autoscroll::newest(),
18871                        };
18872                        let nav_history = editor.nav_history.take();
18873                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18874                            s.select_ranges(ranges);
18875                        });
18876                        editor.nav_history = nav_history;
18877                    });
18878                }
18879            })
18880        });
18881    }
18882
18883    // For now, don't allow opening excerpts in buffers that aren't backed by
18884    // regular project files.
18885    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18886        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18887    }
18888
18889    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18890        let snapshot = self.buffer.read(cx).read(cx);
18891        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18892        Some(
18893            ranges
18894                .iter()
18895                .map(move |range| {
18896                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18897                })
18898                .collect(),
18899        )
18900    }
18901
18902    fn selection_replacement_ranges(
18903        &self,
18904        range: Range<OffsetUtf16>,
18905        cx: &mut App,
18906    ) -> Vec<Range<OffsetUtf16>> {
18907        let selections = self.selections.all::<OffsetUtf16>(cx);
18908        let newest_selection = selections
18909            .iter()
18910            .max_by_key(|selection| selection.id)
18911            .unwrap();
18912        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18913        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18914        let snapshot = self.buffer.read(cx).read(cx);
18915        selections
18916            .into_iter()
18917            .map(|mut selection| {
18918                selection.start.0 =
18919                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18920                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18921                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18922                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18923            })
18924            .collect()
18925    }
18926
18927    fn report_editor_event(
18928        &self,
18929        event_type: &'static str,
18930        file_extension: Option<String>,
18931        cx: &App,
18932    ) {
18933        if cfg!(any(test, feature = "test-support")) {
18934            return;
18935        }
18936
18937        let Some(project) = &self.project else { return };
18938
18939        // If None, we are in a file without an extension
18940        let file = self
18941            .buffer
18942            .read(cx)
18943            .as_singleton()
18944            .and_then(|b| b.read(cx).file());
18945        let file_extension = file_extension.or(file
18946            .as_ref()
18947            .and_then(|file| Path::new(file.file_name(cx)).extension())
18948            .and_then(|e| e.to_str())
18949            .map(|a| a.to_string()));
18950
18951        let vim_mode = vim_enabled(cx);
18952
18953        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18954        let copilot_enabled = edit_predictions_provider
18955            == language::language_settings::EditPredictionProvider::Copilot;
18956        let copilot_enabled_for_language = self
18957            .buffer
18958            .read(cx)
18959            .language_settings(cx)
18960            .show_edit_predictions;
18961
18962        let project = project.read(cx);
18963        telemetry::event!(
18964            event_type,
18965            file_extension,
18966            vim_mode,
18967            copilot_enabled,
18968            copilot_enabled_for_language,
18969            edit_predictions_provider,
18970            is_via_ssh = project.is_via_ssh(),
18971        );
18972    }
18973
18974    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18975    /// with each line being an array of {text, highlight} objects.
18976    fn copy_highlight_json(
18977        &mut self,
18978        _: &CopyHighlightJson,
18979        window: &mut Window,
18980        cx: &mut Context<Self>,
18981    ) {
18982        #[derive(Serialize)]
18983        struct Chunk<'a> {
18984            text: String,
18985            highlight: Option<&'a str>,
18986        }
18987
18988        let snapshot = self.buffer.read(cx).snapshot(cx);
18989        let range = self
18990            .selected_text_range(false, window, cx)
18991            .and_then(|selection| {
18992                if selection.range.is_empty() {
18993                    None
18994                } else {
18995                    Some(selection.range)
18996                }
18997            })
18998            .unwrap_or_else(|| 0..snapshot.len());
18999
19000        let chunks = snapshot.chunks(range, true);
19001        let mut lines = Vec::new();
19002        let mut line: VecDeque<Chunk> = VecDeque::new();
19003
19004        let Some(style) = self.style.as_ref() else {
19005            return;
19006        };
19007
19008        for chunk in chunks {
19009            let highlight = chunk
19010                .syntax_highlight_id
19011                .and_then(|id| id.name(&style.syntax));
19012            let mut chunk_lines = chunk.text.split('\n').peekable();
19013            while let Some(text) = chunk_lines.next() {
19014                let mut merged_with_last_token = false;
19015                if let Some(last_token) = line.back_mut() {
19016                    if last_token.highlight == highlight {
19017                        last_token.text.push_str(text);
19018                        merged_with_last_token = true;
19019                    }
19020                }
19021
19022                if !merged_with_last_token {
19023                    line.push_back(Chunk {
19024                        text: text.into(),
19025                        highlight,
19026                    });
19027                }
19028
19029                if chunk_lines.peek().is_some() {
19030                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19031                        line.pop_front();
19032                    }
19033                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19034                        line.pop_back();
19035                    }
19036
19037                    lines.push(mem::take(&mut line));
19038                }
19039            }
19040        }
19041
19042        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19043            return;
19044        };
19045        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19046    }
19047
19048    pub fn open_context_menu(
19049        &mut self,
19050        _: &OpenContextMenu,
19051        window: &mut Window,
19052        cx: &mut Context<Self>,
19053    ) {
19054        self.request_autoscroll(Autoscroll::newest(), cx);
19055        let position = self.selections.newest_display(cx).start;
19056        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19057    }
19058
19059    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19060        &self.inlay_hint_cache
19061    }
19062
19063    pub fn replay_insert_event(
19064        &mut self,
19065        text: &str,
19066        relative_utf16_range: Option<Range<isize>>,
19067        window: &mut Window,
19068        cx: &mut Context<Self>,
19069    ) {
19070        if !self.input_enabled {
19071            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19072            return;
19073        }
19074        if let Some(relative_utf16_range) = relative_utf16_range {
19075            let selections = self.selections.all::<OffsetUtf16>(cx);
19076            self.change_selections(None, window, cx, |s| {
19077                let new_ranges = selections.into_iter().map(|range| {
19078                    let start = OffsetUtf16(
19079                        range
19080                            .head()
19081                            .0
19082                            .saturating_add_signed(relative_utf16_range.start),
19083                    );
19084                    let end = OffsetUtf16(
19085                        range
19086                            .head()
19087                            .0
19088                            .saturating_add_signed(relative_utf16_range.end),
19089                    );
19090                    start..end
19091                });
19092                s.select_ranges(new_ranges);
19093            });
19094        }
19095
19096        self.handle_input(text, window, cx);
19097    }
19098
19099    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19100        let Some(provider) = self.semantics_provider.as_ref() else {
19101            return false;
19102        };
19103
19104        let mut supports = false;
19105        self.buffer().update(cx, |this, cx| {
19106            this.for_each_buffer(|buffer| {
19107                supports |= provider.supports_inlay_hints(buffer, cx);
19108            });
19109        });
19110
19111        supports
19112    }
19113
19114    pub fn is_focused(&self, window: &Window) -> bool {
19115        self.focus_handle.is_focused(window)
19116    }
19117
19118    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19119        cx.emit(EditorEvent::Focused);
19120
19121        if let Some(descendant) = self
19122            .last_focused_descendant
19123            .take()
19124            .and_then(|descendant| descendant.upgrade())
19125        {
19126            window.focus(&descendant);
19127        } else {
19128            if let Some(blame) = self.blame.as_ref() {
19129                blame.update(cx, GitBlame::focus)
19130            }
19131
19132            self.blink_manager.update(cx, BlinkManager::enable);
19133            self.show_cursor_names(window, cx);
19134            self.buffer.update(cx, |buffer, cx| {
19135                buffer.finalize_last_transaction(cx);
19136                if self.leader_id.is_none() {
19137                    buffer.set_active_selections(
19138                        &self.selections.disjoint_anchors(),
19139                        self.selections.line_mode,
19140                        self.cursor_shape,
19141                        cx,
19142                    );
19143                }
19144            });
19145        }
19146    }
19147
19148    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19149        cx.emit(EditorEvent::FocusedIn)
19150    }
19151
19152    fn handle_focus_out(
19153        &mut self,
19154        event: FocusOutEvent,
19155        _window: &mut Window,
19156        cx: &mut Context<Self>,
19157    ) {
19158        if event.blurred != self.focus_handle {
19159            self.last_focused_descendant = Some(event.blurred);
19160        }
19161        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19162    }
19163
19164    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19165        self.blink_manager.update(cx, BlinkManager::disable);
19166        self.buffer
19167            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19168
19169        if let Some(blame) = self.blame.as_ref() {
19170            blame.update(cx, GitBlame::blur)
19171        }
19172        if !self.hover_state.focused(window, cx) {
19173            hide_hover(self, cx);
19174        }
19175        if !self
19176            .context_menu
19177            .borrow()
19178            .as_ref()
19179            .is_some_and(|context_menu| context_menu.focused(window, cx))
19180        {
19181            self.hide_context_menu(window, cx);
19182        }
19183        self.discard_inline_completion(false, cx);
19184        cx.emit(EditorEvent::Blurred);
19185        cx.notify();
19186    }
19187
19188    pub fn register_action<A: Action>(
19189        &mut self,
19190        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19191    ) -> Subscription {
19192        let id = self.next_editor_action_id.post_inc();
19193        let listener = Arc::new(listener);
19194        self.editor_actions.borrow_mut().insert(
19195            id,
19196            Box::new(move |window, _| {
19197                let listener = listener.clone();
19198                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19199                    let action = action.downcast_ref().unwrap();
19200                    if phase == DispatchPhase::Bubble {
19201                        listener(action, window, cx)
19202                    }
19203                })
19204            }),
19205        );
19206
19207        let editor_actions = self.editor_actions.clone();
19208        Subscription::new(move || {
19209            editor_actions.borrow_mut().remove(&id);
19210        })
19211    }
19212
19213    pub fn file_header_size(&self) -> u32 {
19214        FILE_HEADER_HEIGHT
19215    }
19216
19217    pub fn restore(
19218        &mut self,
19219        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19220        window: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) {
19223        let workspace = self.workspace();
19224        let project = self.project.as_ref();
19225        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19226            let mut tasks = Vec::new();
19227            for (buffer_id, changes) in revert_changes {
19228                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19229                    buffer.update(cx, |buffer, cx| {
19230                        buffer.edit(
19231                            changes
19232                                .into_iter()
19233                                .map(|(range, text)| (range, text.to_string())),
19234                            None,
19235                            cx,
19236                        );
19237                    });
19238
19239                    if let Some(project) =
19240                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19241                    {
19242                        project.update(cx, |project, cx| {
19243                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19244                        })
19245                    }
19246                }
19247            }
19248            tasks
19249        });
19250        cx.spawn_in(window, async move |_, cx| {
19251            for (buffer, task) in save_tasks {
19252                let result = task.await;
19253                if result.is_err() {
19254                    let Some(path) = buffer
19255                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19256                        .ok()
19257                    else {
19258                        continue;
19259                    };
19260                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19261                        let Some(task) = cx
19262                            .update_window_entity(&workspace, |workspace, window, cx| {
19263                                workspace
19264                                    .open_path_preview(path, None, false, false, false, window, cx)
19265                            })
19266                            .ok()
19267                        else {
19268                            continue;
19269                        };
19270                        task.await.log_err();
19271                    }
19272                }
19273            }
19274        })
19275        .detach();
19276        self.change_selections(None, window, cx, |selections| selections.refresh());
19277    }
19278
19279    pub fn to_pixel_point(
19280        &self,
19281        source: multi_buffer::Anchor,
19282        editor_snapshot: &EditorSnapshot,
19283        window: &mut Window,
19284    ) -> Option<gpui::Point<Pixels>> {
19285        let source_point = source.to_display_point(editor_snapshot);
19286        self.display_to_pixel_point(source_point, editor_snapshot, window)
19287    }
19288
19289    pub fn display_to_pixel_point(
19290        &self,
19291        source: DisplayPoint,
19292        editor_snapshot: &EditorSnapshot,
19293        window: &mut Window,
19294    ) -> Option<gpui::Point<Pixels>> {
19295        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19296        let text_layout_details = self.text_layout_details(window);
19297        let scroll_top = text_layout_details
19298            .scroll_anchor
19299            .scroll_position(editor_snapshot)
19300            .y;
19301
19302        if source.row().as_f32() < scroll_top.floor() {
19303            return None;
19304        }
19305        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19306        let source_y = line_height * (source.row().as_f32() - scroll_top);
19307        Some(gpui::Point::new(source_x, source_y))
19308    }
19309
19310    pub fn has_visible_completions_menu(&self) -> bool {
19311        !self.edit_prediction_preview_is_active()
19312            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19313                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19314            })
19315    }
19316
19317    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19318        if self.mode.is_minimap() {
19319            return;
19320        }
19321        self.addons
19322            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19323    }
19324
19325    pub fn unregister_addon<T: Addon>(&mut self) {
19326        self.addons.remove(&std::any::TypeId::of::<T>());
19327    }
19328
19329    pub fn addon<T: Addon>(&self) -> Option<&T> {
19330        let type_id = std::any::TypeId::of::<T>();
19331        self.addons
19332            .get(&type_id)
19333            .and_then(|item| item.to_any().downcast_ref::<T>())
19334    }
19335
19336    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19337        let type_id = std::any::TypeId::of::<T>();
19338        self.addons
19339            .get_mut(&type_id)
19340            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19341    }
19342
19343    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19344        let text_layout_details = self.text_layout_details(window);
19345        let style = &text_layout_details.editor_style;
19346        let font_id = window.text_system().resolve_font(&style.text.font());
19347        let font_size = style.text.font_size.to_pixels(window.rem_size());
19348        let line_height = style.text.line_height_in_pixels(window.rem_size());
19349        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19350
19351        gpui::Size::new(em_width, line_height)
19352    }
19353
19354    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19355        self.load_diff_task.clone()
19356    }
19357
19358    fn read_metadata_from_db(
19359        &mut self,
19360        item_id: u64,
19361        workspace_id: WorkspaceId,
19362        window: &mut Window,
19363        cx: &mut Context<Editor>,
19364    ) {
19365        if self.is_singleton(cx)
19366            && !self.mode.is_minimap()
19367            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19368        {
19369            let buffer_snapshot = OnceCell::new();
19370
19371            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19372                if !folds.is_empty() {
19373                    let snapshot =
19374                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19375                    self.fold_ranges(
19376                        folds
19377                            .into_iter()
19378                            .map(|(start, end)| {
19379                                snapshot.clip_offset(start, Bias::Left)
19380                                    ..snapshot.clip_offset(end, Bias::Right)
19381                            })
19382                            .collect(),
19383                        false,
19384                        window,
19385                        cx,
19386                    );
19387                }
19388            }
19389
19390            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19391                if !selections.is_empty() {
19392                    let snapshot =
19393                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19394                    self.change_selections(None, window, cx, |s| {
19395                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19396                            snapshot.clip_offset(start, Bias::Left)
19397                                ..snapshot.clip_offset(end, Bias::Right)
19398                        }));
19399                    });
19400                }
19401            };
19402        }
19403
19404        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19405    }
19406}
19407
19408fn vim_enabled(cx: &App) -> bool {
19409    cx.global::<SettingsStore>()
19410        .raw_user_settings()
19411        .get("vim_mode")
19412        == Some(&serde_json::Value::Bool(true))
19413}
19414
19415// Consider user intent and default settings
19416fn choose_completion_range(
19417    completion: &Completion,
19418    intent: CompletionIntent,
19419    buffer: &Entity<Buffer>,
19420    cx: &mut Context<Editor>,
19421) -> Range<usize> {
19422    fn should_replace(
19423        completion: &Completion,
19424        insert_range: &Range<text::Anchor>,
19425        intent: CompletionIntent,
19426        completion_mode_setting: LspInsertMode,
19427        buffer: &Buffer,
19428    ) -> bool {
19429        // specific actions take precedence over settings
19430        match intent {
19431            CompletionIntent::CompleteWithInsert => return false,
19432            CompletionIntent::CompleteWithReplace => return true,
19433            CompletionIntent::Complete | CompletionIntent::Compose => {}
19434        }
19435
19436        match completion_mode_setting {
19437            LspInsertMode::Insert => false,
19438            LspInsertMode::Replace => true,
19439            LspInsertMode::ReplaceSubsequence => {
19440                let mut text_to_replace = buffer.chars_for_range(
19441                    buffer.anchor_before(completion.replace_range.start)
19442                        ..buffer.anchor_after(completion.replace_range.end),
19443                );
19444                let mut completion_text = completion.new_text.chars();
19445
19446                // is `text_to_replace` a subsequence of `completion_text`
19447                text_to_replace
19448                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19449            }
19450            LspInsertMode::ReplaceSuffix => {
19451                let range_after_cursor = insert_range.end..completion.replace_range.end;
19452
19453                let text_after_cursor = buffer
19454                    .text_for_range(
19455                        buffer.anchor_before(range_after_cursor.start)
19456                            ..buffer.anchor_after(range_after_cursor.end),
19457                    )
19458                    .collect::<String>();
19459                completion.new_text.ends_with(&text_after_cursor)
19460            }
19461        }
19462    }
19463
19464    let buffer = buffer.read(cx);
19465
19466    if let CompletionSource::Lsp {
19467        insert_range: Some(insert_range),
19468        ..
19469    } = &completion.source
19470    {
19471        let completion_mode_setting =
19472            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19473                .completions
19474                .lsp_insert_mode;
19475
19476        if !should_replace(
19477            completion,
19478            &insert_range,
19479            intent,
19480            completion_mode_setting,
19481            buffer,
19482        ) {
19483            return insert_range.to_offset(buffer);
19484        }
19485    }
19486
19487    completion.replace_range.to_offset(buffer)
19488}
19489
19490fn insert_extra_newline_brackets(
19491    buffer: &MultiBufferSnapshot,
19492    range: Range<usize>,
19493    language: &language::LanguageScope,
19494) -> bool {
19495    let leading_whitespace_len = buffer
19496        .reversed_chars_at(range.start)
19497        .take_while(|c| c.is_whitespace() && *c != '\n')
19498        .map(|c| c.len_utf8())
19499        .sum::<usize>();
19500    let trailing_whitespace_len = buffer
19501        .chars_at(range.end)
19502        .take_while(|c| c.is_whitespace() && *c != '\n')
19503        .map(|c| c.len_utf8())
19504        .sum::<usize>();
19505    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19506
19507    language.brackets().any(|(pair, enabled)| {
19508        let pair_start = pair.start.trim_end();
19509        let pair_end = pair.end.trim_start();
19510
19511        enabled
19512            && pair.newline
19513            && buffer.contains_str_at(range.end, pair_end)
19514            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19515    })
19516}
19517
19518fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19519    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19520        [(buffer, range, _)] => (*buffer, range.clone()),
19521        _ => return false,
19522    };
19523    let pair = {
19524        let mut result: Option<BracketMatch> = None;
19525
19526        for pair in buffer
19527            .all_bracket_ranges(range.clone())
19528            .filter(move |pair| {
19529                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19530            })
19531        {
19532            let len = pair.close_range.end - pair.open_range.start;
19533
19534            if let Some(existing) = &result {
19535                let existing_len = existing.close_range.end - existing.open_range.start;
19536                if len > existing_len {
19537                    continue;
19538                }
19539            }
19540
19541            result = Some(pair);
19542        }
19543
19544        result
19545    };
19546    let Some(pair) = pair else {
19547        return false;
19548    };
19549    pair.newline_only
19550        && buffer
19551            .chars_for_range(pair.open_range.end..range.start)
19552            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19553            .all(|c| c.is_whitespace() && c != '\n')
19554}
19555
19556fn update_uncommitted_diff_for_buffer(
19557    editor: Entity<Editor>,
19558    project: &Entity<Project>,
19559    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19560    buffer: Entity<MultiBuffer>,
19561    cx: &mut App,
19562) -> Task<()> {
19563    let mut tasks = Vec::new();
19564    project.update(cx, |project, cx| {
19565        for buffer in buffers {
19566            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19567                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19568            }
19569        }
19570    });
19571    cx.spawn(async move |cx| {
19572        let diffs = future::join_all(tasks).await;
19573        if editor
19574            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19575            .unwrap_or(false)
19576        {
19577            return;
19578        }
19579
19580        buffer
19581            .update(cx, |buffer, cx| {
19582                for diff in diffs.into_iter().flatten() {
19583                    buffer.add_diff(diff, cx);
19584                }
19585            })
19586            .ok();
19587    })
19588}
19589
19590pub trait CollaborationHub {
19591    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19592    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19593    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19594}
19595
19596impl CollaborationHub for Entity<Project> {
19597    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19598        self.read(cx).collaborators()
19599    }
19600
19601    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19602        self.read(cx).user_store().read(cx).participant_indices()
19603    }
19604
19605    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19606        let this = self.read(cx);
19607        let user_ids = this.collaborators().values().map(|c| c.user_id);
19608        this.user_store().read(cx).participant_names(user_ids, cx)
19609    }
19610}
19611
19612pub trait SemanticsProvider {
19613    fn hover(
19614        &self,
19615        buffer: &Entity<Buffer>,
19616        position: text::Anchor,
19617        cx: &mut App,
19618    ) -> Option<Task<Vec<project::Hover>>>;
19619
19620    fn inline_values(
19621        &self,
19622        buffer_handle: Entity<Buffer>,
19623        range: Range<text::Anchor>,
19624        cx: &mut App,
19625    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19626
19627    fn inlay_hints(
19628        &self,
19629        buffer_handle: Entity<Buffer>,
19630        range: Range<text::Anchor>,
19631        cx: &mut App,
19632    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19633
19634    fn resolve_inlay_hint(
19635        &self,
19636        hint: InlayHint,
19637        buffer_handle: Entity<Buffer>,
19638        server_id: LanguageServerId,
19639        cx: &mut App,
19640    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19641
19642    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19643
19644    fn document_highlights(
19645        &self,
19646        buffer: &Entity<Buffer>,
19647        position: text::Anchor,
19648        cx: &mut App,
19649    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19650
19651    fn definitions(
19652        &self,
19653        buffer: &Entity<Buffer>,
19654        position: text::Anchor,
19655        kind: GotoDefinitionKind,
19656        cx: &mut App,
19657    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19658
19659    fn range_for_rename(
19660        &self,
19661        buffer: &Entity<Buffer>,
19662        position: text::Anchor,
19663        cx: &mut App,
19664    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19665
19666    fn perform_rename(
19667        &self,
19668        buffer: &Entity<Buffer>,
19669        position: text::Anchor,
19670        new_name: String,
19671        cx: &mut App,
19672    ) -> Option<Task<Result<ProjectTransaction>>>;
19673}
19674
19675pub trait CompletionProvider {
19676    fn completions(
19677        &self,
19678        excerpt_id: ExcerptId,
19679        buffer: &Entity<Buffer>,
19680        buffer_position: text::Anchor,
19681        trigger: CompletionContext,
19682        window: &mut Window,
19683        cx: &mut Context<Editor>,
19684    ) -> Task<Result<Option<Vec<Completion>>>>;
19685
19686    fn resolve_completions(
19687        &self,
19688        buffer: Entity<Buffer>,
19689        completion_indices: Vec<usize>,
19690        completions: Rc<RefCell<Box<[Completion]>>>,
19691        cx: &mut Context<Editor>,
19692    ) -> Task<Result<bool>>;
19693
19694    fn apply_additional_edits_for_completion(
19695        &self,
19696        _buffer: Entity<Buffer>,
19697        _completions: Rc<RefCell<Box<[Completion]>>>,
19698        _completion_index: usize,
19699        _push_to_history: bool,
19700        _cx: &mut Context<Editor>,
19701    ) -> Task<Result<Option<language::Transaction>>> {
19702        Task::ready(Ok(None))
19703    }
19704
19705    fn is_completion_trigger(
19706        &self,
19707        buffer: &Entity<Buffer>,
19708        position: language::Anchor,
19709        text: &str,
19710        trigger_in_words: bool,
19711        cx: &mut Context<Editor>,
19712    ) -> bool;
19713
19714    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
19715
19716    fn sort_completions(&self) -> bool {
19717        true
19718    }
19719
19720    fn filter_completions(&self) -> bool {
19721        true
19722    }
19723}
19724
19725pub trait CodeActionProvider {
19726    fn id(&self) -> Arc<str>;
19727
19728    fn code_actions(
19729        &self,
19730        buffer: &Entity<Buffer>,
19731        range: Range<text::Anchor>,
19732        window: &mut Window,
19733        cx: &mut App,
19734    ) -> Task<Result<Vec<CodeAction>>>;
19735
19736    fn apply_code_action(
19737        &self,
19738        buffer_handle: Entity<Buffer>,
19739        action: CodeAction,
19740        excerpt_id: ExcerptId,
19741        push_to_history: bool,
19742        window: &mut Window,
19743        cx: &mut App,
19744    ) -> Task<Result<ProjectTransaction>>;
19745}
19746
19747impl CodeActionProvider for Entity<Project> {
19748    fn id(&self) -> Arc<str> {
19749        "project".into()
19750    }
19751
19752    fn code_actions(
19753        &self,
19754        buffer: &Entity<Buffer>,
19755        range: Range<text::Anchor>,
19756        _window: &mut Window,
19757        cx: &mut App,
19758    ) -> Task<Result<Vec<CodeAction>>> {
19759        self.update(cx, |project, cx| {
19760            let code_lens = project.code_lens(buffer, range.clone(), cx);
19761            let code_actions = project.code_actions(buffer, range, None, cx);
19762            cx.background_spawn(async move {
19763                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19764                Ok(code_lens
19765                    .context("code lens fetch")?
19766                    .into_iter()
19767                    .chain(code_actions.context("code action fetch")?)
19768                    .collect())
19769            })
19770        })
19771    }
19772
19773    fn apply_code_action(
19774        &self,
19775        buffer_handle: Entity<Buffer>,
19776        action: CodeAction,
19777        _excerpt_id: ExcerptId,
19778        push_to_history: bool,
19779        _window: &mut Window,
19780        cx: &mut App,
19781    ) -> Task<Result<ProjectTransaction>> {
19782        self.update(cx, |project, cx| {
19783            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19784        })
19785    }
19786}
19787
19788fn snippet_completions(
19789    project: &Project,
19790    buffer: &Entity<Buffer>,
19791    buffer_position: text::Anchor,
19792    cx: &mut App,
19793) -> Task<Result<Vec<Completion>>> {
19794    let languages = buffer.read(cx).languages_at(buffer_position);
19795    let snippet_store = project.snippets().read(cx);
19796
19797    let scopes: Vec<_> = languages
19798        .iter()
19799        .filter_map(|language| {
19800            let language_name = language.lsp_id();
19801            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19802
19803            if snippets.is_empty() {
19804                None
19805            } else {
19806                Some((language.default_scope(), snippets))
19807            }
19808        })
19809        .collect();
19810
19811    if scopes.is_empty() {
19812        return Task::ready(Ok(vec![]));
19813    }
19814
19815    let snapshot = buffer.read(cx).text_snapshot();
19816    let chars: String = snapshot
19817        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19818        .collect();
19819    let executor = cx.background_executor().clone();
19820
19821    cx.background_spawn(async move {
19822        let mut all_results: Vec<Completion> = Vec::new();
19823        for (scope, snippets) in scopes.into_iter() {
19824            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19825            let mut last_word = chars
19826                .chars()
19827                .take_while(|c| classifier.is_word(*c))
19828                .collect::<String>();
19829            last_word = last_word.chars().rev().collect();
19830
19831            if last_word.is_empty() {
19832                return Ok(vec![]);
19833            }
19834
19835            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19836            let to_lsp = |point: &text::Anchor| {
19837                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19838                point_to_lsp(end)
19839            };
19840            let lsp_end = to_lsp(&buffer_position);
19841
19842            let candidates = snippets
19843                .iter()
19844                .enumerate()
19845                .flat_map(|(ix, snippet)| {
19846                    snippet
19847                        .prefix
19848                        .iter()
19849                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19850                })
19851                .collect::<Vec<StringMatchCandidate>>();
19852
19853            let mut matches = fuzzy::match_strings(
19854                &candidates,
19855                &last_word,
19856                last_word.chars().any(|c| c.is_uppercase()),
19857                100,
19858                &Default::default(),
19859                executor.clone(),
19860            )
19861            .await;
19862
19863            // Remove all candidates where the query's start does not match the start of any word in the candidate
19864            if let Some(query_start) = last_word.chars().next() {
19865                matches.retain(|string_match| {
19866                    split_words(&string_match.string).any(|word| {
19867                        // Check that the first codepoint of the word as lowercase matches the first
19868                        // codepoint of the query as lowercase
19869                        word.chars()
19870                            .flat_map(|codepoint| codepoint.to_lowercase())
19871                            .zip(query_start.to_lowercase())
19872                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19873                    })
19874                });
19875            }
19876
19877            let matched_strings = matches
19878                .into_iter()
19879                .map(|m| m.string)
19880                .collect::<HashSet<_>>();
19881
19882            let mut result: Vec<Completion> = snippets
19883                .iter()
19884                .filter_map(|snippet| {
19885                    let matching_prefix = snippet
19886                        .prefix
19887                        .iter()
19888                        .find(|prefix| matched_strings.contains(*prefix))?;
19889                    let start = as_offset - last_word.len();
19890                    let start = snapshot.anchor_before(start);
19891                    let range = start..buffer_position;
19892                    let lsp_start = to_lsp(&start);
19893                    let lsp_range = lsp::Range {
19894                        start: lsp_start,
19895                        end: lsp_end,
19896                    };
19897                    Some(Completion {
19898                        replace_range: range,
19899                        new_text: snippet.body.clone(),
19900                        source: CompletionSource::Lsp {
19901                            insert_range: None,
19902                            server_id: LanguageServerId(usize::MAX),
19903                            resolved: true,
19904                            lsp_completion: Box::new(lsp::CompletionItem {
19905                                label: snippet.prefix.first().unwrap().clone(),
19906                                kind: Some(CompletionItemKind::SNIPPET),
19907                                label_details: snippet.description.as_ref().map(|description| {
19908                                    lsp::CompletionItemLabelDetails {
19909                                        detail: Some(description.clone()),
19910                                        description: None,
19911                                    }
19912                                }),
19913                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19914                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19915                                    lsp::InsertReplaceEdit {
19916                                        new_text: snippet.body.clone(),
19917                                        insert: lsp_range,
19918                                        replace: lsp_range,
19919                                    },
19920                                )),
19921                                filter_text: Some(snippet.body.clone()),
19922                                sort_text: Some(char::MAX.to_string()),
19923                                ..lsp::CompletionItem::default()
19924                            }),
19925                            lsp_defaults: None,
19926                        },
19927                        label: CodeLabel {
19928                            text: matching_prefix.clone(),
19929                            runs: Vec::new(),
19930                            filter_range: 0..matching_prefix.len(),
19931                        },
19932                        icon_path: None,
19933                        documentation: Some(
19934                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
19935                                single_line: snippet.name.clone().into(),
19936                                plain_text: snippet
19937                                    .description
19938                                    .clone()
19939                                    .map(|description| description.into()),
19940                            },
19941                        ),
19942                        insert_text_mode: None,
19943                        confirm: None,
19944                    })
19945                })
19946                .collect();
19947
19948            all_results.append(&mut result);
19949        }
19950
19951        Ok(all_results)
19952    })
19953}
19954
19955impl CompletionProvider for Entity<Project> {
19956    fn completions(
19957        &self,
19958        _excerpt_id: ExcerptId,
19959        buffer: &Entity<Buffer>,
19960        buffer_position: text::Anchor,
19961        options: CompletionContext,
19962        _window: &mut Window,
19963        cx: &mut Context<Editor>,
19964    ) -> Task<Result<Option<Vec<Completion>>>> {
19965        self.update(cx, |project, cx| {
19966            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19967            let project_completions = project.completions(buffer, buffer_position, options, cx);
19968            cx.background_spawn(async move {
19969                let snippets_completions = snippets.await?;
19970                match project_completions.await? {
19971                    Some(mut completions) => {
19972                        completions.extend(snippets_completions);
19973                        Ok(Some(completions))
19974                    }
19975                    None => {
19976                        if snippets_completions.is_empty() {
19977                            Ok(None)
19978                        } else {
19979                            Ok(Some(snippets_completions))
19980                        }
19981                    }
19982                }
19983            })
19984        })
19985    }
19986
19987    fn resolve_completions(
19988        &self,
19989        buffer: Entity<Buffer>,
19990        completion_indices: Vec<usize>,
19991        completions: Rc<RefCell<Box<[Completion]>>>,
19992        cx: &mut Context<Editor>,
19993    ) -> Task<Result<bool>> {
19994        self.update(cx, |project, cx| {
19995            project.lsp_store().update(cx, |lsp_store, cx| {
19996                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19997            })
19998        })
19999    }
20000
20001    fn apply_additional_edits_for_completion(
20002        &self,
20003        buffer: Entity<Buffer>,
20004        completions: Rc<RefCell<Box<[Completion]>>>,
20005        completion_index: usize,
20006        push_to_history: bool,
20007        cx: &mut Context<Editor>,
20008    ) -> Task<Result<Option<language::Transaction>>> {
20009        self.update(cx, |project, cx| {
20010            project.lsp_store().update(cx, |lsp_store, cx| {
20011                lsp_store.apply_additional_edits_for_completion(
20012                    buffer,
20013                    completions,
20014                    completion_index,
20015                    push_to_history,
20016                    cx,
20017                )
20018            })
20019        })
20020    }
20021
20022    fn is_completion_trigger(
20023        &self,
20024        buffer: &Entity<Buffer>,
20025        position: language::Anchor,
20026        text: &str,
20027        trigger_in_words: bool,
20028        cx: &mut Context<Editor>,
20029    ) -> bool {
20030        let mut chars = text.chars();
20031        let char = if let Some(char) = chars.next() {
20032            char
20033        } else {
20034            return false;
20035        };
20036        if chars.next().is_some() {
20037            return false;
20038        }
20039
20040        let buffer = buffer.read(cx);
20041        let snapshot = buffer.snapshot();
20042        if !snapshot.settings_at(position, cx).show_completions_on_input {
20043            return false;
20044        }
20045        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20046        if trigger_in_words && classifier.is_word(char) {
20047            return true;
20048        }
20049
20050        buffer.completion_triggers().contains(text)
20051    }
20052}
20053
20054impl SemanticsProvider for Entity<Project> {
20055    fn hover(
20056        &self,
20057        buffer: &Entity<Buffer>,
20058        position: text::Anchor,
20059        cx: &mut App,
20060    ) -> Option<Task<Vec<project::Hover>>> {
20061        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20062    }
20063
20064    fn document_highlights(
20065        &self,
20066        buffer: &Entity<Buffer>,
20067        position: text::Anchor,
20068        cx: &mut App,
20069    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20070        Some(self.update(cx, |project, cx| {
20071            project.document_highlights(buffer, position, cx)
20072        }))
20073    }
20074
20075    fn definitions(
20076        &self,
20077        buffer: &Entity<Buffer>,
20078        position: text::Anchor,
20079        kind: GotoDefinitionKind,
20080        cx: &mut App,
20081    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20082        Some(self.update(cx, |project, cx| match kind {
20083            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20084            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20085            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20086            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20087        }))
20088    }
20089
20090    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20091        // TODO: make this work for remote projects
20092        self.update(cx, |project, cx| {
20093            if project
20094                .active_debug_session(cx)
20095                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20096            {
20097                return true;
20098            }
20099
20100            buffer.update(cx, |buffer, cx| {
20101                project.any_language_server_supports_inlay_hints(buffer, cx)
20102            })
20103        })
20104    }
20105
20106    fn inline_values(
20107        &self,
20108        buffer_handle: Entity<Buffer>,
20109
20110        range: Range<text::Anchor>,
20111        cx: &mut App,
20112    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20113        self.update(cx, |project, cx| {
20114            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20115
20116            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20117        })
20118    }
20119
20120    fn inlay_hints(
20121        &self,
20122        buffer_handle: Entity<Buffer>,
20123        range: Range<text::Anchor>,
20124        cx: &mut App,
20125    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20126        Some(self.update(cx, |project, cx| {
20127            project.inlay_hints(buffer_handle, range, cx)
20128        }))
20129    }
20130
20131    fn resolve_inlay_hint(
20132        &self,
20133        hint: InlayHint,
20134        buffer_handle: Entity<Buffer>,
20135        server_id: LanguageServerId,
20136        cx: &mut App,
20137    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20138        Some(self.update(cx, |project, cx| {
20139            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20140        }))
20141    }
20142
20143    fn range_for_rename(
20144        &self,
20145        buffer: &Entity<Buffer>,
20146        position: text::Anchor,
20147        cx: &mut App,
20148    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20149        Some(self.update(cx, |project, cx| {
20150            let buffer = buffer.clone();
20151            let task = project.prepare_rename(buffer.clone(), position, cx);
20152            cx.spawn(async move |_, cx| {
20153                Ok(match task.await? {
20154                    PrepareRenameResponse::Success(range) => Some(range),
20155                    PrepareRenameResponse::InvalidPosition => None,
20156                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20157                        // Fallback on using TreeSitter info to determine identifier range
20158                        buffer.read_with(cx, |buffer, _| {
20159                            let snapshot = buffer.snapshot();
20160                            let (range, kind) = snapshot.surrounding_word(position);
20161                            if kind != Some(CharKind::Word) {
20162                                return None;
20163                            }
20164                            Some(
20165                                snapshot.anchor_before(range.start)
20166                                    ..snapshot.anchor_after(range.end),
20167                            )
20168                        })?
20169                    }
20170                })
20171            })
20172        }))
20173    }
20174
20175    fn perform_rename(
20176        &self,
20177        buffer: &Entity<Buffer>,
20178        position: text::Anchor,
20179        new_name: String,
20180        cx: &mut App,
20181    ) -> Option<Task<Result<ProjectTransaction>>> {
20182        Some(self.update(cx, |project, cx| {
20183            project.perform_rename(buffer.clone(), position, new_name, cx)
20184        }))
20185    }
20186}
20187
20188fn inlay_hint_settings(
20189    location: Anchor,
20190    snapshot: &MultiBufferSnapshot,
20191    cx: &mut Context<Editor>,
20192) -> InlayHintSettings {
20193    let file = snapshot.file_at(location);
20194    let language = snapshot.language_at(location).map(|l| l.name());
20195    language_settings(language, file, cx).inlay_hints
20196}
20197
20198fn consume_contiguous_rows(
20199    contiguous_row_selections: &mut Vec<Selection<Point>>,
20200    selection: &Selection<Point>,
20201    display_map: &DisplaySnapshot,
20202    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20203) -> (MultiBufferRow, MultiBufferRow) {
20204    contiguous_row_selections.push(selection.clone());
20205    let start_row = MultiBufferRow(selection.start.row);
20206    let mut end_row = ending_row(selection, display_map);
20207
20208    while let Some(next_selection) = selections.peek() {
20209        if next_selection.start.row <= end_row.0 {
20210            end_row = ending_row(next_selection, display_map);
20211            contiguous_row_selections.push(selections.next().unwrap().clone());
20212        } else {
20213            break;
20214        }
20215    }
20216    (start_row, end_row)
20217}
20218
20219fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20220    if next_selection.end.column > 0 || next_selection.is_empty() {
20221        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20222    } else {
20223        MultiBufferRow(next_selection.end.row)
20224    }
20225}
20226
20227impl EditorSnapshot {
20228    pub fn remote_selections_in_range<'a>(
20229        &'a self,
20230        range: &'a Range<Anchor>,
20231        collaboration_hub: &dyn CollaborationHub,
20232        cx: &'a App,
20233    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20234        let participant_names = collaboration_hub.user_names(cx);
20235        let participant_indices = collaboration_hub.user_participant_indices(cx);
20236        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20237        let collaborators_by_replica_id = collaborators_by_peer_id
20238            .values()
20239            .map(|collaborator| (collaborator.replica_id, collaborator))
20240            .collect::<HashMap<_, _>>();
20241        self.buffer_snapshot
20242            .selections_in_range(range, false)
20243            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20244                if replica_id == AGENT_REPLICA_ID {
20245                    Some(RemoteSelection {
20246                        replica_id,
20247                        selection,
20248                        cursor_shape,
20249                        line_mode,
20250                        collaborator_id: CollaboratorId::Agent,
20251                        user_name: Some("Agent".into()),
20252                        color: cx.theme().players().agent(),
20253                    })
20254                } else {
20255                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20256                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20257                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20258                    Some(RemoteSelection {
20259                        replica_id,
20260                        selection,
20261                        cursor_shape,
20262                        line_mode,
20263                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20264                        user_name,
20265                        color: if let Some(index) = participant_index {
20266                            cx.theme().players().color_for_participant(index.0)
20267                        } else {
20268                            cx.theme().players().absent()
20269                        },
20270                    })
20271                }
20272            })
20273    }
20274
20275    pub fn hunks_for_ranges(
20276        &self,
20277        ranges: impl IntoIterator<Item = Range<Point>>,
20278    ) -> Vec<MultiBufferDiffHunk> {
20279        let mut hunks = Vec::new();
20280        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20281            HashMap::default();
20282        for query_range in ranges {
20283            let query_rows =
20284                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20285            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20286                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20287            ) {
20288                // Include deleted hunks that are adjacent to the query range, because
20289                // otherwise they would be missed.
20290                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20291                if hunk.status().is_deleted() {
20292                    intersects_range |= hunk.row_range.start == query_rows.end;
20293                    intersects_range |= hunk.row_range.end == query_rows.start;
20294                }
20295                if intersects_range {
20296                    if !processed_buffer_rows
20297                        .entry(hunk.buffer_id)
20298                        .or_default()
20299                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20300                    {
20301                        continue;
20302                    }
20303                    hunks.push(hunk);
20304                }
20305            }
20306        }
20307
20308        hunks
20309    }
20310
20311    fn display_diff_hunks_for_rows<'a>(
20312        &'a self,
20313        display_rows: Range<DisplayRow>,
20314        folded_buffers: &'a HashSet<BufferId>,
20315    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20316        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20317        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20318
20319        self.buffer_snapshot
20320            .diff_hunks_in_range(buffer_start..buffer_end)
20321            .filter_map(|hunk| {
20322                if folded_buffers.contains(&hunk.buffer_id) {
20323                    return None;
20324                }
20325
20326                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20327                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20328
20329                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20330                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20331
20332                let display_hunk = if hunk_display_start.column() != 0 {
20333                    DisplayDiffHunk::Folded {
20334                        display_row: hunk_display_start.row(),
20335                    }
20336                } else {
20337                    let mut end_row = hunk_display_end.row();
20338                    if hunk_display_end.column() > 0 {
20339                        end_row.0 += 1;
20340                    }
20341                    let is_created_file = hunk.is_created_file();
20342                    DisplayDiffHunk::Unfolded {
20343                        status: hunk.status(),
20344                        diff_base_byte_range: hunk.diff_base_byte_range,
20345                        display_row_range: hunk_display_start.row()..end_row,
20346                        multi_buffer_range: Anchor::range_in_buffer(
20347                            hunk.excerpt_id,
20348                            hunk.buffer_id,
20349                            hunk.buffer_range,
20350                        ),
20351                        is_created_file,
20352                    }
20353                };
20354
20355                Some(display_hunk)
20356            })
20357    }
20358
20359    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20360        self.display_snapshot.buffer_snapshot.language_at(position)
20361    }
20362
20363    pub fn is_focused(&self) -> bool {
20364        self.is_focused
20365    }
20366
20367    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20368        self.placeholder_text.as_ref()
20369    }
20370
20371    pub fn scroll_position(&self) -> gpui::Point<f32> {
20372        self.scroll_anchor.scroll_position(&self.display_snapshot)
20373    }
20374
20375    fn gutter_dimensions(
20376        &self,
20377        font_id: FontId,
20378        font_size: Pixels,
20379        max_line_number_width: Pixels,
20380        cx: &App,
20381    ) -> Option<GutterDimensions> {
20382        if !self.show_gutter {
20383            return None;
20384        }
20385
20386        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20387        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20388
20389        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20390            matches!(
20391                ProjectSettings::get_global(cx).git.git_gutter,
20392                Some(GitGutterSetting::TrackedFiles)
20393            )
20394        });
20395        let gutter_settings = EditorSettings::get_global(cx).gutter;
20396        let show_line_numbers = self
20397            .show_line_numbers
20398            .unwrap_or(gutter_settings.line_numbers);
20399        let line_gutter_width = if show_line_numbers {
20400            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20401            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20402            max_line_number_width.max(min_width_for_number_on_gutter)
20403        } else {
20404            0.0.into()
20405        };
20406
20407        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20408        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20409
20410        let git_blame_entries_width =
20411            self.git_blame_gutter_max_author_length
20412                .map(|max_author_length| {
20413                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20414                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20415
20416                    /// The number of characters to dedicate to gaps and margins.
20417                    const SPACING_WIDTH: usize = 4;
20418
20419                    let max_char_count = max_author_length.min(renderer.max_author_length())
20420                        + ::git::SHORT_SHA_LENGTH
20421                        + MAX_RELATIVE_TIMESTAMP.len()
20422                        + SPACING_WIDTH;
20423
20424                    em_advance * max_char_count
20425                });
20426
20427        let is_singleton = self.buffer_snapshot.is_singleton();
20428
20429        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20430        left_padding += if !is_singleton {
20431            em_width * 4.0
20432        } else if show_runnables || show_breakpoints {
20433            em_width * 3.0
20434        } else if show_git_gutter && show_line_numbers {
20435            em_width * 2.0
20436        } else if show_git_gutter || show_line_numbers {
20437            em_width
20438        } else {
20439            px(0.)
20440        };
20441
20442        let shows_folds = is_singleton && gutter_settings.folds;
20443
20444        let right_padding = if shows_folds && show_line_numbers {
20445            em_width * 4.0
20446        } else if shows_folds || (!is_singleton && show_line_numbers) {
20447            em_width * 3.0
20448        } else if show_line_numbers {
20449            em_width
20450        } else {
20451            px(0.)
20452        };
20453
20454        Some(GutterDimensions {
20455            left_padding,
20456            right_padding,
20457            width: line_gutter_width + left_padding + right_padding,
20458            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20459            git_blame_entries_width,
20460        })
20461    }
20462
20463    pub fn render_crease_toggle(
20464        &self,
20465        buffer_row: MultiBufferRow,
20466        row_contains_cursor: bool,
20467        editor: Entity<Editor>,
20468        window: &mut Window,
20469        cx: &mut App,
20470    ) -> Option<AnyElement> {
20471        let folded = self.is_line_folded(buffer_row);
20472        let mut is_foldable = false;
20473
20474        if let Some(crease) = self
20475            .crease_snapshot
20476            .query_row(buffer_row, &self.buffer_snapshot)
20477        {
20478            is_foldable = true;
20479            match crease {
20480                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20481                    if let Some(render_toggle) = render_toggle {
20482                        let toggle_callback =
20483                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20484                                if folded {
20485                                    editor.update(cx, |editor, cx| {
20486                                        editor.fold_at(buffer_row, window, cx)
20487                                    });
20488                                } else {
20489                                    editor.update(cx, |editor, cx| {
20490                                        editor.unfold_at(buffer_row, window, cx)
20491                                    });
20492                                }
20493                            });
20494                        return Some((render_toggle)(
20495                            buffer_row,
20496                            folded,
20497                            toggle_callback,
20498                            window,
20499                            cx,
20500                        ));
20501                    }
20502                }
20503            }
20504        }
20505
20506        is_foldable |= self.starts_indent(buffer_row);
20507
20508        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20509            Some(
20510                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20511                    .toggle_state(folded)
20512                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20513                        if folded {
20514                            this.unfold_at(buffer_row, window, cx);
20515                        } else {
20516                            this.fold_at(buffer_row, window, cx);
20517                        }
20518                    }))
20519                    .into_any_element(),
20520            )
20521        } else {
20522            None
20523        }
20524    }
20525
20526    pub fn render_crease_trailer(
20527        &self,
20528        buffer_row: MultiBufferRow,
20529        window: &mut Window,
20530        cx: &mut App,
20531    ) -> Option<AnyElement> {
20532        let folded = self.is_line_folded(buffer_row);
20533        if let Crease::Inline { render_trailer, .. } = self
20534            .crease_snapshot
20535            .query_row(buffer_row, &self.buffer_snapshot)?
20536        {
20537            let render_trailer = render_trailer.as_ref()?;
20538            Some(render_trailer(buffer_row, folded, window, cx))
20539        } else {
20540            None
20541        }
20542    }
20543}
20544
20545impl Deref for EditorSnapshot {
20546    type Target = DisplaySnapshot;
20547
20548    fn deref(&self) -> &Self::Target {
20549        &self.display_snapshot
20550    }
20551}
20552
20553#[derive(Clone, Debug, PartialEq, Eq)]
20554pub enum EditorEvent {
20555    InputIgnored {
20556        text: Arc<str>,
20557    },
20558    InputHandled {
20559        utf16_range_to_replace: Option<Range<isize>>,
20560        text: Arc<str>,
20561    },
20562    ExcerptsAdded {
20563        buffer: Entity<Buffer>,
20564        predecessor: ExcerptId,
20565        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20566    },
20567    ExcerptsRemoved {
20568        ids: Vec<ExcerptId>,
20569        removed_buffer_ids: Vec<BufferId>,
20570    },
20571    BufferFoldToggled {
20572        ids: Vec<ExcerptId>,
20573        folded: bool,
20574    },
20575    ExcerptsEdited {
20576        ids: Vec<ExcerptId>,
20577    },
20578    ExcerptsExpanded {
20579        ids: Vec<ExcerptId>,
20580    },
20581    BufferEdited,
20582    Edited {
20583        transaction_id: clock::Lamport,
20584    },
20585    Reparsed(BufferId),
20586    Focused,
20587    FocusedIn,
20588    Blurred,
20589    DirtyChanged,
20590    Saved,
20591    TitleChanged,
20592    DiffBaseChanged,
20593    SelectionsChanged {
20594        local: bool,
20595    },
20596    ScrollPositionChanged {
20597        local: bool,
20598        autoscroll: bool,
20599    },
20600    Closed,
20601    TransactionUndone {
20602        transaction_id: clock::Lamport,
20603    },
20604    TransactionBegun {
20605        transaction_id: clock::Lamport,
20606    },
20607    Reloaded,
20608    CursorShapeChanged,
20609    PushedToNavHistory {
20610        anchor: Anchor,
20611        is_deactivate: bool,
20612    },
20613}
20614
20615impl EventEmitter<EditorEvent> for Editor {}
20616
20617impl Focusable for Editor {
20618    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20619        self.focus_handle.clone()
20620    }
20621}
20622
20623impl Render for Editor {
20624    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20625        let settings = ThemeSettings::get_global(cx);
20626
20627        let mut text_style = match self.mode {
20628            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20629                color: cx.theme().colors().editor_foreground,
20630                font_family: settings.ui_font.family.clone(),
20631                font_features: settings.ui_font.features.clone(),
20632                font_fallbacks: settings.ui_font.fallbacks.clone(),
20633                font_size: rems(0.875).into(),
20634                font_weight: settings.ui_font.weight,
20635                line_height: relative(settings.buffer_line_height.value()),
20636                ..Default::default()
20637            },
20638            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20639                color: cx.theme().colors().editor_foreground,
20640                font_family: settings.buffer_font.family.clone(),
20641                font_features: settings.buffer_font.features.clone(),
20642                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20643                font_size: settings.buffer_font_size(cx).into(),
20644                font_weight: settings.buffer_font.weight,
20645                line_height: relative(settings.buffer_line_height.value()),
20646                ..Default::default()
20647            },
20648        };
20649        if let Some(text_style_refinement) = &self.text_style_refinement {
20650            text_style.refine(text_style_refinement)
20651        }
20652
20653        let background = match self.mode {
20654            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20655            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20656            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20657            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20658        };
20659
20660        EditorElement::new(
20661            &cx.entity(),
20662            EditorStyle {
20663                background,
20664                local_player: cx.theme().players().local(),
20665                text: text_style,
20666                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20667                syntax: cx.theme().syntax().clone(),
20668                status: cx.theme().status().clone(),
20669                inlay_hints_style: make_inlay_hints_style(cx),
20670                inline_completion_styles: make_suggestion_styles(cx),
20671                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20672                show_underlines: !self.mode.is_minimap(),
20673            },
20674        )
20675    }
20676}
20677
20678impl EntityInputHandler for Editor {
20679    fn text_for_range(
20680        &mut self,
20681        range_utf16: Range<usize>,
20682        adjusted_range: &mut Option<Range<usize>>,
20683        _: &mut Window,
20684        cx: &mut Context<Self>,
20685    ) -> Option<String> {
20686        let snapshot = self.buffer.read(cx).read(cx);
20687        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20688        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20689        if (start.0..end.0) != range_utf16 {
20690            adjusted_range.replace(start.0..end.0);
20691        }
20692        Some(snapshot.text_for_range(start..end).collect())
20693    }
20694
20695    fn selected_text_range(
20696        &mut self,
20697        ignore_disabled_input: bool,
20698        _: &mut Window,
20699        cx: &mut Context<Self>,
20700    ) -> Option<UTF16Selection> {
20701        // Prevent the IME menu from appearing when holding down an alphabetic key
20702        // while input is disabled.
20703        if !ignore_disabled_input && !self.input_enabled {
20704            return None;
20705        }
20706
20707        let selection = self.selections.newest::<OffsetUtf16>(cx);
20708        let range = selection.range();
20709
20710        Some(UTF16Selection {
20711            range: range.start.0..range.end.0,
20712            reversed: selection.reversed,
20713        })
20714    }
20715
20716    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20717        let snapshot = self.buffer.read(cx).read(cx);
20718        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20719        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20720    }
20721
20722    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20723        self.clear_highlights::<InputComposition>(cx);
20724        self.ime_transaction.take();
20725    }
20726
20727    fn replace_text_in_range(
20728        &mut self,
20729        range_utf16: Option<Range<usize>>,
20730        text: &str,
20731        window: &mut Window,
20732        cx: &mut Context<Self>,
20733    ) {
20734        if !self.input_enabled {
20735            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20736            return;
20737        }
20738
20739        self.transact(window, cx, |this, window, cx| {
20740            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20741                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20742                Some(this.selection_replacement_ranges(range_utf16, cx))
20743            } else {
20744                this.marked_text_ranges(cx)
20745            };
20746
20747            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20748                let newest_selection_id = this.selections.newest_anchor().id;
20749                this.selections
20750                    .all::<OffsetUtf16>(cx)
20751                    .iter()
20752                    .zip(ranges_to_replace.iter())
20753                    .find_map(|(selection, range)| {
20754                        if selection.id == newest_selection_id {
20755                            Some(
20756                                (range.start.0 as isize - selection.head().0 as isize)
20757                                    ..(range.end.0 as isize - selection.head().0 as isize),
20758                            )
20759                        } else {
20760                            None
20761                        }
20762                    })
20763            });
20764
20765            cx.emit(EditorEvent::InputHandled {
20766                utf16_range_to_replace: range_to_replace,
20767                text: text.into(),
20768            });
20769
20770            if let Some(new_selected_ranges) = new_selected_ranges {
20771                this.change_selections(None, window, cx, |selections| {
20772                    selections.select_ranges(new_selected_ranges)
20773                });
20774                this.backspace(&Default::default(), window, cx);
20775            }
20776
20777            this.handle_input(text, window, cx);
20778        });
20779
20780        if let Some(transaction) = self.ime_transaction {
20781            self.buffer.update(cx, |buffer, cx| {
20782                buffer.group_until_transaction(transaction, cx);
20783            });
20784        }
20785
20786        self.unmark_text(window, cx);
20787    }
20788
20789    fn replace_and_mark_text_in_range(
20790        &mut self,
20791        range_utf16: Option<Range<usize>>,
20792        text: &str,
20793        new_selected_range_utf16: Option<Range<usize>>,
20794        window: &mut Window,
20795        cx: &mut Context<Self>,
20796    ) {
20797        if !self.input_enabled {
20798            return;
20799        }
20800
20801        let transaction = self.transact(window, cx, |this, window, cx| {
20802            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20803                let snapshot = this.buffer.read(cx).read(cx);
20804                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20805                    for marked_range in &mut marked_ranges {
20806                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20807                        marked_range.start.0 += relative_range_utf16.start;
20808                        marked_range.start =
20809                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20810                        marked_range.end =
20811                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20812                    }
20813                }
20814                Some(marked_ranges)
20815            } else if let Some(range_utf16) = range_utf16 {
20816                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20817                Some(this.selection_replacement_ranges(range_utf16, cx))
20818            } else {
20819                None
20820            };
20821
20822            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20823                let newest_selection_id = this.selections.newest_anchor().id;
20824                this.selections
20825                    .all::<OffsetUtf16>(cx)
20826                    .iter()
20827                    .zip(ranges_to_replace.iter())
20828                    .find_map(|(selection, range)| {
20829                        if selection.id == newest_selection_id {
20830                            Some(
20831                                (range.start.0 as isize - selection.head().0 as isize)
20832                                    ..(range.end.0 as isize - selection.head().0 as isize),
20833                            )
20834                        } else {
20835                            None
20836                        }
20837                    })
20838            });
20839
20840            cx.emit(EditorEvent::InputHandled {
20841                utf16_range_to_replace: range_to_replace,
20842                text: text.into(),
20843            });
20844
20845            if let Some(ranges) = ranges_to_replace {
20846                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20847            }
20848
20849            let marked_ranges = {
20850                let snapshot = this.buffer.read(cx).read(cx);
20851                this.selections
20852                    .disjoint_anchors()
20853                    .iter()
20854                    .map(|selection| {
20855                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20856                    })
20857                    .collect::<Vec<_>>()
20858            };
20859
20860            if text.is_empty() {
20861                this.unmark_text(window, cx);
20862            } else {
20863                this.highlight_text::<InputComposition>(
20864                    marked_ranges.clone(),
20865                    HighlightStyle {
20866                        underline: Some(UnderlineStyle {
20867                            thickness: px(1.),
20868                            color: None,
20869                            wavy: false,
20870                        }),
20871                        ..Default::default()
20872                    },
20873                    cx,
20874                );
20875            }
20876
20877            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20878            let use_autoclose = this.use_autoclose;
20879            let use_auto_surround = this.use_auto_surround;
20880            this.set_use_autoclose(false);
20881            this.set_use_auto_surround(false);
20882            this.handle_input(text, window, cx);
20883            this.set_use_autoclose(use_autoclose);
20884            this.set_use_auto_surround(use_auto_surround);
20885
20886            if let Some(new_selected_range) = new_selected_range_utf16 {
20887                let snapshot = this.buffer.read(cx).read(cx);
20888                let new_selected_ranges = marked_ranges
20889                    .into_iter()
20890                    .map(|marked_range| {
20891                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20892                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20893                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20894                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20895                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20896                    })
20897                    .collect::<Vec<_>>();
20898
20899                drop(snapshot);
20900                this.change_selections(None, window, cx, |selections| {
20901                    selections.select_ranges(new_selected_ranges)
20902                });
20903            }
20904        });
20905
20906        self.ime_transaction = self.ime_transaction.or(transaction);
20907        if let Some(transaction) = self.ime_transaction {
20908            self.buffer.update(cx, |buffer, cx| {
20909                buffer.group_until_transaction(transaction, cx);
20910            });
20911        }
20912
20913        if self.text_highlights::<InputComposition>(cx).is_none() {
20914            self.ime_transaction.take();
20915        }
20916    }
20917
20918    fn bounds_for_range(
20919        &mut self,
20920        range_utf16: Range<usize>,
20921        element_bounds: gpui::Bounds<Pixels>,
20922        window: &mut Window,
20923        cx: &mut Context<Self>,
20924    ) -> Option<gpui::Bounds<Pixels>> {
20925        let text_layout_details = self.text_layout_details(window);
20926        let gpui::Size {
20927            width: em_width,
20928            height: line_height,
20929        } = self.character_size(window);
20930
20931        let snapshot = self.snapshot(window, cx);
20932        let scroll_position = snapshot.scroll_position();
20933        let scroll_left = scroll_position.x * em_width;
20934
20935        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20936        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20937            + self.gutter_dimensions.width
20938            + self.gutter_dimensions.margin;
20939        let y = line_height * (start.row().as_f32() - scroll_position.y);
20940
20941        Some(Bounds {
20942            origin: element_bounds.origin + point(x, y),
20943            size: size(em_width, line_height),
20944        })
20945    }
20946
20947    fn character_index_for_point(
20948        &mut self,
20949        point: gpui::Point<Pixels>,
20950        _window: &mut Window,
20951        _cx: &mut Context<Self>,
20952    ) -> Option<usize> {
20953        let position_map = self.last_position_map.as_ref()?;
20954        if !position_map.text_hitbox.contains(&point) {
20955            return None;
20956        }
20957        let display_point = position_map.point_for_position(point).previous_valid;
20958        let anchor = position_map
20959            .snapshot
20960            .display_point_to_anchor(display_point, Bias::Left);
20961        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20962        Some(utf16_offset.0)
20963    }
20964}
20965
20966trait SelectionExt {
20967    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20968    fn spanned_rows(
20969        &self,
20970        include_end_if_at_line_start: bool,
20971        map: &DisplaySnapshot,
20972    ) -> Range<MultiBufferRow>;
20973}
20974
20975impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20976    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20977        let start = self
20978            .start
20979            .to_point(&map.buffer_snapshot)
20980            .to_display_point(map);
20981        let end = self
20982            .end
20983            .to_point(&map.buffer_snapshot)
20984            .to_display_point(map);
20985        if self.reversed {
20986            end..start
20987        } else {
20988            start..end
20989        }
20990    }
20991
20992    fn spanned_rows(
20993        &self,
20994        include_end_if_at_line_start: bool,
20995        map: &DisplaySnapshot,
20996    ) -> Range<MultiBufferRow> {
20997        let start = self.start.to_point(&map.buffer_snapshot);
20998        let mut end = self.end.to_point(&map.buffer_snapshot);
20999        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21000            end.row -= 1;
21001        }
21002
21003        let buffer_start = map.prev_line_boundary(start).0;
21004        let buffer_end = map.next_line_boundary(end).0;
21005        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21006    }
21007}
21008
21009impl<T: InvalidationRegion> InvalidationStack<T> {
21010    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21011    where
21012        S: Clone + ToOffset,
21013    {
21014        while let Some(region) = self.last() {
21015            let all_selections_inside_invalidation_ranges =
21016                if selections.len() == region.ranges().len() {
21017                    selections
21018                        .iter()
21019                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21020                        .all(|(selection, invalidation_range)| {
21021                            let head = selection.head().to_offset(buffer);
21022                            invalidation_range.start <= head && invalidation_range.end >= head
21023                        })
21024                } else {
21025                    false
21026                };
21027
21028            if all_selections_inside_invalidation_ranges {
21029                break;
21030            } else {
21031                self.pop();
21032            }
21033        }
21034    }
21035}
21036
21037impl<T> Default for InvalidationStack<T> {
21038    fn default() -> Self {
21039        Self(Default::default())
21040    }
21041}
21042
21043impl<T> Deref for InvalidationStack<T> {
21044    type Target = Vec<T>;
21045
21046    fn deref(&self) -> &Self::Target {
21047        &self.0
21048    }
21049}
21050
21051impl<T> DerefMut for InvalidationStack<T> {
21052    fn deref_mut(&mut self) -> &mut Self::Target {
21053        &mut self.0
21054    }
21055}
21056
21057impl InvalidationRegion for SnippetState {
21058    fn ranges(&self) -> &[Range<Anchor>] {
21059        &self.ranges[self.active_index]
21060    }
21061}
21062
21063fn inline_completion_edit_text(
21064    current_snapshot: &BufferSnapshot,
21065    edits: &[(Range<Anchor>, String)],
21066    edit_preview: &EditPreview,
21067    include_deletions: bool,
21068    cx: &App,
21069) -> HighlightedText {
21070    let edits = edits
21071        .iter()
21072        .map(|(anchor, text)| {
21073            (
21074                anchor.start.text_anchor..anchor.end.text_anchor,
21075                text.clone(),
21076            )
21077        })
21078        .collect::<Vec<_>>();
21079
21080    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21081}
21082
21083pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21084    match severity {
21085        lsp::DiagnosticSeverity::ERROR => colors.error,
21086        lsp::DiagnosticSeverity::WARNING => colors.warning,
21087        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21088        lsp::DiagnosticSeverity::HINT => colors.info,
21089        _ => colors.ignored,
21090    }
21091}
21092
21093pub fn styled_runs_for_code_label<'a>(
21094    label: &'a CodeLabel,
21095    syntax_theme: &'a theme::SyntaxTheme,
21096) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21097    let fade_out = HighlightStyle {
21098        fade_out: Some(0.35),
21099        ..Default::default()
21100    };
21101
21102    let mut prev_end = label.filter_range.end;
21103    label
21104        .runs
21105        .iter()
21106        .enumerate()
21107        .flat_map(move |(ix, (range, highlight_id))| {
21108            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21109                style
21110            } else {
21111                return Default::default();
21112            };
21113            let mut muted_style = style;
21114            muted_style.highlight(fade_out);
21115
21116            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21117            if range.start >= label.filter_range.end {
21118                if range.start > prev_end {
21119                    runs.push((prev_end..range.start, fade_out));
21120                }
21121                runs.push((range.clone(), muted_style));
21122            } else if range.end <= label.filter_range.end {
21123                runs.push((range.clone(), style));
21124            } else {
21125                runs.push((range.start..label.filter_range.end, style));
21126                runs.push((label.filter_range.end..range.end, muted_style));
21127            }
21128            prev_end = cmp::max(prev_end, range.end);
21129
21130            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21131                runs.push((prev_end..label.text.len(), fade_out));
21132            }
21133
21134            runs
21135        })
21136}
21137
21138pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21139    let mut prev_index = 0;
21140    let mut prev_codepoint: Option<char> = None;
21141    text.char_indices()
21142        .chain([(text.len(), '\0')])
21143        .filter_map(move |(index, codepoint)| {
21144            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21145            let is_boundary = index == text.len()
21146                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21147                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21148            if is_boundary {
21149                let chunk = &text[prev_index..index];
21150                prev_index = index;
21151                Some(chunk)
21152            } else {
21153                None
21154            }
21155        })
21156}
21157
21158pub trait RangeToAnchorExt: Sized {
21159    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21160
21161    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21162        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21163        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21164    }
21165}
21166
21167impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21168    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21169        let start_offset = self.start.to_offset(snapshot);
21170        let end_offset = self.end.to_offset(snapshot);
21171        if start_offset == end_offset {
21172            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21173        } else {
21174            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21175        }
21176    }
21177}
21178
21179pub trait RowExt {
21180    fn as_f32(&self) -> f32;
21181
21182    fn next_row(&self) -> Self;
21183
21184    fn previous_row(&self) -> Self;
21185
21186    fn minus(&self, other: Self) -> u32;
21187}
21188
21189impl RowExt for DisplayRow {
21190    fn as_f32(&self) -> f32 {
21191        self.0 as f32
21192    }
21193
21194    fn next_row(&self) -> Self {
21195        Self(self.0 + 1)
21196    }
21197
21198    fn previous_row(&self) -> Self {
21199        Self(self.0.saturating_sub(1))
21200    }
21201
21202    fn minus(&self, other: Self) -> u32 {
21203        self.0 - other.0
21204    }
21205}
21206
21207impl RowExt for MultiBufferRow {
21208    fn as_f32(&self) -> f32 {
21209        self.0 as f32
21210    }
21211
21212    fn next_row(&self) -> Self {
21213        Self(self.0 + 1)
21214    }
21215
21216    fn previous_row(&self) -> Self {
21217        Self(self.0.saturating_sub(1))
21218    }
21219
21220    fn minus(&self, other: Self) -> u32 {
21221        self.0 - other.0
21222    }
21223}
21224
21225trait RowRangeExt {
21226    type Row;
21227
21228    fn len(&self) -> usize;
21229
21230    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21231}
21232
21233impl RowRangeExt for Range<MultiBufferRow> {
21234    type Row = MultiBufferRow;
21235
21236    fn len(&self) -> usize {
21237        (self.end.0 - self.start.0) as usize
21238    }
21239
21240    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21241        (self.start.0..self.end.0).map(MultiBufferRow)
21242    }
21243}
21244
21245impl RowRangeExt for Range<DisplayRow> {
21246    type Row = DisplayRow;
21247
21248    fn len(&self) -> usize {
21249        (self.end.0 - self.start.0) as usize
21250    }
21251
21252    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21253        (self.start.0..self.end.0).map(DisplayRow)
21254    }
21255}
21256
21257/// If select range has more than one line, we
21258/// just point the cursor to range.start.
21259fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21260    if range.start.row == range.end.row {
21261        range
21262    } else {
21263        range.start..range.start
21264    }
21265}
21266pub struct KillRing(ClipboardItem);
21267impl Global for KillRing {}
21268
21269const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21270
21271enum BreakpointPromptEditAction {
21272    Log,
21273    Condition,
21274    HitCondition,
21275}
21276
21277struct BreakpointPromptEditor {
21278    pub(crate) prompt: Entity<Editor>,
21279    editor: WeakEntity<Editor>,
21280    breakpoint_anchor: Anchor,
21281    breakpoint: Breakpoint,
21282    edit_action: BreakpointPromptEditAction,
21283    block_ids: HashSet<CustomBlockId>,
21284    editor_margins: Arc<Mutex<EditorMargins>>,
21285    _subscriptions: Vec<Subscription>,
21286}
21287
21288impl BreakpointPromptEditor {
21289    const MAX_LINES: u8 = 4;
21290
21291    fn new(
21292        editor: WeakEntity<Editor>,
21293        breakpoint_anchor: Anchor,
21294        breakpoint: Breakpoint,
21295        edit_action: BreakpointPromptEditAction,
21296        window: &mut Window,
21297        cx: &mut Context<Self>,
21298    ) -> Self {
21299        let base_text = match edit_action {
21300            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21301            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21302            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21303        }
21304        .map(|msg| msg.to_string())
21305        .unwrap_or_default();
21306
21307        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21308        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21309
21310        let prompt = cx.new(|cx| {
21311            let mut prompt = Editor::new(
21312                EditorMode::AutoHeight {
21313                    max_lines: Self::MAX_LINES as usize,
21314                },
21315                buffer,
21316                None,
21317                window,
21318                cx,
21319            );
21320            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21321            prompt.set_show_cursor_when_unfocused(false, cx);
21322            prompt.set_placeholder_text(
21323                match edit_action {
21324                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21325                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21326                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21327                },
21328                cx,
21329            );
21330
21331            prompt
21332        });
21333
21334        Self {
21335            prompt,
21336            editor,
21337            breakpoint_anchor,
21338            breakpoint,
21339            edit_action,
21340            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21341            block_ids: Default::default(),
21342            _subscriptions: vec![],
21343        }
21344    }
21345
21346    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21347        self.block_ids.extend(block_ids)
21348    }
21349
21350    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21351        if let Some(editor) = self.editor.upgrade() {
21352            let message = self
21353                .prompt
21354                .read(cx)
21355                .buffer
21356                .read(cx)
21357                .as_singleton()
21358                .expect("A multi buffer in breakpoint prompt isn't possible")
21359                .read(cx)
21360                .as_rope()
21361                .to_string();
21362
21363            editor.update(cx, |editor, cx| {
21364                editor.edit_breakpoint_at_anchor(
21365                    self.breakpoint_anchor,
21366                    self.breakpoint.clone(),
21367                    match self.edit_action {
21368                        BreakpointPromptEditAction::Log => {
21369                            BreakpointEditAction::EditLogMessage(message.into())
21370                        }
21371                        BreakpointPromptEditAction::Condition => {
21372                            BreakpointEditAction::EditCondition(message.into())
21373                        }
21374                        BreakpointPromptEditAction::HitCondition => {
21375                            BreakpointEditAction::EditHitCondition(message.into())
21376                        }
21377                    },
21378                    cx,
21379                );
21380
21381                editor.remove_blocks(self.block_ids.clone(), None, cx);
21382                cx.focus_self(window);
21383            });
21384        }
21385    }
21386
21387    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21388        self.editor
21389            .update(cx, |editor, cx| {
21390                editor.remove_blocks(self.block_ids.clone(), None, cx);
21391                window.focus(&editor.focus_handle);
21392            })
21393            .log_err();
21394    }
21395
21396    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21397        let settings = ThemeSettings::get_global(cx);
21398        let text_style = TextStyle {
21399            color: if self.prompt.read(cx).read_only(cx) {
21400                cx.theme().colors().text_disabled
21401            } else {
21402                cx.theme().colors().text
21403            },
21404            font_family: settings.buffer_font.family.clone(),
21405            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21406            font_size: settings.buffer_font_size(cx).into(),
21407            font_weight: settings.buffer_font.weight,
21408            line_height: relative(settings.buffer_line_height.value()),
21409            ..Default::default()
21410        };
21411        EditorElement::new(
21412            &self.prompt,
21413            EditorStyle {
21414                background: cx.theme().colors().editor_background,
21415                local_player: cx.theme().players().local(),
21416                text: text_style,
21417                ..Default::default()
21418            },
21419        )
21420    }
21421}
21422
21423impl Render for BreakpointPromptEditor {
21424    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21425        let editor_margins = *self.editor_margins.lock();
21426        let gutter_dimensions = editor_margins.gutter;
21427        h_flex()
21428            .key_context("Editor")
21429            .bg(cx.theme().colors().editor_background)
21430            .border_y_1()
21431            .border_color(cx.theme().status().info_border)
21432            .size_full()
21433            .py(window.line_height() / 2.5)
21434            .on_action(cx.listener(Self::confirm))
21435            .on_action(cx.listener(Self::cancel))
21436            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21437            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21438    }
21439}
21440
21441impl Focusable for BreakpointPromptEditor {
21442    fn focus_handle(&self, cx: &App) -> FocusHandle {
21443        self.prompt.focus_handle(cx)
21444    }
21445}
21446
21447fn all_edits_insertions_or_deletions(
21448    edits: &Vec<(Range<Anchor>, String)>,
21449    snapshot: &MultiBufferSnapshot,
21450) -> bool {
21451    let mut all_insertions = true;
21452    let mut all_deletions = true;
21453
21454    for (range, new_text) in edits.iter() {
21455        let range_is_empty = range.to_offset(&snapshot).is_empty();
21456        let text_is_empty = new_text.is_empty();
21457
21458        if range_is_empty != text_is_empty {
21459            if range_is_empty {
21460                all_deletions = false;
21461            } else {
21462                all_insertions = false;
21463            }
21464        } else {
21465            return false;
21466        }
21467
21468        if !all_insertions && !all_deletions {
21469            return false;
21470        }
21471    }
21472    all_insertions || all_deletions
21473}
21474
21475struct MissingEditPredictionKeybindingTooltip;
21476
21477impl Render for MissingEditPredictionKeybindingTooltip {
21478    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21479        ui::tooltip_container(window, cx, |container, _, cx| {
21480            container
21481                .flex_shrink_0()
21482                .max_w_80()
21483                .min_h(rems_from_px(124.))
21484                .justify_between()
21485                .child(
21486                    v_flex()
21487                        .flex_1()
21488                        .text_ui_sm(cx)
21489                        .child(Label::new("Conflict with Accept Keybinding"))
21490                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21491                )
21492                .child(
21493                    h_flex()
21494                        .pb_1()
21495                        .gap_1()
21496                        .items_end()
21497                        .w_full()
21498                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21499                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21500                        }))
21501                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21502                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21503                        })),
21504                )
21505        })
21506    }
21507}
21508
21509#[derive(Debug, Clone, Copy, PartialEq)]
21510pub struct LineHighlight {
21511    pub background: Background,
21512    pub border: Option<gpui::Hsla>,
21513    pub include_gutter: bool,
21514    pub type_id: Option<TypeId>,
21515}
21516
21517fn render_diff_hunk_controls(
21518    row: u32,
21519    status: &DiffHunkStatus,
21520    hunk_range: Range<Anchor>,
21521    is_created_file: bool,
21522    line_height: Pixels,
21523    editor: &Entity<Editor>,
21524    _window: &mut Window,
21525    cx: &mut App,
21526) -> AnyElement {
21527    h_flex()
21528        .h(line_height)
21529        .mr_1()
21530        .gap_1()
21531        .px_0p5()
21532        .pb_1()
21533        .border_x_1()
21534        .border_b_1()
21535        .border_color(cx.theme().colors().border_variant)
21536        .rounded_b_lg()
21537        .bg(cx.theme().colors().editor_background)
21538        .gap_1()
21539        .stop_mouse_events_except_scroll()
21540        .shadow_md()
21541        .child(if status.has_secondary_hunk() {
21542            Button::new(("stage", row as u64), "Stage")
21543                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21544                .tooltip({
21545                    let focus_handle = editor.focus_handle(cx);
21546                    move |window, cx| {
21547                        Tooltip::for_action_in(
21548                            "Stage Hunk",
21549                            &::git::ToggleStaged,
21550                            &focus_handle,
21551                            window,
21552                            cx,
21553                        )
21554                    }
21555                })
21556                .on_click({
21557                    let editor = editor.clone();
21558                    move |_event, _window, cx| {
21559                        editor.update(cx, |editor, cx| {
21560                            editor.stage_or_unstage_diff_hunks(
21561                                true,
21562                                vec![hunk_range.start..hunk_range.start],
21563                                cx,
21564                            );
21565                        });
21566                    }
21567                })
21568        } else {
21569            Button::new(("unstage", row as u64), "Unstage")
21570                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21571                .tooltip({
21572                    let focus_handle = editor.focus_handle(cx);
21573                    move |window, cx| {
21574                        Tooltip::for_action_in(
21575                            "Unstage Hunk",
21576                            &::git::ToggleStaged,
21577                            &focus_handle,
21578                            window,
21579                            cx,
21580                        )
21581                    }
21582                })
21583                .on_click({
21584                    let editor = editor.clone();
21585                    move |_event, _window, cx| {
21586                        editor.update(cx, |editor, cx| {
21587                            editor.stage_or_unstage_diff_hunks(
21588                                false,
21589                                vec![hunk_range.start..hunk_range.start],
21590                                cx,
21591                            );
21592                        });
21593                    }
21594                })
21595        })
21596        .child(
21597            Button::new(("restore", row as u64), "Restore")
21598                .tooltip({
21599                    let focus_handle = editor.focus_handle(cx);
21600                    move |window, cx| {
21601                        Tooltip::for_action_in(
21602                            "Restore Hunk",
21603                            &::git::Restore,
21604                            &focus_handle,
21605                            window,
21606                            cx,
21607                        )
21608                    }
21609                })
21610                .on_click({
21611                    let editor = editor.clone();
21612                    move |_event, window, cx| {
21613                        editor.update(cx, |editor, cx| {
21614                            let snapshot = editor.snapshot(window, cx);
21615                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21616                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21617                        });
21618                    }
21619                })
21620                .disabled(is_created_file),
21621        )
21622        .when(
21623            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21624            |el| {
21625                el.child(
21626                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21627                        .shape(IconButtonShape::Square)
21628                        .icon_size(IconSize::Small)
21629                        // .disabled(!has_multiple_hunks)
21630                        .tooltip({
21631                            let focus_handle = editor.focus_handle(cx);
21632                            move |window, cx| {
21633                                Tooltip::for_action_in(
21634                                    "Next Hunk",
21635                                    &GoToHunk,
21636                                    &focus_handle,
21637                                    window,
21638                                    cx,
21639                                )
21640                            }
21641                        })
21642                        .on_click({
21643                            let editor = editor.clone();
21644                            move |_event, window, cx| {
21645                                editor.update(cx, |editor, cx| {
21646                                    let snapshot = editor.snapshot(window, cx);
21647                                    let position =
21648                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21649                                    editor.go_to_hunk_before_or_after_position(
21650                                        &snapshot,
21651                                        position,
21652                                        Direction::Next,
21653                                        window,
21654                                        cx,
21655                                    );
21656                                    editor.expand_selected_diff_hunks(cx);
21657                                });
21658                            }
21659                        }),
21660                )
21661                .child(
21662                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21663                        .shape(IconButtonShape::Square)
21664                        .icon_size(IconSize::Small)
21665                        // .disabled(!has_multiple_hunks)
21666                        .tooltip({
21667                            let focus_handle = editor.focus_handle(cx);
21668                            move |window, cx| {
21669                                Tooltip::for_action_in(
21670                                    "Previous Hunk",
21671                                    &GoToPreviousHunk,
21672                                    &focus_handle,
21673                                    window,
21674                                    cx,
21675                                )
21676                            }
21677                        })
21678                        .on_click({
21679                            let editor = editor.clone();
21680                            move |_event, window, cx| {
21681                                editor.update(cx, |editor, cx| {
21682                                    let snapshot = editor.snapshot(window, cx);
21683                                    let point =
21684                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21685                                    editor.go_to_hunk_before_or_after_position(
21686                                        &snapshot,
21687                                        point,
21688                                        Direction::Prev,
21689                                        window,
21690                                        cx,
21691                                    );
21692                                    editor.expand_selected_diff_hunks(cx);
21693                                });
21694                            }
21695                        }),
21696                )
21697            },
21698        )
21699        .into_any_element()
21700}