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_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    ZetaTosClicked,
  257    Closed,
  258}
  259
  260impl ReportEditorEvent {
  261    pub fn event_type(&self) -> &'static str {
  262        match self {
  263            Self::Saved { .. } => "Editor Saved",
  264            Self::EditorOpened => "Editor Opened",
  265            Self::ZetaTosClicked => "Edit Prediction Provider ToS Clicked",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271struct InlineValueCache {
  272    enabled: bool,
  273    inlays: Vec<InlayId>,
  274    refresh_task: Task<Option<()>>,
  275}
  276
  277impl InlineValueCache {
  278    fn new(enabled: bool) -> Self {
  279        Self {
  280            enabled,
  281            inlays: Vec::new(),
  282            refresh_task: Task::ready(None),
  283        }
  284    }
  285}
  286
  287#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  288pub enum InlayId {
  289    EditPrediction(usize),
  290    DebuggerValue(usize),
  291    // LSP
  292    Hint(usize),
  293    Color(usize),
  294}
  295
  296impl InlayId {
  297    fn id(&self) -> usize {
  298        match self {
  299            Self::EditPrediction(id) => *id,
  300            Self::DebuggerValue(id) => *id,
  301            Self::Hint(id) => *id,
  302            Self::Color(id) => *id,
  303        }
  304    }
  305}
  306
  307pub enum ActiveDebugLine {}
  308pub enum DebugStackFrameLine {}
  309enum DocumentHighlightRead {}
  310enum DocumentHighlightWrite {}
  311enum InputComposition {}
  312pub enum PendingInput {}
  313enum SelectedTextHighlight {}
  314
  315pub enum ConflictsOuter {}
  316pub enum ConflictsOurs {}
  317pub enum ConflictsTheirs {}
  318pub enum ConflictsOursMarker {}
  319pub enum ConflictsTheirsMarker {}
  320
  321#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  322pub enum Navigated {
  323    Yes,
  324    No,
  325}
  326
  327impl Navigated {
  328    pub fn from_bool(yes: bool) -> Navigated {
  329        if yes { Navigated::Yes } else { Navigated::No }
  330    }
  331}
  332
  333#[derive(Debug, Clone, PartialEq, Eq)]
  334enum DisplayDiffHunk {
  335    Folded {
  336        display_row: DisplayRow,
  337    },
  338    Unfolded {
  339        is_created_file: bool,
  340        diff_base_byte_range: Range<usize>,
  341        display_row_range: Range<DisplayRow>,
  342        multi_buffer_range: Range<Anchor>,
  343        status: DiffHunkStatus,
  344    },
  345}
  346
  347pub enum HideMouseCursorOrigin {
  348    TypingAction,
  349    MovementAction,
  350}
  351
  352pub fn init_settings(cx: &mut App) {
  353    EditorSettings::register(cx);
  354}
  355
  356pub fn init(cx: &mut App) {
  357    init_settings(cx);
  358
  359    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  360
  361    workspace::register_project_item::<Editor>(cx);
  362    workspace::FollowableViewRegistry::register::<Editor>(cx);
  363    workspace::register_serializable_item::<Editor>(cx);
  364
  365    cx.observe_new(
  366        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  367            workspace.register_action(Editor::new_file);
  368            workspace.register_action(Editor::new_file_vertical);
  369            workspace.register_action(Editor::new_file_horizontal);
  370            workspace.register_action(Editor::cancel_language_server_work);
  371            workspace.register_action(Editor::toggle_focus);
  372        },
  373    )
  374    .detach();
  375
  376    cx.on_action(move |_: &workspace::NewFile, cx| {
  377        let app_state = workspace::AppState::global(cx);
  378        if let Some(app_state) = app_state.upgrade() {
  379            workspace::open_new(
  380                Default::default(),
  381                app_state,
  382                cx,
  383                |workspace, window, cx| {
  384                    Editor::new_file(workspace, &Default::default(), window, cx)
  385                },
  386            )
  387            .detach();
  388        }
  389    });
  390    cx.on_action(move |_: &workspace::NewWindow, cx| {
  391        let app_state = workspace::AppState::global(cx);
  392        if let Some(app_state) = app_state.upgrade() {
  393            workspace::open_new(
  394                Default::default(),
  395                app_state,
  396                cx,
  397                |workspace, window, cx| {
  398                    cx.activate(true);
  399                    Editor::new_file(workspace, &Default::default(), window, cx)
  400                },
  401            )
  402            .detach();
  403        }
  404    });
  405}
  406
  407pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  408    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  409}
  410
  411pub trait DiagnosticRenderer {
  412    fn render_group(
  413        &self,
  414        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  415        buffer_id: BufferId,
  416        snapshot: EditorSnapshot,
  417        editor: WeakEntity<Editor>,
  418        cx: &mut App,
  419    ) -> Vec<BlockProperties<Anchor>>;
  420
  421    fn render_hover(
  422        &self,
  423        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  424        range: Range<Point>,
  425        buffer_id: BufferId,
  426        cx: &mut App,
  427    ) -> Option<Entity<markdown::Markdown>>;
  428
  429    fn open_link(
  430        &self,
  431        editor: &mut Editor,
  432        link: SharedString,
  433        window: &mut Window,
  434        cx: &mut Context<Editor>,
  435    );
  436}
  437
  438pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  439
  440impl GlobalDiagnosticRenderer {
  441    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  442        cx.try_global::<Self>().map(|g| g.0.clone())
  443    }
  444}
  445
  446impl gpui::Global for GlobalDiagnosticRenderer {}
  447pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  448    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  449}
  450
  451pub struct SearchWithinRange;
  452
  453trait InvalidationRegion {
  454    fn ranges(&self) -> &[Range<Anchor>];
  455}
  456
  457#[derive(Clone, Debug, PartialEq)]
  458pub enum SelectPhase {
  459    Begin {
  460        position: DisplayPoint,
  461        add: bool,
  462        click_count: usize,
  463    },
  464    BeginColumnar {
  465        position: DisplayPoint,
  466        reset: bool,
  467        mode: ColumnarMode,
  468        goal_column: u32,
  469    },
  470    Extend {
  471        position: DisplayPoint,
  472        click_count: usize,
  473    },
  474    Update {
  475        position: DisplayPoint,
  476        goal_column: u32,
  477        scroll_delta: gpui::Point<f32>,
  478    },
  479    End,
  480}
  481
  482#[derive(Clone, Debug, PartialEq)]
  483pub enum ColumnarMode {
  484    FromMouse,
  485    FromSelection,
  486}
  487
  488#[derive(Clone, Debug)]
  489pub enum SelectMode {
  490    Character,
  491    Word(Range<Anchor>),
  492    Line(Range<Anchor>),
  493    All,
  494}
  495
  496#[derive(Clone, PartialEq, Eq, Debug)]
  497pub enum EditorMode {
  498    SingleLine,
  499    AutoHeight {
  500        min_lines: usize,
  501        max_lines: Option<usize>,
  502    },
  503    Full {
  504        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  505        scale_ui_elements_with_buffer_font_size: bool,
  506        /// When set to `true`, the editor will render a background for the active line.
  507        show_active_line_background: bool,
  508        /// When set to `true`, the editor's height will be determined by its content.
  509        sized_by_content: bool,
  510    },
  511    Minimap {
  512        parent: WeakEntity<Editor>,
  513    },
  514}
  515
  516impl EditorMode {
  517    pub fn full() -> Self {
  518        Self::Full {
  519            scale_ui_elements_with_buffer_font_size: true,
  520            show_active_line_background: true,
  521            sized_by_content: false,
  522        }
  523    }
  524
  525    #[inline]
  526    pub fn is_full(&self) -> bool {
  527        matches!(self, Self::Full { .. })
  528    }
  529
  530    #[inline]
  531    pub fn is_single_line(&self) -> bool {
  532        matches!(self, Self::SingleLine { .. })
  533    }
  534
  535    #[inline]
  536    fn is_minimap(&self) -> bool {
  537        matches!(self, Self::Minimap { .. })
  538    }
  539}
  540
  541#[derive(Copy, Clone, Debug)]
  542pub enum SoftWrap {
  543    /// Prefer not to wrap at all.
  544    ///
  545    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  546    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  547    GitDiff,
  548    /// Prefer a single line generally, unless an overly long line is encountered.
  549    None,
  550    /// Soft wrap lines that exceed the editor width.
  551    EditorWidth,
  552    /// Soft wrap lines at the preferred line length.
  553    Column(u32),
  554    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  555    Bounded(u32),
  556}
  557
  558#[derive(Clone)]
  559pub struct EditorStyle {
  560    pub background: Hsla,
  561    pub border: Hsla,
  562    pub local_player: PlayerColor,
  563    pub text: TextStyle,
  564    pub scrollbar_width: Pixels,
  565    pub syntax: Arc<SyntaxTheme>,
  566    pub status: StatusColors,
  567    pub inlay_hints_style: HighlightStyle,
  568    pub edit_prediction_styles: EditPredictionStyles,
  569    pub unnecessary_code_fade: f32,
  570    pub show_underlines: bool,
  571}
  572
  573impl Default for EditorStyle {
  574    fn default() -> Self {
  575        Self {
  576            background: Hsla::default(),
  577            border: Hsla::default(),
  578            local_player: PlayerColor::default(),
  579            text: TextStyle::default(),
  580            scrollbar_width: Pixels::default(),
  581            syntax: Default::default(),
  582            // HACK: Status colors don't have a real default.
  583            // We should look into removing the status colors from the editor
  584            // style and retrieve them directly from the theme.
  585            status: StatusColors::dark(),
  586            inlay_hints_style: HighlightStyle::default(),
  587            edit_prediction_styles: EditPredictionStyles {
  588                insertion: HighlightStyle::default(),
  589                whitespace: HighlightStyle::default(),
  590            },
  591            unnecessary_code_fade: Default::default(),
  592            show_underlines: true,
  593        }
  594    }
  595}
  596
  597pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  598    let show_background = language_settings::language_settings(None, None, cx)
  599        .inlay_hints
  600        .show_background;
  601
  602    HighlightStyle {
  603        color: Some(cx.theme().status().hint),
  604        background_color: show_background.then(|| cx.theme().status().hint_background),
  605        ..HighlightStyle::default()
  606    }
  607}
  608
  609pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  610    EditPredictionStyles {
  611        insertion: HighlightStyle {
  612            color: Some(cx.theme().status().predictive),
  613            ..HighlightStyle::default()
  614        },
  615        whitespace: HighlightStyle {
  616            background_color: Some(cx.theme().status().created_background),
  617            ..HighlightStyle::default()
  618        },
  619    }
  620}
  621
  622type CompletionId = usize;
  623
  624pub(crate) enum EditDisplayMode {
  625    TabAccept,
  626    DiffPopover,
  627    Inline,
  628}
  629
  630enum EditPrediction {
  631    Edit {
  632        edits: Vec<(Range<Anchor>, String)>,
  633        edit_preview: Option<EditPreview>,
  634        display_mode: EditDisplayMode,
  635        snapshot: BufferSnapshot,
  636    },
  637    Move {
  638        target: Anchor,
  639        snapshot: BufferSnapshot,
  640    },
  641}
  642
  643struct EditPredictionState {
  644    inlay_ids: Vec<InlayId>,
  645    completion: EditPrediction,
  646    completion_id: Option<SharedString>,
  647    invalidation_range: Range<Anchor>,
  648}
  649
  650enum EditPredictionSettings {
  651    Disabled,
  652    Enabled {
  653        show_in_menu: bool,
  654        preview_requires_modifier: bool,
  655    },
  656}
  657
  658enum EditPredictionHighlight {}
  659
  660#[derive(Debug, Clone)]
  661struct InlineDiagnostic {
  662    message: SharedString,
  663    group_id: usize,
  664    is_primary: bool,
  665    start: Point,
  666    severity: lsp::DiagnosticSeverity,
  667}
  668
  669pub enum MenuEditPredictionsPolicy {
  670    Never,
  671    ByProvider,
  672}
  673
  674pub enum EditPredictionPreview {
  675    /// Modifier is not pressed
  676    Inactive { released_too_fast: bool },
  677    /// Modifier pressed
  678    Active {
  679        since: Instant,
  680        previous_scroll_position: Option<ScrollAnchor>,
  681    },
  682}
  683
  684impl EditPredictionPreview {
  685    pub fn released_too_fast(&self) -> bool {
  686        match self {
  687            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  688            EditPredictionPreview::Active { .. } => false,
  689        }
  690    }
  691
  692    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  693        if let EditPredictionPreview::Active {
  694            previous_scroll_position,
  695            ..
  696        } = self
  697        {
  698            *previous_scroll_position = scroll_position;
  699        }
  700    }
  701}
  702
  703pub struct ContextMenuOptions {
  704    pub min_entries_visible: usize,
  705    pub max_entries_visible: usize,
  706    pub placement: Option<ContextMenuPlacement>,
  707}
  708
  709#[derive(Debug, Clone, PartialEq, Eq)]
  710pub enum ContextMenuPlacement {
  711    Above,
  712    Below,
  713}
  714
  715#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  716struct EditorActionId(usize);
  717
  718impl EditorActionId {
  719    pub fn post_inc(&mut self) -> Self {
  720        let answer = self.0;
  721
  722        *self = Self(answer + 1);
  723
  724        Self(answer)
  725    }
  726}
  727
  728// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  729// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  730
  731type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  732type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  733
  734#[derive(Default)]
  735struct ScrollbarMarkerState {
  736    scrollbar_size: Size<Pixels>,
  737    dirty: bool,
  738    markers: Arc<[PaintQuad]>,
  739    pending_refresh: Option<Task<Result<()>>>,
  740}
  741
  742impl ScrollbarMarkerState {
  743    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  744        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  745    }
  746}
  747
  748#[derive(Clone, Copy, PartialEq, Eq)]
  749pub enum MinimapVisibility {
  750    Disabled,
  751    Enabled {
  752        /// The configuration currently present in the users settings.
  753        setting_configuration: bool,
  754        /// Whether to override the currently set visibility from the users setting.
  755        toggle_override: bool,
  756    },
  757}
  758
  759impl MinimapVisibility {
  760    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  761        if mode.is_full() {
  762            Self::Enabled {
  763                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  764                toggle_override: false,
  765            }
  766        } else {
  767            Self::Disabled
  768        }
  769    }
  770
  771    fn hidden(&self) -> Self {
  772        match *self {
  773            Self::Enabled {
  774                setting_configuration,
  775                ..
  776            } => Self::Enabled {
  777                setting_configuration,
  778                toggle_override: setting_configuration,
  779            },
  780            Self::Disabled => Self::Disabled,
  781        }
  782    }
  783
  784    fn disabled(&self) -> bool {
  785        matches!(*self, Self::Disabled)
  786    }
  787
  788    fn settings_visibility(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                ..
  793            } => setting_configuration,
  794            _ => false,
  795        }
  796    }
  797
  798    fn visible(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                toggle_override,
  803            } => setting_configuration ^ toggle_override,
  804            _ => false,
  805        }
  806    }
  807
  808    fn toggle_visibility(&self) -> Self {
  809        match *self {
  810            Self::Enabled {
  811                toggle_override,
  812                setting_configuration,
  813            } => Self::Enabled {
  814                setting_configuration,
  815                toggle_override: !toggle_override,
  816            },
  817            Self::Disabled => Self::Disabled,
  818        }
  819    }
  820}
  821
  822#[derive(Clone, Debug)]
  823struct RunnableTasks {
  824    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  825    offset: multi_buffer::Anchor,
  826    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  827    column: u32,
  828    // Values of all named captures, including those starting with '_'
  829    extra_variables: HashMap<String, String>,
  830    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  831    context_range: Range<BufferOffset>,
  832}
  833
  834impl RunnableTasks {
  835    fn resolve<'a>(
  836        &'a self,
  837        cx: &'a task::TaskContext,
  838    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  839        self.templates.iter().filter_map(|(kind, template)| {
  840            template
  841                .resolve_task(&kind.to_id_base(), cx)
  842                .map(|task| (kind.clone(), task))
  843        })
  844    }
  845}
  846
  847#[derive(Clone)]
  848pub struct ResolvedTasks {
  849    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  850    position: Anchor,
  851}
  852
  853#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  854struct BufferOffset(usize);
  855
  856// Addons allow storing per-editor state in other crates (e.g. Vim)
  857pub trait Addon: 'static {
  858    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  859
  860    fn render_buffer_header_controls(
  861        &self,
  862        _: &ExcerptInfo,
  863        _: &Window,
  864        _: &App,
  865    ) -> Option<AnyElement> {
  866        None
  867    }
  868
  869    fn to_any(&self) -> &dyn std::any::Any;
  870
  871    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  872        None
  873    }
  874}
  875
  876struct ChangeLocation {
  877    current: Option<Vec<Anchor>>,
  878    original: Vec<Anchor>,
  879}
  880impl ChangeLocation {
  881    fn locations(&self) -> &[Anchor] {
  882        self.current.as_ref().unwrap_or(&self.original)
  883    }
  884}
  885
  886/// A set of caret positions, registered when the editor was edited.
  887pub struct ChangeList {
  888    changes: Vec<ChangeLocation>,
  889    /// Currently "selected" change.
  890    position: Option<usize>,
  891}
  892
  893impl ChangeList {
  894    pub fn new() -> Self {
  895        Self {
  896            changes: Vec::new(),
  897            position: None,
  898        }
  899    }
  900
  901    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  902    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  903    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  904        if self.changes.is_empty() {
  905            return None;
  906        }
  907
  908        let prev = self.position.unwrap_or(self.changes.len());
  909        let next = if direction == Direction::Prev {
  910            prev.saturating_sub(count)
  911        } else {
  912            (prev + count).min(self.changes.len() - 1)
  913        };
  914        self.position = Some(next);
  915        self.changes.get(next).map(|change| change.locations())
  916    }
  917
  918    /// Adds a new change to the list, resetting the change list position.
  919    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  920        self.position.take();
  921        if let Some(last) = self.changes.last_mut()
  922            && group
  923        {
  924            last.current = Some(new_positions)
  925        } else {
  926            self.changes.push(ChangeLocation {
  927                original: new_positions,
  928                current: None,
  929            });
  930        }
  931    }
  932
  933    pub fn last(&self) -> Option<&[Anchor]> {
  934        self.changes.last().map(|change| change.locations())
  935    }
  936
  937    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  938        self.changes.last().map(|change| change.original.as_slice())
  939    }
  940
  941    pub fn invert_last_group(&mut self) {
  942        if let Some(last) = self.changes.last_mut()
  943            && let Some(current) = last.current.as_mut()
  944        {
  945            mem::swap(&mut last.original, current);
  946        }
  947    }
  948}
  949
  950#[derive(Clone)]
  951struct InlineBlamePopoverState {
  952    scroll_handle: ScrollHandle,
  953    commit_message: Option<ParsedCommitMessage>,
  954    markdown: Entity<Markdown>,
  955}
  956
  957struct InlineBlamePopover {
  958    position: gpui::Point<Pixels>,
  959    hide_task: Option<Task<()>>,
  960    popover_bounds: Option<Bounds<Pixels>>,
  961    popover_state: InlineBlamePopoverState,
  962    keyboard_grace: bool,
  963}
  964
  965enum SelectionDragState {
  966    /// State when no drag related activity is detected.
  967    None,
  968    /// State when the mouse is down on a selection that is about to be dragged.
  969    ReadyToDrag {
  970        selection: Selection<Anchor>,
  971        click_position: gpui::Point<Pixels>,
  972        mouse_down_time: Instant,
  973    },
  974    /// State when the mouse is dragging the selection in the editor.
  975    Dragging {
  976        selection: Selection<Anchor>,
  977        drop_cursor: Selection<Anchor>,
  978        hide_drop_cursor: bool,
  979    },
  980}
  981
  982enum ColumnarSelectionState {
  983    FromMouse {
  984        selection_tail: Anchor,
  985        display_point: Option<DisplayPoint>,
  986    },
  987    FromSelection {
  988        selection_tail: Anchor,
  989    },
  990}
  991
  992/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  993/// a breakpoint on them.
  994#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  995struct PhantomBreakpointIndicator {
  996    display_row: DisplayRow,
  997    /// There's a small debounce between hovering over the line and showing the indicator.
  998    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  999    is_active: bool,
 1000    collides_with_existing_breakpoint: bool,
 1001}
 1002
 1003/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1004///
 1005/// See the [module level documentation](self) for more information.
 1006pub struct Editor {
 1007    focus_handle: FocusHandle,
 1008    last_focused_descendant: Option<WeakFocusHandle>,
 1009    /// The text buffer being edited
 1010    buffer: Entity<MultiBuffer>,
 1011    /// Map of how text in the buffer should be displayed.
 1012    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1013    pub display_map: Entity<DisplayMap>,
 1014    pub selections: SelectionsCollection,
 1015    pub scroll_manager: ScrollManager,
 1016    /// When inline assist editors are linked, they all render cursors because
 1017    /// typing enters text into each of them, even the ones that aren't focused.
 1018    pub(crate) show_cursor_when_unfocused: bool,
 1019    columnar_selection_state: Option<ColumnarSelectionState>,
 1020    add_selections_state: Option<AddSelectionsState>,
 1021    select_next_state: Option<SelectNextState>,
 1022    select_prev_state: Option<SelectNextState>,
 1023    selection_history: SelectionHistory,
 1024    defer_selection_effects: bool,
 1025    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1026    autoclose_regions: Vec<AutocloseRegion>,
 1027    snippet_stack: InvalidationStack<SnippetState>,
 1028    select_syntax_node_history: SelectSyntaxNodeHistory,
 1029    ime_transaction: Option<TransactionId>,
 1030    pub diagnostics_max_severity: DiagnosticSeverity,
 1031    active_diagnostics: ActiveDiagnostic,
 1032    show_inline_diagnostics: bool,
 1033    inline_diagnostics_update: Task<()>,
 1034    inline_diagnostics_enabled: bool,
 1035    diagnostics_enabled: bool,
 1036    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1037    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1038    hard_wrap: Option<usize>,
 1039    project: Option<Entity<Project>>,
 1040    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1041    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1042    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1043    blink_manager: Entity<BlinkManager>,
 1044    show_cursor_names: bool,
 1045    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1046    pub show_local_selections: bool,
 1047    mode: EditorMode,
 1048    show_breadcrumbs: bool,
 1049    show_gutter: bool,
 1050    show_scrollbars: ScrollbarAxes,
 1051    minimap_visibility: MinimapVisibility,
 1052    offset_content: bool,
 1053    disable_expand_excerpt_buttons: bool,
 1054    show_line_numbers: Option<bool>,
 1055    use_relative_line_numbers: Option<bool>,
 1056    show_git_diff_gutter: Option<bool>,
 1057    show_code_actions: Option<bool>,
 1058    show_runnables: Option<bool>,
 1059    show_breakpoints: Option<bool>,
 1060    show_wrap_guides: Option<bool>,
 1061    show_indent_guides: Option<bool>,
 1062    placeholder_text: Option<Arc<str>>,
 1063    highlight_order: usize,
 1064    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1065    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1066    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1067    scrollbar_marker_state: ScrollbarMarkerState,
 1068    active_indent_guides_state: ActiveIndentGuidesState,
 1069    nav_history: Option<ItemNavHistory>,
 1070    context_menu: RefCell<Option<CodeContextMenu>>,
 1071    context_menu_options: Option<ContextMenuOptions>,
 1072    mouse_context_menu: Option<MouseContextMenu>,
 1073    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1074    inline_blame_popover: Option<InlineBlamePopover>,
 1075    inline_blame_popover_show_task: Option<Task<()>>,
 1076    signature_help_state: SignatureHelpState,
 1077    auto_signature_help: Option<bool>,
 1078    find_all_references_task_sources: Vec<Anchor>,
 1079    next_completion_id: CompletionId,
 1080    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1081    code_actions_task: Option<Task<Result<()>>>,
 1082    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1083    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1084    document_highlights_task: Option<Task<()>>,
 1085    linked_editing_range_task: Option<Task<Option<()>>>,
 1086    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1087    pending_rename: Option<RenameState>,
 1088    searchable: bool,
 1089    cursor_shape: CursorShape,
 1090    current_line_highlight: Option<CurrentLineHighlight>,
 1091    collapse_matches: bool,
 1092    autoindent_mode: Option<AutoindentMode>,
 1093    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1094    input_enabled: bool,
 1095    use_modal_editing: bool,
 1096    read_only: bool,
 1097    leader_id: Option<CollaboratorId>,
 1098    remote_id: Option<ViewId>,
 1099    pub hover_state: HoverState,
 1100    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1101    gutter_hovered: bool,
 1102    hovered_link_state: Option<HoveredLinkState>,
 1103    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1104    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1105    active_edit_prediction: Option<EditPredictionState>,
 1106    /// Used to prevent flickering as the user types while the menu is open
 1107    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1108    edit_prediction_settings: EditPredictionSettings,
 1109    edit_predictions_hidden_for_vim_mode: bool,
 1110    show_edit_predictions_override: Option<bool>,
 1111    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1112    edit_prediction_preview: EditPredictionPreview,
 1113    edit_prediction_indent_conflict: bool,
 1114    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1115    inlay_hint_cache: InlayHintCache,
 1116    next_inlay_id: usize,
 1117    _subscriptions: Vec<Subscription>,
 1118    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1119    gutter_dimensions: GutterDimensions,
 1120    style: Option<EditorStyle>,
 1121    text_style_refinement: Option<TextStyleRefinement>,
 1122    next_editor_action_id: EditorActionId,
 1123    editor_actions: Rc<
 1124        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1125    >,
 1126    use_autoclose: bool,
 1127    use_auto_surround: bool,
 1128    auto_replace_emoji_shortcode: bool,
 1129    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1130    show_git_blame_gutter: bool,
 1131    show_git_blame_inline: bool,
 1132    show_git_blame_inline_delay_task: Option<Task<()>>,
 1133    git_blame_inline_enabled: bool,
 1134    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1135    serialize_dirty_buffers: bool,
 1136    show_selection_menu: Option<bool>,
 1137    blame: Option<Entity<GitBlame>>,
 1138    blame_subscription: Option<Subscription>,
 1139    custom_context_menu: Option<
 1140        Box<
 1141            dyn 'static
 1142                + Fn(
 1143                    &mut Self,
 1144                    DisplayPoint,
 1145                    &mut Window,
 1146                    &mut Context<Self>,
 1147                ) -> Option<Entity<ui::ContextMenu>>,
 1148        >,
 1149    >,
 1150    last_bounds: Option<Bounds<Pixels>>,
 1151    last_position_map: Option<Rc<PositionMap>>,
 1152    expect_bounds_change: Option<Bounds<Pixels>>,
 1153    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1154    tasks_update_task: Option<Task<()>>,
 1155    breakpoint_store: Option<Entity<BreakpointStore>>,
 1156    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1157    hovered_diff_hunk_row: Option<DisplayRow>,
 1158    pull_diagnostics_task: Task<()>,
 1159    in_project_search: bool,
 1160    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1161    breadcrumb_header: Option<String>,
 1162    focused_block: Option<FocusedBlock>,
 1163    next_scroll_position: NextScrollCursorCenterTopBottom,
 1164    addons: HashMap<TypeId, Box<dyn Addon>>,
 1165    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1166    load_diff_task: Option<Shared<Task<()>>>,
 1167    /// Whether we are temporarily displaying a diff other than git's
 1168    temporary_diff_override: bool,
 1169    selection_mark_mode: bool,
 1170    toggle_fold_multiple_buffers: Task<()>,
 1171    _scroll_cursor_center_top_bottom_task: Task<()>,
 1172    serialize_selections: Task<()>,
 1173    serialize_folds: Task<()>,
 1174    mouse_cursor_hidden: bool,
 1175    minimap: Option<Entity<Self>>,
 1176    hide_mouse_mode: HideMouseMode,
 1177    pub change_list: ChangeList,
 1178    inline_value_cache: InlineValueCache,
 1179    selection_drag_state: SelectionDragState,
 1180    next_color_inlay_id: usize,
 1181    colors: Option<LspColorData>,
 1182    folding_newlines: Task<()>,
 1183}
 1184
 1185#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1186enum NextScrollCursorCenterTopBottom {
 1187    #[default]
 1188    Center,
 1189    Top,
 1190    Bottom,
 1191}
 1192
 1193impl NextScrollCursorCenterTopBottom {
 1194    fn next(&self) -> Self {
 1195        match self {
 1196            Self::Center => Self::Top,
 1197            Self::Top => Self::Bottom,
 1198            Self::Bottom => Self::Center,
 1199        }
 1200    }
 1201}
 1202
 1203#[derive(Clone)]
 1204pub struct EditorSnapshot {
 1205    pub mode: EditorMode,
 1206    show_gutter: bool,
 1207    show_line_numbers: Option<bool>,
 1208    show_git_diff_gutter: Option<bool>,
 1209    show_code_actions: Option<bool>,
 1210    show_runnables: Option<bool>,
 1211    show_breakpoints: Option<bool>,
 1212    git_blame_gutter_max_author_length: Option<usize>,
 1213    pub display_snapshot: DisplaySnapshot,
 1214    pub placeholder_text: Option<Arc<str>>,
 1215    is_focused: bool,
 1216    scroll_anchor: ScrollAnchor,
 1217    ongoing_scroll: OngoingScroll,
 1218    current_line_highlight: CurrentLineHighlight,
 1219    gutter_hovered: bool,
 1220}
 1221
 1222#[derive(Default, Debug, Clone, Copy)]
 1223pub struct GutterDimensions {
 1224    pub left_padding: Pixels,
 1225    pub right_padding: Pixels,
 1226    pub width: Pixels,
 1227    pub margin: Pixels,
 1228    pub git_blame_entries_width: Option<Pixels>,
 1229}
 1230
 1231impl GutterDimensions {
 1232    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1233        Self {
 1234            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1235            ..Default::default()
 1236        }
 1237    }
 1238
 1239    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1240        -cx.text_system().descent(font_id, font_size)
 1241    }
 1242    /// The full width of the space taken up by the gutter.
 1243    pub fn full_width(&self) -> Pixels {
 1244        self.margin + self.width
 1245    }
 1246
 1247    /// The width of the space reserved for the fold indicators,
 1248    /// use alongside 'justify_end' and `gutter_width` to
 1249    /// right align content with the line numbers
 1250    pub fn fold_area_width(&self) -> Pixels {
 1251        self.margin + self.right_padding
 1252    }
 1253}
 1254
 1255struct CharacterDimensions {
 1256    em_width: Pixels,
 1257    em_advance: Pixels,
 1258    line_height: Pixels,
 1259}
 1260
 1261#[derive(Debug)]
 1262pub struct RemoteSelection {
 1263    pub replica_id: ReplicaId,
 1264    pub selection: Selection<Anchor>,
 1265    pub cursor_shape: CursorShape,
 1266    pub collaborator_id: CollaboratorId,
 1267    pub line_mode: bool,
 1268    pub user_name: Option<SharedString>,
 1269    pub color: PlayerColor,
 1270}
 1271
 1272#[derive(Clone, Debug)]
 1273struct SelectionHistoryEntry {
 1274    selections: Arc<[Selection<Anchor>]>,
 1275    select_next_state: Option<SelectNextState>,
 1276    select_prev_state: Option<SelectNextState>,
 1277    add_selections_state: Option<AddSelectionsState>,
 1278}
 1279
 1280#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1281enum SelectionHistoryMode {
 1282    Normal,
 1283    Undoing,
 1284    Redoing,
 1285    Skipping,
 1286}
 1287
 1288#[derive(Clone, PartialEq, Eq, Hash)]
 1289struct HoveredCursor {
 1290    replica_id: u16,
 1291    selection_id: usize,
 1292}
 1293
 1294impl Default for SelectionHistoryMode {
 1295    fn default() -> Self {
 1296        Self::Normal
 1297    }
 1298}
 1299
 1300#[derive(Debug)]
 1301/// SelectionEffects controls the side-effects of updating the selection.
 1302///
 1303/// The default behaviour does "what you mostly want":
 1304/// - it pushes to the nav history if the cursor moved by >10 lines
 1305/// - it re-triggers completion requests
 1306/// - it scrolls to fit
 1307///
 1308/// You might want to modify these behaviours. For example when doing a "jump"
 1309/// like go to definition, we always want to add to nav history; but when scrolling
 1310/// in vim mode we never do.
 1311///
 1312/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1313/// move.
 1314#[derive(Clone)]
 1315pub struct SelectionEffects {
 1316    nav_history: Option<bool>,
 1317    completions: bool,
 1318    scroll: Option<Autoscroll>,
 1319}
 1320
 1321impl Default for SelectionEffects {
 1322    fn default() -> Self {
 1323        Self {
 1324            nav_history: None,
 1325            completions: true,
 1326            scroll: Some(Autoscroll::fit()),
 1327        }
 1328    }
 1329}
 1330impl SelectionEffects {
 1331    pub fn scroll(scroll: Autoscroll) -> Self {
 1332        Self {
 1333            scroll: Some(scroll),
 1334            ..Default::default()
 1335        }
 1336    }
 1337
 1338    pub fn no_scroll() -> Self {
 1339        Self {
 1340            scroll: None,
 1341            ..Default::default()
 1342        }
 1343    }
 1344
 1345    pub fn completions(self, completions: bool) -> Self {
 1346        Self {
 1347            completions,
 1348            ..self
 1349        }
 1350    }
 1351
 1352    pub fn nav_history(self, nav_history: bool) -> Self {
 1353        Self {
 1354            nav_history: Some(nav_history),
 1355            ..self
 1356        }
 1357    }
 1358}
 1359
 1360struct DeferredSelectionEffectsState {
 1361    changed: bool,
 1362    effects: SelectionEffects,
 1363    old_cursor_position: Anchor,
 1364    history_entry: SelectionHistoryEntry,
 1365}
 1366
 1367#[derive(Default)]
 1368struct SelectionHistory {
 1369    #[allow(clippy::type_complexity)]
 1370    selections_by_transaction:
 1371        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1372    mode: SelectionHistoryMode,
 1373    undo_stack: VecDeque<SelectionHistoryEntry>,
 1374    redo_stack: VecDeque<SelectionHistoryEntry>,
 1375}
 1376
 1377impl SelectionHistory {
 1378    #[track_caller]
 1379    fn insert_transaction(
 1380        &mut self,
 1381        transaction_id: TransactionId,
 1382        selections: Arc<[Selection<Anchor>]>,
 1383    ) {
 1384        if selections.is_empty() {
 1385            log::error!(
 1386                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1387                std::panic::Location::caller()
 1388            );
 1389            return;
 1390        }
 1391        self.selections_by_transaction
 1392            .insert(transaction_id, (selections, None));
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction(
 1397        &self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get(&transaction_id)
 1401    }
 1402
 1403    #[allow(clippy::type_complexity)]
 1404    fn transaction_mut(
 1405        &mut self,
 1406        transaction_id: TransactionId,
 1407    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1408        self.selections_by_transaction.get_mut(&transaction_id)
 1409    }
 1410
 1411    fn push(&mut self, entry: SelectionHistoryEntry) {
 1412        if !entry.selections.is_empty() {
 1413            match self.mode {
 1414                SelectionHistoryMode::Normal => {
 1415                    self.push_undo(entry);
 1416                    self.redo_stack.clear();
 1417                }
 1418                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1419                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1420                SelectionHistoryMode::Skipping => {}
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .undo_stack
 1428            .back()
 1429            .is_none_or(|e| e.selections != entry.selections)
 1430        {
 1431            self.undo_stack.push_back(entry);
 1432            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.undo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .redo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.redo_stack.push_back(entry);
 1445            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.redo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450}
 1451
 1452#[derive(Clone, Copy)]
 1453pub struct RowHighlightOptions {
 1454    pub autoscroll: bool,
 1455    pub include_gutter: bool,
 1456}
 1457
 1458impl Default for RowHighlightOptions {
 1459    fn default() -> Self {
 1460        Self {
 1461            autoscroll: Default::default(),
 1462            include_gutter: true,
 1463        }
 1464    }
 1465}
 1466
 1467struct RowHighlight {
 1468    index: usize,
 1469    range: Range<Anchor>,
 1470    color: Hsla,
 1471    options: RowHighlightOptions,
 1472    type_id: TypeId,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsState {
 1477    groups: Vec<AddSelectionsGroup>,
 1478}
 1479
 1480#[derive(Clone, Debug)]
 1481struct AddSelectionsGroup {
 1482    above: bool,
 1483    stack: Vec<usize>,
 1484}
 1485
 1486#[derive(Clone)]
 1487struct SelectNextState {
 1488    query: AhoCorasick,
 1489    wordwise: bool,
 1490    done: bool,
 1491}
 1492
 1493impl std::fmt::Debug for SelectNextState {
 1494    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1495        f.debug_struct(std::any::type_name::<Self>())
 1496            .field("wordwise", &self.wordwise)
 1497            .field("done", &self.done)
 1498            .finish()
 1499    }
 1500}
 1501
 1502#[derive(Debug)]
 1503struct AutocloseRegion {
 1504    selection_id: usize,
 1505    range: Range<Anchor>,
 1506    pair: BracketPair,
 1507}
 1508
 1509#[derive(Debug)]
 1510struct SnippetState {
 1511    ranges: Vec<Vec<Range<Anchor>>>,
 1512    active_index: usize,
 1513    choices: Vec<Option<Vec<String>>>,
 1514}
 1515
 1516#[doc(hidden)]
 1517pub struct RenameState {
 1518    pub range: Range<Anchor>,
 1519    pub old_name: Arc<str>,
 1520    pub editor: Entity<Editor>,
 1521    block_id: CustomBlockId,
 1522}
 1523
 1524struct InvalidationStack<T>(Vec<T>);
 1525
 1526struct RegisteredEditPredictionProvider {
 1527    provider: Arc<dyn EditPredictionProviderHandle>,
 1528    _subscription: Subscription,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532pub struct ActiveDiagnosticGroup {
 1533    pub active_range: Range<Anchor>,
 1534    pub active_message: String,
 1535    pub group_id: usize,
 1536    pub blocks: HashSet<CustomBlockId>,
 1537}
 1538
 1539#[derive(Debug, PartialEq, Eq)]
 1540
 1541pub(crate) enum ActiveDiagnostic {
 1542    None,
 1543    All,
 1544    Group(ActiveDiagnosticGroup),
 1545}
 1546
 1547#[derive(Serialize, Deserialize, Clone, Debug)]
 1548pub struct ClipboardSelection {
 1549    /// The number of bytes in this selection.
 1550    pub len: usize,
 1551    /// Whether this was a full-line selection.
 1552    pub is_entire_line: bool,
 1553    /// The indentation of the first line when this content was originally copied.
 1554    pub first_line_indent: u32,
 1555}
 1556
 1557// selections, scroll behavior, was newest selection reversed
 1558type SelectSyntaxNodeHistoryState = (
 1559    Box<[Selection<usize>]>,
 1560    SelectSyntaxNodeScrollBehavior,
 1561    bool,
 1562);
 1563
 1564#[derive(Default)]
 1565struct SelectSyntaxNodeHistory {
 1566    stack: Vec<SelectSyntaxNodeHistoryState>,
 1567    // disable temporarily to allow changing selections without losing the stack
 1568    pub disable_clearing: bool,
 1569}
 1570
 1571impl SelectSyntaxNodeHistory {
 1572    pub fn try_clear(&mut self) {
 1573        if !self.disable_clearing {
 1574            self.stack.clear();
 1575        }
 1576    }
 1577
 1578    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1579        self.stack.push(selection);
 1580    }
 1581
 1582    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1583        self.stack.pop()
 1584    }
 1585}
 1586
 1587enum SelectSyntaxNodeScrollBehavior {
 1588    CursorTop,
 1589    FitSelection,
 1590    CursorBottom,
 1591}
 1592
 1593#[derive(Debug)]
 1594pub(crate) struct NavigationData {
 1595    cursor_anchor: Anchor,
 1596    cursor_position: Point,
 1597    scroll_anchor: ScrollAnchor,
 1598    scroll_top_row: u32,
 1599}
 1600
 1601#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1602pub enum GotoDefinitionKind {
 1603    Symbol,
 1604    Declaration,
 1605    Type,
 1606    Implementation,
 1607}
 1608
 1609#[derive(Debug, Clone)]
 1610enum InlayHintRefreshReason {
 1611    ModifiersChanged(bool),
 1612    Toggle(bool),
 1613    SettingsChange(InlayHintSettings),
 1614    NewLinesShown,
 1615    BufferEdited(HashSet<Arc<Language>>),
 1616    RefreshRequested,
 1617    ExcerptsRemoved(Vec<ExcerptId>),
 1618}
 1619
 1620impl InlayHintRefreshReason {
 1621    fn description(&self) -> &'static str {
 1622        match self {
 1623            Self::ModifiersChanged(_) => "modifiers changed",
 1624            Self::Toggle(_) => "toggle",
 1625            Self::SettingsChange(_) => "settings change",
 1626            Self::NewLinesShown => "new lines shown",
 1627            Self::BufferEdited(_) => "buffer edited",
 1628            Self::RefreshRequested => "refresh requested",
 1629            Self::ExcerptsRemoved(_) => "excerpts removed",
 1630        }
 1631    }
 1632}
 1633
 1634pub enum FormatTarget {
 1635    Buffers(HashSet<Entity<Buffer>>),
 1636    Ranges(Vec<Range<MultiBufferPoint>>),
 1637}
 1638
 1639pub(crate) struct FocusedBlock {
 1640    id: BlockId,
 1641    focus_handle: WeakFocusHandle,
 1642}
 1643
 1644#[derive(Clone)]
 1645enum JumpData {
 1646    MultiBufferRow {
 1647        row: MultiBufferRow,
 1648        line_offset_from_top: u32,
 1649    },
 1650    MultiBufferPoint {
 1651        excerpt_id: ExcerptId,
 1652        position: Point,
 1653        anchor: text::Anchor,
 1654        line_offset_from_top: u32,
 1655    },
 1656}
 1657
 1658pub enum MultibufferSelectionMode {
 1659    First,
 1660    All,
 1661}
 1662
 1663#[derive(Clone, Copy, Debug, Default)]
 1664pub struct RewrapOptions {
 1665    pub override_language_settings: bool,
 1666    pub preserve_existing_whitespace: bool,
 1667}
 1668
 1669impl Editor {
 1670    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1677        let buffer = cx.new(|cx| Buffer::local("", cx));
 1678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1679        Self::new(EditorMode::full(), buffer, None, window, cx)
 1680    }
 1681
 1682    pub fn auto_height(
 1683        min_lines: usize,
 1684        max_lines: usize,
 1685        window: &mut Window,
 1686        cx: &mut Context<Self>,
 1687    ) -> Self {
 1688        let buffer = cx.new(|cx| Buffer::local("", cx));
 1689        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1690        Self::new(
 1691            EditorMode::AutoHeight {
 1692                min_lines,
 1693                max_lines: Some(max_lines),
 1694            },
 1695            buffer,
 1696            None,
 1697            window,
 1698            cx,
 1699        )
 1700    }
 1701
 1702    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1703    /// The editor grows as tall as needed to fit its content.
 1704    pub fn auto_height_unbounded(
 1705        min_lines: usize,
 1706        window: &mut Window,
 1707        cx: &mut Context<Self>,
 1708    ) -> Self {
 1709        let buffer = cx.new(|cx| Buffer::local("", cx));
 1710        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1711        Self::new(
 1712            EditorMode::AutoHeight {
 1713                min_lines,
 1714                max_lines: None,
 1715            },
 1716            buffer,
 1717            None,
 1718            window,
 1719            cx,
 1720        )
 1721    }
 1722
 1723    pub fn for_buffer(
 1724        buffer: Entity<Buffer>,
 1725        project: Option<Entity<Project>>,
 1726        window: &mut Window,
 1727        cx: &mut Context<Self>,
 1728    ) -> Self {
 1729        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1730        Self::new(EditorMode::full(), buffer, project, window, cx)
 1731    }
 1732
 1733    pub fn for_multibuffer(
 1734        buffer: Entity<MultiBuffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        Self::new(EditorMode::full(), buffer, project, window, cx)
 1740    }
 1741
 1742    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1743        let mut clone = Self::new(
 1744            self.mode.clone(),
 1745            self.buffer.clone(),
 1746            self.project.clone(),
 1747            window,
 1748            cx,
 1749        );
 1750        self.display_map.update(cx, |display_map, cx| {
 1751            let snapshot = display_map.snapshot(cx);
 1752            clone.display_map.update(cx, |display_map, cx| {
 1753                display_map.set_state(&snapshot, cx);
 1754            });
 1755        });
 1756        clone.folds_did_change(cx);
 1757        clone.selections.clone_state(&self.selections);
 1758        clone.scroll_manager.clone_state(&self.scroll_manager);
 1759        clone.searchable = self.searchable;
 1760        clone.read_only = self.read_only;
 1761        clone
 1762    }
 1763
 1764    pub fn new(
 1765        mode: EditorMode,
 1766        buffer: Entity<MultiBuffer>,
 1767        project: Option<Entity<Project>>,
 1768        window: &mut Window,
 1769        cx: &mut Context<Self>,
 1770    ) -> Self {
 1771        Editor::new_internal(mode, buffer, project, None, window, cx)
 1772    }
 1773
 1774    fn new_internal(
 1775        mode: EditorMode,
 1776        buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        display_map: Option<Entity<DisplayMap>>,
 1779        window: &mut Window,
 1780        cx: &mut Context<Self>,
 1781    ) -> Self {
 1782        debug_assert!(
 1783            display_map.is_none() || mode.is_minimap(),
 1784            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1785        );
 1786
 1787        let full_mode = mode.is_full();
 1788        let is_minimap = mode.is_minimap();
 1789        let diagnostics_max_severity = if full_mode {
 1790            EditorSettings::get_global(cx)
 1791                .diagnostics_max_severity
 1792                .unwrap_or(DiagnosticSeverity::Hint)
 1793        } else {
 1794            DiagnosticSeverity::Off
 1795        };
 1796        let style = window.text_style();
 1797        let font_size = style.font_size.to_pixels(window.rem_size());
 1798        let editor = cx.entity().downgrade();
 1799        let fold_placeholder = FoldPlaceholder {
 1800            constrain_width: true,
 1801            render: Arc::new(move |fold_id, fold_range, cx| {
 1802                let editor = editor.clone();
 1803                div()
 1804                    .id(fold_id)
 1805                    .bg(cx.theme().colors().ghost_element_background)
 1806                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1807                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1808                    .rounded_xs()
 1809                    .size_full()
 1810                    .cursor_pointer()
 1811                    .child("")
 1812                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1813                    .on_click(move |_, _window, cx| {
 1814                        editor
 1815                            .update(cx, |editor, cx| {
 1816                                editor.unfold_ranges(
 1817                                    &[fold_range.start..fold_range.end],
 1818                                    true,
 1819                                    false,
 1820                                    cx,
 1821                                );
 1822                                cx.stop_propagation();
 1823                            })
 1824                            .ok();
 1825                    })
 1826                    .into_any()
 1827            }),
 1828            merge_adjacent: true,
 1829            ..FoldPlaceholder::default()
 1830        };
 1831        let display_map = display_map.unwrap_or_else(|| {
 1832            cx.new(|cx| {
 1833                DisplayMap::new(
 1834                    buffer.clone(),
 1835                    style.font(),
 1836                    font_size,
 1837                    None,
 1838                    FILE_HEADER_HEIGHT,
 1839                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1840                    fold_placeholder,
 1841                    diagnostics_max_severity,
 1842                    cx,
 1843                )
 1844            })
 1845        });
 1846
 1847        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1848
 1849        let blink_manager = cx.new(|cx| {
 1850            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1851            if is_minimap {
 1852                blink_manager.disable(cx);
 1853            }
 1854            blink_manager
 1855        });
 1856
 1857        let soft_wrap_mode_override =
 1858            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1859
 1860        let mut project_subscriptions = Vec::new();
 1861        if full_mode && let Some(project) = project.as_ref() {
 1862            project_subscriptions.push(cx.subscribe_in(
 1863                project,
 1864                window,
 1865                |editor, _, event, window, cx| match event {
 1866                    project::Event::RefreshCodeLens => {
 1867                        // we always query lens with actions, without storing them, always refreshing them
 1868                    }
 1869                    project::Event::RefreshInlayHints => {
 1870                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1871                    }
 1872                    project::Event::LanguageServerAdded(..)
 1873                    | project::Event::LanguageServerRemoved(..) => {
 1874                        if editor.tasks_update_task.is_none() {
 1875                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1876                        }
 1877                    }
 1878                    project::Event::SnippetEdit(id, snippet_edits) => {
 1879                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1880                            let focus_handle = editor.focus_handle(cx);
 1881                            if focus_handle.is_focused(window) {
 1882                                let snapshot = buffer.read(cx).snapshot();
 1883                                for (range, snippet) in snippet_edits {
 1884                                    let editor_range =
 1885                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1886                                    editor
 1887                                        .insert_snippet(
 1888                                            &[editor_range],
 1889                                            snippet.clone(),
 1890                                            window,
 1891                                            cx,
 1892                                        )
 1893                                        .ok();
 1894                                }
 1895                            }
 1896                        }
 1897                    }
 1898                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1899                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1900                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1901                        }
 1902                    }
 1903
 1904                    project::Event::EntryRenamed(transaction) => {
 1905                        let Some(workspace) = editor.workspace() else {
 1906                            return;
 1907                        };
 1908                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1909                        else {
 1910                            return;
 1911                        };
 1912                        if active_editor.entity_id() == cx.entity_id() {
 1913                            let edited_buffers_already_open = {
 1914                                let other_editors: Vec<Entity<Editor>> = workspace
 1915                                    .read(cx)
 1916                                    .panes()
 1917                                    .iter()
 1918                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1919                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1920                                    .collect();
 1921
 1922                                transaction.0.keys().all(|buffer| {
 1923                                    other_editors.iter().any(|editor| {
 1924                                        let multi_buffer = editor.read(cx).buffer();
 1925                                        multi_buffer.read(cx).is_singleton()
 1926                                            && multi_buffer.read(cx).as_singleton().map_or(
 1927                                                false,
 1928                                                |singleton| {
 1929                                                    singleton.entity_id() == buffer.entity_id()
 1930                                                },
 1931                                            )
 1932                                    })
 1933                                })
 1934                            };
 1935
 1936                            if !edited_buffers_already_open {
 1937                                let workspace = workspace.downgrade();
 1938                                let transaction = transaction.clone();
 1939                                cx.defer_in(window, move |_, window, cx| {
 1940                                    cx.spawn_in(window, async move |editor, cx| {
 1941                                        Self::open_project_transaction(
 1942                                            &editor,
 1943                                            workspace,
 1944                                            transaction,
 1945                                            "Rename".to_string(),
 1946                                            cx,
 1947                                        )
 1948                                        .await
 1949                                        .ok()
 1950                                    })
 1951                                    .detach();
 1952                                });
 1953                            }
 1954                        }
 1955                    }
 1956
 1957                    _ => {}
 1958                },
 1959            ));
 1960            if let Some(task_inventory) = project
 1961                .read(cx)
 1962                .task_store()
 1963                .read(cx)
 1964                .task_inventory()
 1965                .cloned()
 1966            {
 1967                project_subscriptions.push(cx.observe_in(
 1968                    &task_inventory,
 1969                    window,
 1970                    |editor, _, window, cx| {
 1971                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1972                    },
 1973                ));
 1974            };
 1975
 1976            project_subscriptions.push(cx.subscribe_in(
 1977                &project.read(cx).breakpoint_store(),
 1978                window,
 1979                |editor, _, event, window, cx| match event {
 1980                    BreakpointStoreEvent::ClearDebugLines => {
 1981                        editor.clear_row_highlights::<ActiveDebugLine>();
 1982                        editor.refresh_inline_values(cx);
 1983                    }
 1984                    BreakpointStoreEvent::SetDebugLine => {
 1985                        if editor.go_to_active_debug_line(window, cx) {
 1986                            cx.stop_propagation();
 1987                        }
 1988
 1989                        editor.refresh_inline_values(cx);
 1990                    }
 1991                    _ => {}
 1992                },
 1993            ));
 1994            let git_store = project.read(cx).git_store().clone();
 1995            let project = project.clone();
 1996            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1997                if let GitStoreEvent::RepositoryUpdated(
 1998                    _,
 1999                    RepositoryEvent::Updated {
 2000                        new_instance: true, ..
 2001                    },
 2002                    _,
 2003                ) = event
 2004                {
 2005                    this.load_diff_task = Some(
 2006                        update_uncommitted_diff_for_buffer(
 2007                            cx.entity(),
 2008                            &project,
 2009                            this.buffer.read(cx).all_buffers(),
 2010                            this.buffer.clone(),
 2011                            cx,
 2012                        )
 2013                        .shared(),
 2014                    );
 2015                }
 2016            }));
 2017        }
 2018
 2019        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2020
 2021        let inlay_hint_settings =
 2022            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2023        let focus_handle = cx.focus_handle();
 2024        if !is_minimap {
 2025            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2026                .detach();
 2027            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2028                .detach();
 2029            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2030                .detach();
 2031            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2032                .detach();
 2033            cx.observe_pending_input(window, Self::observe_pending_input)
 2034                .detach();
 2035        }
 2036
 2037        let show_indent_guides =
 2038            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2039                Some(false)
 2040            } else {
 2041                None
 2042            };
 2043
 2044        let breakpoint_store = match (&mode, project.as_ref()) {
 2045            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2046            _ => None,
 2047        };
 2048
 2049        let mut code_action_providers = Vec::new();
 2050        let mut load_uncommitted_diff = None;
 2051        if let Some(project) = project.clone() {
 2052            load_uncommitted_diff = Some(
 2053                update_uncommitted_diff_for_buffer(
 2054                    cx.entity(),
 2055                    &project,
 2056                    buffer.read(cx).all_buffers(),
 2057                    buffer.clone(),
 2058                    cx,
 2059                )
 2060                .shared(),
 2061            );
 2062            code_action_providers.push(Rc::new(project) as Rc<_>);
 2063        }
 2064
 2065        let mut editor = Self {
 2066            focus_handle,
 2067            show_cursor_when_unfocused: false,
 2068            last_focused_descendant: None,
 2069            buffer: buffer.clone(),
 2070            display_map: display_map.clone(),
 2071            selections,
 2072            scroll_manager: ScrollManager::new(cx),
 2073            columnar_selection_state: None,
 2074            add_selections_state: None,
 2075            select_next_state: None,
 2076            select_prev_state: None,
 2077            selection_history: SelectionHistory::default(),
 2078            defer_selection_effects: false,
 2079            deferred_selection_effects_state: None,
 2080            autoclose_regions: Vec::new(),
 2081            snippet_stack: InvalidationStack::default(),
 2082            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2083            ime_transaction: None,
 2084            active_diagnostics: ActiveDiagnostic::None,
 2085            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2086            inline_diagnostics_update: Task::ready(()),
 2087            inline_diagnostics: Vec::new(),
 2088            soft_wrap_mode_override,
 2089            diagnostics_max_severity,
 2090            hard_wrap: None,
 2091            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2092            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2093            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2094            project,
 2095            blink_manager: blink_manager.clone(),
 2096            show_local_selections: true,
 2097            show_scrollbars: ScrollbarAxes {
 2098                horizontal: full_mode,
 2099                vertical: full_mode,
 2100            },
 2101            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2102            offset_content: !matches!(mode, EditorMode::SingleLine),
 2103            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2104            show_gutter: full_mode,
 2105            show_line_numbers: (!full_mode).then_some(false),
 2106            use_relative_line_numbers: None,
 2107            disable_expand_excerpt_buttons: !full_mode,
 2108            show_git_diff_gutter: None,
 2109            show_code_actions: None,
 2110            show_runnables: None,
 2111            show_breakpoints: None,
 2112            show_wrap_guides: None,
 2113            show_indent_guides,
 2114            placeholder_text: None,
 2115            highlight_order: 0,
 2116            highlighted_rows: HashMap::default(),
 2117            background_highlights: TreeMap::default(),
 2118            gutter_highlights: TreeMap::default(),
 2119            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2120            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2121            nav_history: None,
 2122            context_menu: RefCell::new(None),
 2123            context_menu_options: None,
 2124            mouse_context_menu: None,
 2125            completion_tasks: Vec::new(),
 2126            inline_blame_popover: None,
 2127            inline_blame_popover_show_task: None,
 2128            signature_help_state: SignatureHelpState::default(),
 2129            auto_signature_help: None,
 2130            find_all_references_task_sources: Vec::new(),
 2131            next_completion_id: 0,
 2132            next_inlay_id: 0,
 2133            code_action_providers,
 2134            available_code_actions: None,
 2135            code_actions_task: None,
 2136            quick_selection_highlight_task: None,
 2137            debounced_selection_highlight_task: None,
 2138            document_highlights_task: None,
 2139            linked_editing_range_task: None,
 2140            pending_rename: None,
 2141            searchable: !is_minimap,
 2142            cursor_shape: EditorSettings::get_global(cx)
 2143                .cursor_shape
 2144                .unwrap_or_default(),
 2145            current_line_highlight: None,
 2146            autoindent_mode: Some(AutoindentMode::EachLine),
 2147            collapse_matches: false,
 2148            workspace: None,
 2149            input_enabled: !is_minimap,
 2150            use_modal_editing: full_mode,
 2151            read_only: is_minimap,
 2152            use_autoclose: true,
 2153            use_auto_surround: true,
 2154            auto_replace_emoji_shortcode: false,
 2155            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2156            leader_id: None,
 2157            remote_id: None,
 2158            hover_state: HoverState::default(),
 2159            pending_mouse_down: None,
 2160            hovered_link_state: None,
 2161            edit_prediction_provider: None,
 2162            active_edit_prediction: None,
 2163            stale_edit_prediction_in_menu: None,
 2164            edit_prediction_preview: EditPredictionPreview::Inactive {
 2165                released_too_fast: false,
 2166            },
 2167            inline_diagnostics_enabled: full_mode,
 2168            diagnostics_enabled: full_mode,
 2169            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2170            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2171            gutter_hovered: false,
 2172            pixel_position_of_newest_cursor: None,
 2173            last_bounds: None,
 2174            last_position_map: None,
 2175            expect_bounds_change: None,
 2176            gutter_dimensions: GutterDimensions::default(),
 2177            style: None,
 2178            show_cursor_names: false,
 2179            hovered_cursors: HashMap::default(),
 2180            next_editor_action_id: EditorActionId::default(),
 2181            editor_actions: Rc::default(),
 2182            edit_predictions_hidden_for_vim_mode: false,
 2183            show_edit_predictions_override: None,
 2184            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2185            edit_prediction_settings: EditPredictionSettings::Disabled,
 2186            edit_prediction_indent_conflict: false,
 2187            edit_prediction_requires_modifier_in_indent_conflict: true,
 2188            custom_context_menu: None,
 2189            show_git_blame_gutter: false,
 2190            show_git_blame_inline: false,
 2191            show_selection_menu: None,
 2192            show_git_blame_inline_delay_task: None,
 2193            git_blame_inline_enabled: full_mode
 2194                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2195            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2196            serialize_dirty_buffers: !is_minimap
 2197                && ProjectSettings::get_global(cx)
 2198                    .session
 2199                    .restore_unsaved_buffers,
 2200            blame: None,
 2201            blame_subscription: None,
 2202            tasks: BTreeMap::default(),
 2203
 2204            breakpoint_store,
 2205            gutter_breakpoint_indicator: (None, None),
 2206            hovered_diff_hunk_row: None,
 2207            _subscriptions: (!is_minimap)
 2208                .then(|| {
 2209                    vec![
 2210                        cx.observe(&buffer, Self::on_buffer_changed),
 2211                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2212                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2213                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2214                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2215                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2216                        cx.observe_window_activation(window, |editor, window, cx| {
 2217                            let active = window.is_window_active();
 2218                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2219                                if active {
 2220                                    blink_manager.enable(cx);
 2221                                } else {
 2222                                    blink_manager.disable(cx);
 2223                                }
 2224                            });
 2225                            if active {
 2226                                editor.show_mouse_cursor(cx);
 2227                            }
 2228                        }),
 2229                    ]
 2230                })
 2231                .unwrap_or_default(),
 2232            tasks_update_task: None,
 2233            pull_diagnostics_task: Task::ready(()),
 2234            colors: None,
 2235            next_color_inlay_id: 0,
 2236            linked_edit_ranges: Default::default(),
 2237            in_project_search: false,
 2238            previous_search_ranges: None,
 2239            breadcrumb_header: None,
 2240            focused_block: None,
 2241            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2242            addons: HashMap::default(),
 2243            registered_buffers: HashMap::default(),
 2244            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2245            selection_mark_mode: false,
 2246            toggle_fold_multiple_buffers: Task::ready(()),
 2247            serialize_selections: Task::ready(()),
 2248            serialize_folds: Task::ready(()),
 2249            text_style_refinement: None,
 2250            load_diff_task: load_uncommitted_diff,
 2251            temporary_diff_override: false,
 2252            mouse_cursor_hidden: false,
 2253            minimap: None,
 2254            hide_mouse_mode: EditorSettings::get_global(cx)
 2255                .hide_mouse
 2256                .unwrap_or_default(),
 2257            change_list: ChangeList::new(),
 2258            mode,
 2259            selection_drag_state: SelectionDragState::None,
 2260            folding_newlines: Task::ready(()),
 2261        };
 2262
 2263        if is_minimap {
 2264            return editor;
 2265        }
 2266
 2267        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2268            editor
 2269                ._subscriptions
 2270                .push(cx.observe(breakpoints, |_, _, cx| {
 2271                    cx.notify();
 2272                }));
 2273        }
 2274        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2275        editor._subscriptions.extend(project_subscriptions);
 2276
 2277        editor._subscriptions.push(cx.subscribe_in(
 2278            &cx.entity(),
 2279            window,
 2280            |editor, _, e: &EditorEvent, window, cx| match e {
 2281                EditorEvent::ScrollPositionChanged { local, .. } => {
 2282                    if *local {
 2283                        let new_anchor = editor.scroll_manager.anchor();
 2284                        let snapshot = editor.snapshot(window, cx);
 2285                        editor.update_restoration_data(cx, move |data| {
 2286                            data.scroll_position = (
 2287                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2288                                new_anchor.offset,
 2289                            );
 2290                        });
 2291                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2292                        editor.inline_blame_popover.take();
 2293                    }
 2294                }
 2295                EditorEvent::Edited { .. } => {
 2296                    if !vim_enabled(cx) {
 2297                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2298                        let pop_state = editor
 2299                            .change_list
 2300                            .last()
 2301                            .map(|previous| {
 2302                                previous.len() == selections.len()
 2303                                    && previous.iter().enumerate().all(|(ix, p)| {
 2304                                        p.to_display_point(&map).row()
 2305                                            == selections[ix].head().row()
 2306                                    })
 2307                            })
 2308                            .unwrap_or(false);
 2309                        let new_positions = selections
 2310                            .into_iter()
 2311                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2312                            .collect();
 2313                        editor
 2314                            .change_list
 2315                            .push_to_change_list(pop_state, new_positions);
 2316                    }
 2317                }
 2318                _ => (),
 2319            },
 2320        ));
 2321
 2322        if let Some(dap_store) = editor
 2323            .project
 2324            .as_ref()
 2325            .map(|project| project.read(cx).dap_store())
 2326        {
 2327            let weak_editor = cx.weak_entity();
 2328
 2329            editor
 2330                ._subscriptions
 2331                .push(
 2332                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2333                        let session_entity = cx.entity();
 2334                        weak_editor
 2335                            .update(cx, |editor, cx| {
 2336                                editor._subscriptions.push(
 2337                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2338                                );
 2339                            })
 2340                            .ok();
 2341                    }),
 2342                );
 2343
 2344            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2345                editor
 2346                    ._subscriptions
 2347                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2348            }
 2349        }
 2350
 2351        // skip adding the initial selection to selection history
 2352        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2353        editor.end_selection(window, cx);
 2354        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2355
 2356        editor.scroll_manager.show_scrollbars(window, cx);
 2357        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2358
 2359        if full_mode {
 2360            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2361            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2362
 2363            if editor.git_blame_inline_enabled {
 2364                editor.start_git_blame_inline(false, window, cx);
 2365            }
 2366
 2367            editor.go_to_active_debug_line(window, cx);
 2368
 2369            if let Some(buffer) = buffer.read(cx).as_singleton()
 2370                && let Some(project) = editor.project()
 2371            {
 2372                let handle = project.update(cx, |project, cx| {
 2373                    project.register_buffer_with_language_servers(&buffer, cx)
 2374                });
 2375                editor
 2376                    .registered_buffers
 2377                    .insert(buffer.read(cx).remote_id(), handle);
 2378            }
 2379
 2380            editor.minimap =
 2381                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2382            editor.colors = Some(LspColorData::new(cx));
 2383            editor.update_lsp_data(false, None, window, cx);
 2384        }
 2385
 2386        if editor.mode.is_full() {
 2387            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2388        }
 2389
 2390        editor
 2391    }
 2392
 2393    pub fn deploy_mouse_context_menu(
 2394        &mut self,
 2395        position: gpui::Point<Pixels>,
 2396        context_menu: Entity<ContextMenu>,
 2397        window: &mut Window,
 2398        cx: &mut Context<Self>,
 2399    ) {
 2400        self.mouse_context_menu = Some(MouseContextMenu::new(
 2401            self,
 2402            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2403            context_menu,
 2404            window,
 2405            cx,
 2406        ));
 2407    }
 2408
 2409    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2410        self.mouse_context_menu
 2411            .as_ref()
 2412            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2413    }
 2414
 2415    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2416        if self
 2417            .selections
 2418            .pending
 2419            .as_ref()
 2420            .is_some_and(|pending_selection| {
 2421                let snapshot = self.buffer().read(cx).snapshot(cx);
 2422                pending_selection
 2423                    .selection
 2424                    .range()
 2425                    .includes(range, &snapshot)
 2426            })
 2427        {
 2428            return true;
 2429        }
 2430
 2431        self.selections
 2432            .disjoint_in_range::<usize>(range.clone(), cx)
 2433            .into_iter()
 2434            .any(|selection| {
 2435                // This is needed to cover a corner case, if we just check for an existing
 2436                // selection in the fold range, having a cursor at the start of the fold
 2437                // marks it as selected. Non-empty selections don't cause this.
 2438                let length = selection.end - selection.start;
 2439                length > 0
 2440            })
 2441    }
 2442
 2443    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2444        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2445    }
 2446
 2447    fn key_context_internal(
 2448        &self,
 2449        has_active_edit_prediction: bool,
 2450        window: &Window,
 2451        cx: &App,
 2452    ) -> KeyContext {
 2453        let mut key_context = KeyContext::new_with_defaults();
 2454        key_context.add("Editor");
 2455        let mode = match self.mode {
 2456            EditorMode::SingleLine => "single_line",
 2457            EditorMode::AutoHeight { .. } => "auto_height",
 2458            EditorMode::Minimap { .. } => "minimap",
 2459            EditorMode::Full { .. } => "full",
 2460        };
 2461
 2462        if EditorSettings::jupyter_enabled(cx) {
 2463            key_context.add("jupyter");
 2464        }
 2465
 2466        key_context.set("mode", mode);
 2467        if self.pending_rename.is_some() {
 2468            key_context.add("renaming");
 2469        }
 2470
 2471        match self.context_menu.borrow().as_ref() {
 2472            Some(CodeContextMenu::Completions(menu)) => {
 2473                if menu.visible() {
 2474                    key_context.add("menu");
 2475                    key_context.add("showing_completions");
 2476                }
 2477            }
 2478            Some(CodeContextMenu::CodeActions(menu)) => {
 2479                if menu.visible() {
 2480                    key_context.add("menu");
 2481                    key_context.add("showing_code_actions")
 2482                }
 2483            }
 2484            None => {}
 2485        }
 2486
 2487        if self.signature_help_state.has_multiple_signatures() {
 2488            key_context.add("showing_signature_help");
 2489        }
 2490
 2491        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2492        if !self.focus_handle(cx).contains_focused(window, cx)
 2493            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2494        {
 2495            for addon in self.addons.values() {
 2496                addon.extend_key_context(&mut key_context, cx)
 2497            }
 2498        }
 2499
 2500        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2501            if let Some(extension) = singleton_buffer
 2502                .read(cx)
 2503                .file()
 2504                .and_then(|file| file.path().extension()?.to_str())
 2505            {
 2506                key_context.set("extension", extension.to_string());
 2507            }
 2508        } else {
 2509            key_context.add("multibuffer");
 2510        }
 2511
 2512        if has_active_edit_prediction {
 2513            if self.edit_prediction_in_conflict() {
 2514                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2515            } else {
 2516                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2517                key_context.add("copilot_suggestion");
 2518            }
 2519        }
 2520
 2521        if self.selection_mark_mode {
 2522            key_context.add("selection_mode");
 2523        }
 2524
 2525        key_context
 2526    }
 2527
 2528    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2529        if self.mouse_cursor_hidden {
 2530            self.mouse_cursor_hidden = false;
 2531            cx.notify();
 2532        }
 2533    }
 2534
 2535    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2536        let hide_mouse_cursor = match origin {
 2537            HideMouseCursorOrigin::TypingAction => {
 2538                matches!(
 2539                    self.hide_mouse_mode,
 2540                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2541                )
 2542            }
 2543            HideMouseCursorOrigin::MovementAction => {
 2544                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2545            }
 2546        };
 2547        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2548            self.mouse_cursor_hidden = hide_mouse_cursor;
 2549            cx.notify();
 2550        }
 2551    }
 2552
 2553    pub fn edit_prediction_in_conflict(&self) -> bool {
 2554        if !self.show_edit_predictions_in_menu() {
 2555            return false;
 2556        }
 2557
 2558        let showing_completions = self
 2559            .context_menu
 2560            .borrow()
 2561            .as_ref()
 2562            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2563
 2564        showing_completions
 2565            || self.edit_prediction_requires_modifier()
 2566            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2567            // bindings to insert tab characters.
 2568            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2569    }
 2570
 2571    pub fn accept_edit_prediction_keybind(
 2572        &self,
 2573        accept_partial: bool,
 2574        window: &Window,
 2575        cx: &App,
 2576    ) -> AcceptEditPredictionBinding {
 2577        let key_context = self.key_context_internal(true, window, cx);
 2578        let in_conflict = self.edit_prediction_in_conflict();
 2579
 2580        let bindings = if accept_partial {
 2581            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2582        } else {
 2583            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2584        };
 2585
 2586        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2587        // just the first one.
 2588        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2589            !in_conflict
 2590                || binding
 2591                    .keystrokes()
 2592                    .first()
 2593                    .is_some_and(|keystroke| keystroke.modifiers.modified())
 2594        }))
 2595    }
 2596
 2597    pub fn new_file(
 2598        workspace: &mut Workspace,
 2599        _: &workspace::NewFile,
 2600        window: &mut Window,
 2601        cx: &mut Context<Workspace>,
 2602    ) {
 2603        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2604            "Failed to create buffer",
 2605            window,
 2606            cx,
 2607            |e, _, _| match e.error_code() {
 2608                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2609                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2610                e.error_tag("required").unwrap_or("the latest version")
 2611            )),
 2612                _ => None,
 2613            },
 2614        );
 2615    }
 2616
 2617    pub fn new_in_workspace(
 2618        workspace: &mut Workspace,
 2619        window: &mut Window,
 2620        cx: &mut Context<Workspace>,
 2621    ) -> Task<Result<Entity<Editor>>> {
 2622        let project = workspace.project().clone();
 2623        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2624
 2625        cx.spawn_in(window, async move |workspace, cx| {
 2626            let buffer = create.await?;
 2627            workspace.update_in(cx, |workspace, window, cx| {
 2628                let editor =
 2629                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2630                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2631                editor
 2632            })
 2633        })
 2634    }
 2635
 2636    fn new_file_vertical(
 2637        workspace: &mut Workspace,
 2638        _: &workspace::NewFileSplitVertical,
 2639        window: &mut Window,
 2640        cx: &mut Context<Workspace>,
 2641    ) {
 2642        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2643    }
 2644
 2645    fn new_file_horizontal(
 2646        workspace: &mut Workspace,
 2647        _: &workspace::NewFileSplitHorizontal,
 2648        window: &mut Window,
 2649        cx: &mut Context<Workspace>,
 2650    ) {
 2651        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2652    }
 2653
 2654    fn new_file_in_direction(
 2655        workspace: &mut Workspace,
 2656        direction: SplitDirection,
 2657        window: &mut Window,
 2658        cx: &mut Context<Workspace>,
 2659    ) {
 2660        let project = workspace.project().clone();
 2661        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2662
 2663        cx.spawn_in(window, async move |workspace, cx| {
 2664            let buffer = create.await?;
 2665            workspace.update_in(cx, move |workspace, window, cx| {
 2666                workspace.split_item(
 2667                    direction,
 2668                    Box::new(
 2669                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2670                    ),
 2671                    window,
 2672                    cx,
 2673                )
 2674            })?;
 2675            anyhow::Ok(())
 2676        })
 2677        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2678            match e.error_code() {
 2679                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2680                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2681                e.error_tag("required").unwrap_or("the latest version")
 2682            )),
 2683                _ => None,
 2684            }
 2685        });
 2686    }
 2687
 2688    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2689        self.leader_id
 2690    }
 2691
 2692    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2693        &self.buffer
 2694    }
 2695
 2696    pub fn project(&self) -> Option<&Entity<Project>> {
 2697        self.project.as_ref()
 2698    }
 2699
 2700    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2701        self.workspace.as_ref()?.0.upgrade()
 2702    }
 2703
 2704    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2705        self.buffer().read(cx).title(cx)
 2706    }
 2707
 2708    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2709        let git_blame_gutter_max_author_length = self
 2710            .render_git_blame_gutter(cx)
 2711            .then(|| {
 2712                if let Some(blame) = self.blame.as_ref() {
 2713                    let max_author_length =
 2714                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2715                    Some(max_author_length)
 2716                } else {
 2717                    None
 2718                }
 2719            })
 2720            .flatten();
 2721
 2722        EditorSnapshot {
 2723            mode: self.mode.clone(),
 2724            show_gutter: self.show_gutter,
 2725            show_line_numbers: self.show_line_numbers,
 2726            show_git_diff_gutter: self.show_git_diff_gutter,
 2727            show_code_actions: self.show_code_actions,
 2728            show_runnables: self.show_runnables,
 2729            show_breakpoints: self.show_breakpoints,
 2730            git_blame_gutter_max_author_length,
 2731            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2732            scroll_anchor: self.scroll_manager.anchor(),
 2733            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2734            placeholder_text: self.placeholder_text.clone(),
 2735            is_focused: self.focus_handle.is_focused(window),
 2736            current_line_highlight: self
 2737                .current_line_highlight
 2738                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2739            gutter_hovered: self.gutter_hovered,
 2740        }
 2741    }
 2742
 2743    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2744        self.buffer.read(cx).language_at(point, cx)
 2745    }
 2746
 2747    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2748        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2749    }
 2750
 2751    pub fn active_excerpt(
 2752        &self,
 2753        cx: &App,
 2754    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2755        self.buffer
 2756            .read(cx)
 2757            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2758    }
 2759
 2760    pub fn mode(&self) -> &EditorMode {
 2761        &self.mode
 2762    }
 2763
 2764    pub fn set_mode(&mut self, mode: EditorMode) {
 2765        self.mode = mode;
 2766    }
 2767
 2768    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2769        self.collaboration_hub.as_deref()
 2770    }
 2771
 2772    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2773        self.collaboration_hub = Some(hub);
 2774    }
 2775
 2776    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2777        self.in_project_search = in_project_search;
 2778    }
 2779
 2780    pub fn set_custom_context_menu(
 2781        &mut self,
 2782        f: impl 'static
 2783        + Fn(
 2784            &mut Self,
 2785            DisplayPoint,
 2786            &mut Window,
 2787            &mut Context<Self>,
 2788        ) -> Option<Entity<ui::ContextMenu>>,
 2789    ) {
 2790        self.custom_context_menu = Some(Box::new(f))
 2791    }
 2792
 2793    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2794        self.completion_provider = provider;
 2795    }
 2796
 2797    #[cfg(any(test, feature = "test-support"))]
 2798    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2799        self.completion_provider.clone()
 2800    }
 2801
 2802    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2803        self.semantics_provider.clone()
 2804    }
 2805
 2806    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2807        self.semantics_provider = provider;
 2808    }
 2809
 2810    pub fn set_edit_prediction_provider<T>(
 2811        &mut self,
 2812        provider: Option<Entity<T>>,
 2813        window: &mut Window,
 2814        cx: &mut Context<Self>,
 2815    ) where
 2816        T: EditPredictionProvider,
 2817    {
 2818        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2819            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2820                if this.focus_handle.is_focused(window) {
 2821                    this.update_visible_edit_prediction(window, cx);
 2822                }
 2823            }),
 2824            provider: Arc::new(provider),
 2825        });
 2826        self.update_edit_prediction_settings(cx);
 2827        self.refresh_edit_prediction(false, false, window, cx);
 2828    }
 2829
 2830    pub fn placeholder_text(&self) -> Option<&str> {
 2831        self.placeholder_text.as_deref()
 2832    }
 2833
 2834    pub fn set_placeholder_text(
 2835        &mut self,
 2836        placeholder_text: impl Into<Arc<str>>,
 2837        cx: &mut Context<Self>,
 2838    ) {
 2839        let placeholder_text = Some(placeholder_text.into());
 2840        if self.placeholder_text != placeholder_text {
 2841            self.placeholder_text = placeholder_text;
 2842            cx.notify();
 2843        }
 2844    }
 2845
 2846    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2847        self.cursor_shape = cursor_shape;
 2848
 2849        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2850        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2851
 2852        cx.notify();
 2853    }
 2854
 2855    pub fn set_current_line_highlight(
 2856        &mut self,
 2857        current_line_highlight: Option<CurrentLineHighlight>,
 2858    ) {
 2859        self.current_line_highlight = current_line_highlight;
 2860    }
 2861
 2862    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2863        self.collapse_matches = collapse_matches;
 2864    }
 2865
 2866    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2867        let buffers = self.buffer.read(cx).all_buffers();
 2868        let Some(project) = self.project.as_ref() else {
 2869            return;
 2870        };
 2871        project.update(cx, |project, cx| {
 2872            for buffer in buffers {
 2873                self.registered_buffers
 2874                    .entry(buffer.read(cx).remote_id())
 2875                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2876            }
 2877        })
 2878    }
 2879
 2880    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2881        if self.collapse_matches {
 2882            return range.start..range.start;
 2883        }
 2884        range.clone()
 2885    }
 2886
 2887    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2888        if self.display_map.read(cx).clip_at_line_ends != clip {
 2889            self.display_map
 2890                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2891        }
 2892    }
 2893
 2894    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2895        self.input_enabled = input_enabled;
 2896    }
 2897
 2898    pub fn set_edit_predictions_hidden_for_vim_mode(
 2899        &mut self,
 2900        hidden: bool,
 2901        window: &mut Window,
 2902        cx: &mut Context<Self>,
 2903    ) {
 2904        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2905            self.edit_predictions_hidden_for_vim_mode = hidden;
 2906            if hidden {
 2907                self.update_visible_edit_prediction(window, cx);
 2908            } else {
 2909                self.refresh_edit_prediction(true, false, window, cx);
 2910            }
 2911        }
 2912    }
 2913
 2914    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2915        self.menu_edit_predictions_policy = value;
 2916    }
 2917
 2918    pub fn set_autoindent(&mut self, autoindent: bool) {
 2919        if autoindent {
 2920            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2921        } else {
 2922            self.autoindent_mode = None;
 2923        }
 2924    }
 2925
 2926    pub fn read_only(&self, cx: &App) -> bool {
 2927        self.read_only || self.buffer.read(cx).read_only()
 2928    }
 2929
 2930    pub fn set_read_only(&mut self, read_only: bool) {
 2931        self.read_only = read_only;
 2932    }
 2933
 2934    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2935        self.use_autoclose = autoclose;
 2936    }
 2937
 2938    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2939        self.use_auto_surround = auto_surround;
 2940    }
 2941
 2942    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2943        self.auto_replace_emoji_shortcode = auto_replace;
 2944    }
 2945
 2946    pub fn toggle_edit_predictions(
 2947        &mut self,
 2948        _: &ToggleEditPrediction,
 2949        window: &mut Window,
 2950        cx: &mut Context<Self>,
 2951    ) {
 2952        if self.show_edit_predictions_override.is_some() {
 2953            self.set_show_edit_predictions(None, window, cx);
 2954        } else {
 2955            let show_edit_predictions = !self.edit_predictions_enabled();
 2956            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2957        }
 2958    }
 2959
 2960    pub fn set_show_edit_predictions(
 2961        &mut self,
 2962        show_edit_predictions: Option<bool>,
 2963        window: &mut Window,
 2964        cx: &mut Context<Self>,
 2965    ) {
 2966        self.show_edit_predictions_override = show_edit_predictions;
 2967        self.update_edit_prediction_settings(cx);
 2968
 2969        if let Some(false) = show_edit_predictions {
 2970            self.discard_edit_prediction(false, cx);
 2971        } else {
 2972            self.refresh_edit_prediction(false, true, window, cx);
 2973        }
 2974    }
 2975
 2976    fn edit_predictions_disabled_in_scope(
 2977        &self,
 2978        buffer: &Entity<Buffer>,
 2979        buffer_position: language::Anchor,
 2980        cx: &App,
 2981    ) -> bool {
 2982        let snapshot = buffer.read(cx).snapshot();
 2983        let settings = snapshot.settings_at(buffer_position, cx);
 2984
 2985        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2986            return false;
 2987        };
 2988
 2989        scope.override_name().is_some_and(|scope_name| {
 2990            settings
 2991                .edit_predictions_disabled_in
 2992                .iter()
 2993                .any(|s| s == scope_name)
 2994        })
 2995    }
 2996
 2997    pub fn set_use_modal_editing(&mut self, to: bool) {
 2998        self.use_modal_editing = to;
 2999    }
 3000
 3001    pub fn use_modal_editing(&self) -> bool {
 3002        self.use_modal_editing
 3003    }
 3004
 3005    fn selections_did_change(
 3006        &mut self,
 3007        local: bool,
 3008        old_cursor_position: &Anchor,
 3009        effects: SelectionEffects,
 3010        window: &mut Window,
 3011        cx: &mut Context<Self>,
 3012    ) {
 3013        window.invalidate_character_coordinates();
 3014
 3015        // Copy selections to primary selection buffer
 3016        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3017        if local {
 3018            let selections = self.selections.all::<usize>(cx);
 3019            let buffer_handle = self.buffer.read(cx).read(cx);
 3020
 3021            let mut text = String::new();
 3022            for (index, selection) in selections.iter().enumerate() {
 3023                let text_for_selection = buffer_handle
 3024                    .text_for_range(selection.start..selection.end)
 3025                    .collect::<String>();
 3026
 3027                text.push_str(&text_for_selection);
 3028                if index != selections.len() - 1 {
 3029                    text.push('\n');
 3030                }
 3031            }
 3032
 3033            if !text.is_empty() {
 3034                cx.write_to_primary(ClipboardItem::new_string(text));
 3035            }
 3036        }
 3037
 3038        let selection_anchors = self.selections.disjoint_anchors();
 3039
 3040        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3041            self.buffer.update(cx, |buffer, cx| {
 3042                buffer.set_active_selections(
 3043                    &selection_anchors,
 3044                    self.selections.line_mode,
 3045                    self.cursor_shape,
 3046                    cx,
 3047                )
 3048            });
 3049        }
 3050        let display_map = self
 3051            .display_map
 3052            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3053        let buffer = &display_map.buffer_snapshot;
 3054        if self.selections.count() == 1 {
 3055            self.add_selections_state = None;
 3056        }
 3057        self.select_next_state = None;
 3058        self.select_prev_state = None;
 3059        self.select_syntax_node_history.try_clear();
 3060        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3061        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3062        self.take_rename(false, window, cx);
 3063
 3064        let newest_selection = self.selections.newest_anchor();
 3065        let new_cursor_position = newest_selection.head();
 3066        let selection_start = newest_selection.start;
 3067
 3068        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3069            self.push_to_nav_history(
 3070                *old_cursor_position,
 3071                Some(new_cursor_position.to_point(buffer)),
 3072                false,
 3073                effects.nav_history == Some(true),
 3074                cx,
 3075            );
 3076        }
 3077
 3078        if local {
 3079            if let Some(buffer_id) = new_cursor_position.buffer_id
 3080                && !self.registered_buffers.contains_key(&buffer_id)
 3081                && let Some(project) = self.project.as_ref()
 3082            {
 3083                project.update(cx, |project, cx| {
 3084                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3085                        return;
 3086                    };
 3087                    self.registered_buffers.insert(
 3088                        buffer_id,
 3089                        project.register_buffer_with_language_servers(&buffer, cx),
 3090                    );
 3091                })
 3092            }
 3093
 3094            let mut context_menu = self.context_menu.borrow_mut();
 3095            let completion_menu = match context_menu.as_ref() {
 3096                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3097                Some(CodeContextMenu::CodeActions(_)) => {
 3098                    *context_menu = None;
 3099                    None
 3100                }
 3101                None => None,
 3102            };
 3103            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3104            drop(context_menu);
 3105
 3106            if effects.completions
 3107                && let Some(completion_position) = completion_position
 3108            {
 3109                let start_offset = selection_start.to_offset(buffer);
 3110                let position_matches = start_offset == completion_position.to_offset(buffer);
 3111                let continue_showing = if position_matches {
 3112                    if self.snippet_stack.is_empty() {
 3113                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3114                    } else {
 3115                        // Snippet choices can be shown even when the cursor is in whitespace.
 3116                        // Dismissing the menu with actions like backspace is handled by
 3117                        // invalidation regions.
 3118                        true
 3119                    }
 3120                } else {
 3121                    false
 3122                };
 3123
 3124                if continue_showing {
 3125                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3126                } else {
 3127                    self.hide_context_menu(window, cx);
 3128                }
 3129            }
 3130
 3131            hide_hover(self, cx);
 3132
 3133            if old_cursor_position.to_display_point(&display_map).row()
 3134                != new_cursor_position.to_display_point(&display_map).row()
 3135            {
 3136                self.available_code_actions.take();
 3137            }
 3138            self.refresh_code_actions(window, cx);
 3139            self.refresh_document_highlights(cx);
 3140            self.refresh_selected_text_highlights(false, window, cx);
 3141            refresh_matching_bracket_highlights(self, window, cx);
 3142            self.update_visible_edit_prediction(window, cx);
 3143            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3144            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3145            self.inline_blame_popover.take();
 3146            if self.git_blame_inline_enabled {
 3147                self.start_inline_blame_timer(window, cx);
 3148            }
 3149        }
 3150
 3151        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3152        cx.emit(EditorEvent::SelectionsChanged { local });
 3153
 3154        let selections = &self.selections.disjoint;
 3155        if selections.len() == 1 {
 3156            cx.emit(SearchEvent::ActiveMatchChanged)
 3157        }
 3158        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3159            let inmemory_selections = selections
 3160                .iter()
 3161                .map(|s| {
 3162                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3163                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3164                })
 3165                .collect();
 3166            self.update_restoration_data(cx, |data| {
 3167                data.selections = inmemory_selections;
 3168            });
 3169
 3170            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3171                && let Some(workspace_id) =
 3172                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3173            {
 3174                let snapshot = self.buffer().read(cx).snapshot(cx);
 3175                let selections = selections.clone();
 3176                let background_executor = cx.background_executor().clone();
 3177                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3178                self.serialize_selections = cx.background_spawn(async move {
 3179                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3180                            let db_selections = selections
 3181                                .iter()
 3182                                .map(|selection| {
 3183                                    (
 3184                                        selection.start.to_offset(&snapshot),
 3185                                        selection.end.to_offset(&snapshot),
 3186                                    )
 3187                                })
 3188                                .collect();
 3189
 3190                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3191                                .await
 3192                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3193                                .log_err();
 3194                        });
 3195            }
 3196        }
 3197
 3198        cx.notify();
 3199    }
 3200
 3201    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3202        use text::ToOffset as _;
 3203        use text::ToPoint as _;
 3204
 3205        if self.mode.is_minimap()
 3206            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3207        {
 3208            return;
 3209        }
 3210
 3211        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3212            return;
 3213        };
 3214
 3215        let snapshot = singleton.read(cx).snapshot();
 3216        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3217            let display_snapshot = display_map.snapshot(cx);
 3218
 3219            display_snapshot
 3220                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3221                .map(|fold| {
 3222                    fold.range.start.text_anchor.to_point(&snapshot)
 3223                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3224                })
 3225                .collect()
 3226        });
 3227        self.update_restoration_data(cx, |data| {
 3228            data.folds = inmemory_folds;
 3229        });
 3230
 3231        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3232            return;
 3233        };
 3234        let background_executor = cx.background_executor().clone();
 3235        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3236        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3237            display_map
 3238                .snapshot(cx)
 3239                .folds_in_range(0..snapshot.len())
 3240                .map(|fold| {
 3241                    (
 3242                        fold.range.start.text_anchor.to_offset(&snapshot),
 3243                        fold.range.end.text_anchor.to_offset(&snapshot),
 3244                    )
 3245                })
 3246                .collect()
 3247        });
 3248        self.serialize_folds = cx.background_spawn(async move {
 3249            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3250            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3251                .await
 3252                .with_context(|| {
 3253                    format!(
 3254                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3255                    )
 3256                })
 3257                .log_err();
 3258        });
 3259    }
 3260
 3261    pub fn sync_selections(
 3262        &mut self,
 3263        other: Entity<Editor>,
 3264        cx: &mut Context<Self>,
 3265    ) -> gpui::Subscription {
 3266        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3267        self.selections.change_with(cx, |selections| {
 3268            selections.select_anchors(other_selections);
 3269        });
 3270
 3271        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3272            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3273                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3274                if other_selections.is_empty() {
 3275                    return;
 3276                }
 3277                this.selections.change_with(cx, |selections| {
 3278                    selections.select_anchors(other_selections);
 3279                });
 3280            }
 3281        });
 3282
 3283        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3284            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3285                let these_selections = this.selections.disjoint.to_vec();
 3286                if these_selections.is_empty() {
 3287                    return;
 3288                }
 3289                other.update(cx, |other_editor, cx| {
 3290                    other_editor.selections.change_with(cx, |selections| {
 3291                        selections.select_anchors(these_selections);
 3292                    })
 3293                });
 3294            }
 3295        });
 3296
 3297        Subscription::join(other_subscription, this_subscription)
 3298    }
 3299
 3300    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3301    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3302    /// effects of selection change occur at the end of the transaction.
 3303    pub fn change_selections<R>(
 3304        &mut self,
 3305        effects: SelectionEffects,
 3306        window: &mut Window,
 3307        cx: &mut Context<Self>,
 3308        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3309    ) -> R {
 3310        if let Some(state) = &mut self.deferred_selection_effects_state {
 3311            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3312            state.effects.completions = effects.completions;
 3313            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3314            let (changed, result) = self.selections.change_with(cx, change);
 3315            state.changed |= changed;
 3316            return result;
 3317        }
 3318        let mut state = DeferredSelectionEffectsState {
 3319            changed: false,
 3320            effects,
 3321            old_cursor_position: self.selections.newest_anchor().head(),
 3322            history_entry: SelectionHistoryEntry {
 3323                selections: self.selections.disjoint_anchors(),
 3324                select_next_state: self.select_next_state.clone(),
 3325                select_prev_state: self.select_prev_state.clone(),
 3326                add_selections_state: self.add_selections_state.clone(),
 3327            },
 3328        };
 3329        let (changed, result) = self.selections.change_with(cx, change);
 3330        state.changed = state.changed || changed;
 3331        if self.defer_selection_effects {
 3332            self.deferred_selection_effects_state = Some(state);
 3333        } else {
 3334            self.apply_selection_effects(state, window, cx);
 3335        }
 3336        result
 3337    }
 3338
 3339    /// Defers the effects of selection change, so that the effects of multiple calls to
 3340    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3341    /// to selection history and the state of popovers based on selection position aren't
 3342    /// erroneously updated.
 3343    pub fn with_selection_effects_deferred<R>(
 3344        &mut self,
 3345        window: &mut Window,
 3346        cx: &mut Context<Self>,
 3347        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3348    ) -> R {
 3349        let already_deferred = self.defer_selection_effects;
 3350        self.defer_selection_effects = true;
 3351        let result = update(self, window, cx);
 3352        if !already_deferred {
 3353            self.defer_selection_effects = false;
 3354            if let Some(state) = self.deferred_selection_effects_state.take() {
 3355                self.apply_selection_effects(state, window, cx);
 3356            }
 3357        }
 3358        result
 3359    }
 3360
 3361    fn apply_selection_effects(
 3362        &mut self,
 3363        state: DeferredSelectionEffectsState,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366    ) {
 3367        if state.changed {
 3368            self.selection_history.push(state.history_entry);
 3369
 3370            if let Some(autoscroll) = state.effects.scroll {
 3371                self.request_autoscroll(autoscroll, cx);
 3372            }
 3373
 3374            let old_cursor_position = &state.old_cursor_position;
 3375
 3376            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3377
 3378            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3379                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3380            }
 3381        }
 3382    }
 3383
 3384    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3385    where
 3386        I: IntoIterator<Item = (Range<S>, T)>,
 3387        S: ToOffset,
 3388        T: Into<Arc<str>>,
 3389    {
 3390        if self.read_only(cx) {
 3391            return;
 3392        }
 3393
 3394        self.buffer
 3395            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3396    }
 3397
 3398    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3399    where
 3400        I: IntoIterator<Item = (Range<S>, T)>,
 3401        S: ToOffset,
 3402        T: Into<Arc<str>>,
 3403    {
 3404        if self.read_only(cx) {
 3405            return;
 3406        }
 3407
 3408        self.buffer.update(cx, |buffer, cx| {
 3409            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3410        });
 3411    }
 3412
 3413    pub fn edit_with_block_indent<I, S, T>(
 3414        &mut self,
 3415        edits: I,
 3416        original_indent_columns: Vec<Option<u32>>,
 3417        cx: &mut Context<Self>,
 3418    ) where
 3419        I: IntoIterator<Item = (Range<S>, T)>,
 3420        S: ToOffset,
 3421        T: Into<Arc<str>>,
 3422    {
 3423        if self.read_only(cx) {
 3424            return;
 3425        }
 3426
 3427        self.buffer.update(cx, |buffer, cx| {
 3428            buffer.edit(
 3429                edits,
 3430                Some(AutoindentMode::Block {
 3431                    original_indent_columns,
 3432                }),
 3433                cx,
 3434            )
 3435        });
 3436    }
 3437
 3438    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3439        self.hide_context_menu(window, cx);
 3440
 3441        match phase {
 3442            SelectPhase::Begin {
 3443                position,
 3444                add,
 3445                click_count,
 3446            } => self.begin_selection(position, add, click_count, window, cx),
 3447            SelectPhase::BeginColumnar {
 3448                position,
 3449                goal_column,
 3450                reset,
 3451                mode,
 3452            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3453            SelectPhase::Extend {
 3454                position,
 3455                click_count,
 3456            } => self.extend_selection(position, click_count, window, cx),
 3457            SelectPhase::Update {
 3458                position,
 3459                goal_column,
 3460                scroll_delta,
 3461            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3462            SelectPhase::End => self.end_selection(window, cx),
 3463        }
 3464    }
 3465
 3466    fn extend_selection(
 3467        &mut self,
 3468        position: DisplayPoint,
 3469        click_count: usize,
 3470        window: &mut Window,
 3471        cx: &mut Context<Self>,
 3472    ) {
 3473        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3474        let tail = self.selections.newest::<usize>(cx).tail();
 3475        self.begin_selection(position, false, click_count, window, cx);
 3476
 3477        let position = position.to_offset(&display_map, Bias::Left);
 3478        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3479
 3480        let mut pending_selection = self
 3481            .selections
 3482            .pending_anchor()
 3483            .expect("extend_selection not called with pending selection");
 3484        if position >= tail {
 3485            pending_selection.start = tail_anchor;
 3486        } else {
 3487            pending_selection.end = tail_anchor;
 3488            pending_selection.reversed = true;
 3489        }
 3490
 3491        let mut pending_mode = self.selections.pending_mode().unwrap();
 3492        match &mut pending_mode {
 3493            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3494            _ => {}
 3495        }
 3496
 3497        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3498            SelectionEffects::scroll(Autoscroll::fit())
 3499        } else {
 3500            SelectionEffects::no_scroll()
 3501        };
 3502
 3503        self.change_selections(effects, window, cx, |s| {
 3504            s.set_pending(pending_selection, pending_mode)
 3505        });
 3506    }
 3507
 3508    fn begin_selection(
 3509        &mut self,
 3510        position: DisplayPoint,
 3511        add: bool,
 3512        click_count: usize,
 3513        window: &mut Window,
 3514        cx: &mut Context<Self>,
 3515    ) {
 3516        if !self.focus_handle.is_focused(window) {
 3517            self.last_focused_descendant = None;
 3518            window.focus(&self.focus_handle);
 3519        }
 3520
 3521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3522        let buffer = &display_map.buffer_snapshot;
 3523        let position = display_map.clip_point(position, Bias::Left);
 3524
 3525        let start;
 3526        let end;
 3527        let mode;
 3528        let mut auto_scroll;
 3529        match click_count {
 3530            1 => {
 3531                start = buffer.anchor_before(position.to_point(&display_map));
 3532                end = start;
 3533                mode = SelectMode::Character;
 3534                auto_scroll = true;
 3535            }
 3536            2 => {
 3537                let position = display_map
 3538                    .clip_point(position, Bias::Left)
 3539                    .to_offset(&display_map, Bias::Left);
 3540                let (range, _) = buffer.surrounding_word(position, false);
 3541                start = buffer.anchor_before(range.start);
 3542                end = buffer.anchor_before(range.end);
 3543                mode = SelectMode::Word(start..end);
 3544                auto_scroll = true;
 3545            }
 3546            3 => {
 3547                let position = display_map
 3548                    .clip_point(position, Bias::Left)
 3549                    .to_point(&display_map);
 3550                let line_start = display_map.prev_line_boundary(position).0;
 3551                let next_line_start = buffer.clip_point(
 3552                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3553                    Bias::Left,
 3554                );
 3555                start = buffer.anchor_before(line_start);
 3556                end = buffer.anchor_before(next_line_start);
 3557                mode = SelectMode::Line(start..end);
 3558                auto_scroll = true;
 3559            }
 3560            _ => {
 3561                start = buffer.anchor_before(0);
 3562                end = buffer.anchor_before(buffer.len());
 3563                mode = SelectMode::All;
 3564                auto_scroll = false;
 3565            }
 3566        }
 3567        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3568
 3569        let point_to_delete: Option<usize> = {
 3570            let selected_points: Vec<Selection<Point>> =
 3571                self.selections.disjoint_in_range(start..end, cx);
 3572
 3573            if !add || click_count > 1 {
 3574                None
 3575            } else if !selected_points.is_empty() {
 3576                Some(selected_points[0].id)
 3577            } else {
 3578                let clicked_point_already_selected =
 3579                    self.selections.disjoint.iter().find(|selection| {
 3580                        selection.start.to_point(buffer) == start.to_point(buffer)
 3581                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3582                    });
 3583
 3584                clicked_point_already_selected.map(|selection| selection.id)
 3585            }
 3586        };
 3587
 3588        let selections_count = self.selections.count();
 3589        let effects = if auto_scroll {
 3590            SelectionEffects::default()
 3591        } else {
 3592            SelectionEffects::no_scroll()
 3593        };
 3594
 3595        self.change_selections(effects, window, cx, |s| {
 3596            if let Some(point_to_delete) = point_to_delete {
 3597                s.delete(point_to_delete);
 3598
 3599                if selections_count == 1 {
 3600                    s.set_pending_anchor_range(start..end, mode);
 3601                }
 3602            } else {
 3603                if !add {
 3604                    s.clear_disjoint();
 3605                }
 3606
 3607                s.set_pending_anchor_range(start..end, mode);
 3608            }
 3609        });
 3610    }
 3611
 3612    fn begin_columnar_selection(
 3613        &mut self,
 3614        position: DisplayPoint,
 3615        goal_column: u32,
 3616        reset: bool,
 3617        mode: ColumnarMode,
 3618        window: &mut Window,
 3619        cx: &mut Context<Self>,
 3620    ) {
 3621        if !self.focus_handle.is_focused(window) {
 3622            self.last_focused_descendant = None;
 3623            window.focus(&self.focus_handle);
 3624        }
 3625
 3626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3627
 3628        if reset {
 3629            let pointer_position = display_map
 3630                .buffer_snapshot
 3631                .anchor_before(position.to_point(&display_map));
 3632
 3633            self.change_selections(
 3634                SelectionEffects::scroll(Autoscroll::newest()),
 3635                window,
 3636                cx,
 3637                |s| {
 3638                    s.clear_disjoint();
 3639                    s.set_pending_anchor_range(
 3640                        pointer_position..pointer_position,
 3641                        SelectMode::Character,
 3642                    );
 3643                },
 3644            );
 3645        };
 3646
 3647        let tail = self.selections.newest::<Point>(cx).tail();
 3648        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3649        self.columnar_selection_state = match mode {
 3650            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3651                selection_tail: selection_anchor,
 3652                display_point: if reset {
 3653                    if position.column() != goal_column {
 3654                        Some(DisplayPoint::new(position.row(), goal_column))
 3655                    } else {
 3656                        None
 3657                    }
 3658                } else {
 3659                    None
 3660                },
 3661            }),
 3662            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3663                selection_tail: selection_anchor,
 3664            }),
 3665        };
 3666
 3667        if !reset {
 3668            self.select_columns(position, goal_column, &display_map, window, cx);
 3669        }
 3670    }
 3671
 3672    fn update_selection(
 3673        &mut self,
 3674        position: DisplayPoint,
 3675        goal_column: u32,
 3676        scroll_delta: gpui::Point<f32>,
 3677        window: &mut Window,
 3678        cx: &mut Context<Self>,
 3679    ) {
 3680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3681
 3682        if self.columnar_selection_state.is_some() {
 3683            self.select_columns(position, goal_column, &display_map, window, cx);
 3684        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3685            let buffer = &display_map.buffer_snapshot;
 3686            let head;
 3687            let tail;
 3688            let mode = self.selections.pending_mode().unwrap();
 3689            match &mode {
 3690                SelectMode::Character => {
 3691                    head = position.to_point(&display_map);
 3692                    tail = pending.tail().to_point(buffer);
 3693                }
 3694                SelectMode::Word(original_range) => {
 3695                    let offset = display_map
 3696                        .clip_point(position, Bias::Left)
 3697                        .to_offset(&display_map, Bias::Left);
 3698                    let original_range = original_range.to_offset(buffer);
 3699
 3700                    let head_offset = if buffer.is_inside_word(offset, false)
 3701                        || original_range.contains(&offset)
 3702                    {
 3703                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3704                        if word_range.start < original_range.start {
 3705                            word_range.start
 3706                        } else {
 3707                            word_range.end
 3708                        }
 3709                    } else {
 3710                        offset
 3711                    };
 3712
 3713                    head = head_offset.to_point(buffer);
 3714                    if head_offset <= original_range.start {
 3715                        tail = original_range.end.to_point(buffer);
 3716                    } else {
 3717                        tail = original_range.start.to_point(buffer);
 3718                    }
 3719                }
 3720                SelectMode::Line(original_range) => {
 3721                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3722
 3723                    let position = display_map
 3724                        .clip_point(position, Bias::Left)
 3725                        .to_point(&display_map);
 3726                    let line_start = display_map.prev_line_boundary(position).0;
 3727                    let next_line_start = buffer.clip_point(
 3728                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3729                        Bias::Left,
 3730                    );
 3731
 3732                    if line_start < original_range.start {
 3733                        head = line_start
 3734                    } else {
 3735                        head = next_line_start
 3736                    }
 3737
 3738                    if head <= original_range.start {
 3739                        tail = original_range.end;
 3740                    } else {
 3741                        tail = original_range.start;
 3742                    }
 3743                }
 3744                SelectMode::All => {
 3745                    return;
 3746                }
 3747            };
 3748
 3749            if head < tail {
 3750                pending.start = buffer.anchor_before(head);
 3751                pending.end = buffer.anchor_before(tail);
 3752                pending.reversed = true;
 3753            } else {
 3754                pending.start = buffer.anchor_before(tail);
 3755                pending.end = buffer.anchor_before(head);
 3756                pending.reversed = false;
 3757            }
 3758
 3759            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3760                s.set_pending(pending, mode);
 3761            });
 3762        } else {
 3763            log::error!("update_selection dispatched with no pending selection");
 3764            return;
 3765        }
 3766
 3767        self.apply_scroll_delta(scroll_delta, window, cx);
 3768        cx.notify();
 3769    }
 3770
 3771    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3772        self.columnar_selection_state.take();
 3773        if self.selections.pending_anchor().is_some() {
 3774            let selections = self.selections.all::<usize>(cx);
 3775            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3776                s.select(selections);
 3777                s.clear_pending();
 3778            });
 3779        }
 3780    }
 3781
 3782    fn select_columns(
 3783        &mut self,
 3784        head: DisplayPoint,
 3785        goal_column: u32,
 3786        display_map: &DisplaySnapshot,
 3787        window: &mut Window,
 3788        cx: &mut Context<Self>,
 3789    ) {
 3790        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3791            return;
 3792        };
 3793
 3794        let tail = match columnar_state {
 3795            ColumnarSelectionState::FromMouse {
 3796                selection_tail,
 3797                display_point,
 3798            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3799            ColumnarSelectionState::FromSelection { selection_tail } => {
 3800                selection_tail.to_display_point(display_map)
 3801            }
 3802        };
 3803
 3804        let start_row = cmp::min(tail.row(), head.row());
 3805        let end_row = cmp::max(tail.row(), head.row());
 3806        let start_column = cmp::min(tail.column(), goal_column);
 3807        let end_column = cmp::max(tail.column(), goal_column);
 3808        let reversed = start_column < tail.column();
 3809
 3810        let selection_ranges = (start_row.0..=end_row.0)
 3811            .map(DisplayRow)
 3812            .filter_map(|row| {
 3813                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3814                    || start_column <= display_map.line_len(row))
 3815                    && !display_map.is_block_line(row)
 3816                {
 3817                    let start = display_map
 3818                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3819                        .to_point(display_map);
 3820                    let end = display_map
 3821                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3822                        .to_point(display_map);
 3823                    if reversed {
 3824                        Some(end..start)
 3825                    } else {
 3826                        Some(start..end)
 3827                    }
 3828                } else {
 3829                    None
 3830                }
 3831            })
 3832            .collect::<Vec<_>>();
 3833
 3834        let ranges = match columnar_state {
 3835            ColumnarSelectionState::FromMouse { .. } => {
 3836                let mut non_empty_ranges = selection_ranges
 3837                    .iter()
 3838                    .filter(|selection_range| selection_range.start != selection_range.end)
 3839                    .peekable();
 3840                if non_empty_ranges.peek().is_some() {
 3841                    non_empty_ranges.cloned().collect()
 3842                } else {
 3843                    selection_ranges
 3844                }
 3845            }
 3846            _ => selection_ranges,
 3847        };
 3848
 3849        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3850            s.select_ranges(ranges);
 3851        });
 3852        cx.notify();
 3853    }
 3854
 3855    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3856        self.selections
 3857            .all_adjusted(cx)
 3858            .iter()
 3859            .any(|selection| !selection.is_empty())
 3860    }
 3861
 3862    pub fn has_pending_nonempty_selection(&self) -> bool {
 3863        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3864            Some(Selection { start, end, .. }) => start != end,
 3865            None => false,
 3866        };
 3867
 3868        pending_nonempty_selection
 3869            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3870    }
 3871
 3872    pub fn has_pending_selection(&self) -> bool {
 3873        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3874    }
 3875
 3876    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3877        self.selection_mark_mode = false;
 3878        self.selection_drag_state = SelectionDragState::None;
 3879
 3880        if self.clear_expanded_diff_hunks(cx) {
 3881            cx.notify();
 3882            return;
 3883        }
 3884        if self.dismiss_menus_and_popups(true, window, cx) {
 3885            return;
 3886        }
 3887
 3888        if self.mode.is_full()
 3889            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3890        {
 3891            return;
 3892        }
 3893
 3894        cx.propagate();
 3895    }
 3896
 3897    pub fn dismiss_menus_and_popups(
 3898        &mut self,
 3899        is_user_requested: bool,
 3900        window: &mut Window,
 3901        cx: &mut Context<Self>,
 3902    ) -> bool {
 3903        if self.take_rename(false, window, cx).is_some() {
 3904            return true;
 3905        }
 3906
 3907        if hide_hover(self, cx) {
 3908            return true;
 3909        }
 3910
 3911        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3912            return true;
 3913        }
 3914
 3915        if self.hide_context_menu(window, cx).is_some() {
 3916            return true;
 3917        }
 3918
 3919        if self.mouse_context_menu.take().is_some() {
 3920            return true;
 3921        }
 3922
 3923        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3924            return true;
 3925        }
 3926
 3927        if self.snippet_stack.pop().is_some() {
 3928            return true;
 3929        }
 3930
 3931        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3932            self.dismiss_diagnostics(cx);
 3933            return true;
 3934        }
 3935
 3936        false
 3937    }
 3938
 3939    fn linked_editing_ranges_for(
 3940        &self,
 3941        selection: Range<text::Anchor>,
 3942        cx: &App,
 3943    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3944        if self.linked_edit_ranges.is_empty() {
 3945            return None;
 3946        }
 3947        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3948            selection.end.buffer_id.and_then(|end_buffer_id| {
 3949                if selection.start.buffer_id != Some(end_buffer_id) {
 3950                    return None;
 3951                }
 3952                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3953                let snapshot = buffer.read(cx).snapshot();
 3954                self.linked_edit_ranges
 3955                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3956                    .map(|ranges| (ranges, snapshot, buffer))
 3957            })?;
 3958        use text::ToOffset as TO;
 3959        // find offset from the start of current range to current cursor position
 3960        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3961
 3962        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3963        let start_difference = start_offset - start_byte_offset;
 3964        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3965        let end_difference = end_offset - start_byte_offset;
 3966        // Current range has associated linked ranges.
 3967        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3968        for range in linked_ranges.iter() {
 3969            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3970            let end_offset = start_offset + end_difference;
 3971            let start_offset = start_offset + start_difference;
 3972            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3973                continue;
 3974            }
 3975            if self.selections.disjoint_anchor_ranges().any(|s| {
 3976                if s.start.buffer_id != selection.start.buffer_id
 3977                    || s.end.buffer_id != selection.end.buffer_id
 3978                {
 3979                    return false;
 3980                }
 3981                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3982                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3983            }) {
 3984                continue;
 3985            }
 3986            let start = buffer_snapshot.anchor_after(start_offset);
 3987            let end = buffer_snapshot.anchor_after(end_offset);
 3988            linked_edits
 3989                .entry(buffer.clone())
 3990                .or_default()
 3991                .push(start..end);
 3992        }
 3993        Some(linked_edits)
 3994    }
 3995
 3996    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3997        let text: Arc<str> = text.into();
 3998
 3999        if self.read_only(cx) {
 4000            return;
 4001        }
 4002
 4003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4004
 4005        let selections = self.selections.all_adjusted(cx);
 4006        let mut bracket_inserted = false;
 4007        let mut edits = Vec::new();
 4008        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4009        let mut new_selections = Vec::with_capacity(selections.len());
 4010        let mut new_autoclose_regions = Vec::new();
 4011        let snapshot = self.buffer.read(cx).read(cx);
 4012        let mut clear_linked_edit_ranges = false;
 4013
 4014        for (selection, autoclose_region) in
 4015            self.selections_with_autoclose_regions(selections, &snapshot)
 4016        {
 4017            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4018                // Determine if the inserted text matches the opening or closing
 4019                // bracket of any of this language's bracket pairs.
 4020                let mut bracket_pair = None;
 4021                let mut is_bracket_pair_start = false;
 4022                let mut is_bracket_pair_end = false;
 4023                if !text.is_empty() {
 4024                    let mut bracket_pair_matching_end = None;
 4025                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4026                    //  and they are removing the character that triggered IME popup.
 4027                    for (pair, enabled) in scope.brackets() {
 4028                        if !pair.close && !pair.surround {
 4029                            continue;
 4030                        }
 4031
 4032                        if enabled && pair.start.ends_with(text.as_ref()) {
 4033                            let prefix_len = pair.start.len() - text.len();
 4034                            let preceding_text_matches_prefix = prefix_len == 0
 4035                                || (selection.start.column >= (prefix_len as u32)
 4036                                    && snapshot.contains_str_at(
 4037                                        Point::new(
 4038                                            selection.start.row,
 4039                                            selection.start.column - (prefix_len as u32),
 4040                                        ),
 4041                                        &pair.start[..prefix_len],
 4042                                    ));
 4043                            if preceding_text_matches_prefix {
 4044                                bracket_pair = Some(pair.clone());
 4045                                is_bracket_pair_start = true;
 4046                                break;
 4047                            }
 4048                        }
 4049                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4050                        {
 4051                            // take first bracket pair matching end, but don't break in case a later bracket
 4052                            // pair matches start
 4053                            bracket_pair_matching_end = Some(pair.clone());
 4054                        }
 4055                    }
 4056                    if let Some(end) = bracket_pair_matching_end
 4057                        && bracket_pair.is_none()
 4058                    {
 4059                        bracket_pair = Some(end);
 4060                        is_bracket_pair_end = true;
 4061                    }
 4062                }
 4063
 4064                if let Some(bracket_pair) = bracket_pair {
 4065                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4066                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4067                    let auto_surround =
 4068                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4069                    if selection.is_empty() {
 4070                        if is_bracket_pair_start {
 4071                            // If the inserted text is a suffix of an opening bracket and the
 4072                            // selection is preceded by the rest of the opening bracket, then
 4073                            // insert the closing bracket.
 4074                            let following_text_allows_autoclose = snapshot
 4075                                .chars_at(selection.start)
 4076                                .next()
 4077                                .is_none_or(|c| scope.should_autoclose_before(c));
 4078
 4079                            let preceding_text_allows_autoclose = selection.start.column == 0
 4080                                || snapshot
 4081                                    .reversed_chars_at(selection.start)
 4082                                    .next()
 4083                                    .is_none_or(|c| {
 4084                                        bracket_pair.start != bracket_pair.end
 4085                                            || !snapshot
 4086                                                .char_classifier_at(selection.start)
 4087                                                .is_word(c)
 4088                                    });
 4089
 4090                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4091                                && bracket_pair.start.len() == 1
 4092                            {
 4093                                let target = bracket_pair.start.chars().next().unwrap();
 4094                                let current_line_count = snapshot
 4095                                    .reversed_chars_at(selection.start)
 4096                                    .take_while(|&c| c != '\n')
 4097                                    .filter(|&c| c == target)
 4098                                    .count();
 4099                                current_line_count % 2 == 1
 4100                            } else {
 4101                                false
 4102                            };
 4103
 4104                            if autoclose
 4105                                && bracket_pair.close
 4106                                && following_text_allows_autoclose
 4107                                && preceding_text_allows_autoclose
 4108                                && !is_closing_quote
 4109                            {
 4110                                let anchor = snapshot.anchor_before(selection.end);
 4111                                new_selections.push((selection.map(|_| anchor), text.len()));
 4112                                new_autoclose_regions.push((
 4113                                    anchor,
 4114                                    text.len(),
 4115                                    selection.id,
 4116                                    bracket_pair.clone(),
 4117                                ));
 4118                                edits.push((
 4119                                    selection.range(),
 4120                                    format!("{}{}", text, bracket_pair.end).into(),
 4121                                ));
 4122                                bracket_inserted = true;
 4123                                continue;
 4124                            }
 4125                        }
 4126
 4127                        if let Some(region) = autoclose_region {
 4128                            // If the selection is followed by an auto-inserted closing bracket,
 4129                            // then don't insert that closing bracket again; just move the selection
 4130                            // past the closing bracket.
 4131                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4132                                && text.as_ref() == region.pair.end.as_str()
 4133                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4134                            if should_skip {
 4135                                let anchor = snapshot.anchor_after(selection.end);
 4136                                new_selections
 4137                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4138                                continue;
 4139                            }
 4140                        }
 4141
 4142                        let always_treat_brackets_as_autoclosed = snapshot
 4143                            .language_settings_at(selection.start, cx)
 4144                            .always_treat_brackets_as_autoclosed;
 4145                        if always_treat_brackets_as_autoclosed
 4146                            && is_bracket_pair_end
 4147                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4148                        {
 4149                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4150                            // and the inserted text is a closing bracket and the selection is followed
 4151                            // by the closing bracket then move the selection past the closing bracket.
 4152                            let anchor = snapshot.anchor_after(selection.end);
 4153                            new_selections.push((selection.map(|_| anchor), text.len()));
 4154                            continue;
 4155                        }
 4156                    }
 4157                    // If an opening bracket is 1 character long and is typed while
 4158                    // text is selected, then surround that text with the bracket pair.
 4159                    else if auto_surround
 4160                        && bracket_pair.surround
 4161                        && is_bracket_pair_start
 4162                        && bracket_pair.start.chars().count() == 1
 4163                    {
 4164                        edits.push((selection.start..selection.start, text.clone()));
 4165                        edits.push((
 4166                            selection.end..selection.end,
 4167                            bracket_pair.end.as_str().into(),
 4168                        ));
 4169                        bracket_inserted = true;
 4170                        new_selections.push((
 4171                            Selection {
 4172                                id: selection.id,
 4173                                start: snapshot.anchor_after(selection.start),
 4174                                end: snapshot.anchor_before(selection.end),
 4175                                reversed: selection.reversed,
 4176                                goal: selection.goal,
 4177                            },
 4178                            0,
 4179                        ));
 4180                        continue;
 4181                    }
 4182                }
 4183            }
 4184
 4185            if self.auto_replace_emoji_shortcode
 4186                && selection.is_empty()
 4187                && text.as_ref().ends_with(':')
 4188                && let Some(possible_emoji_short_code) =
 4189                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4190                && !possible_emoji_short_code.is_empty()
 4191                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4192            {
 4193                let emoji_shortcode_start = Point::new(
 4194                    selection.start.row,
 4195                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4196                );
 4197
 4198                // Remove shortcode from buffer
 4199                edits.push((
 4200                    emoji_shortcode_start..selection.start,
 4201                    "".to_string().into(),
 4202                ));
 4203                new_selections.push((
 4204                    Selection {
 4205                        id: selection.id,
 4206                        start: snapshot.anchor_after(emoji_shortcode_start),
 4207                        end: snapshot.anchor_before(selection.start),
 4208                        reversed: selection.reversed,
 4209                        goal: selection.goal,
 4210                    },
 4211                    0,
 4212                ));
 4213
 4214                // Insert emoji
 4215                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4216                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4217                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4218
 4219                continue;
 4220            }
 4221
 4222            // If not handling any auto-close operation, then just replace the selected
 4223            // text with the given input and move the selection to the end of the
 4224            // newly inserted text.
 4225            let anchor = snapshot.anchor_after(selection.end);
 4226            if !self.linked_edit_ranges.is_empty() {
 4227                let start_anchor = snapshot.anchor_before(selection.start);
 4228
 4229                let is_word_char = text.chars().next().is_none_or(|char| {
 4230                    let classifier = snapshot
 4231                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4232                        .ignore_punctuation(true);
 4233                    classifier.is_word(char)
 4234                });
 4235
 4236                if is_word_char {
 4237                    if let Some(ranges) = self
 4238                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4239                    {
 4240                        for (buffer, edits) in ranges {
 4241                            linked_edits
 4242                                .entry(buffer.clone())
 4243                                .or_default()
 4244                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4245                        }
 4246                    }
 4247                } else {
 4248                    clear_linked_edit_ranges = true;
 4249                }
 4250            }
 4251
 4252            new_selections.push((selection.map(|_| anchor), 0));
 4253            edits.push((selection.start..selection.end, text.clone()));
 4254        }
 4255
 4256        drop(snapshot);
 4257
 4258        self.transact(window, cx, |this, window, cx| {
 4259            if clear_linked_edit_ranges {
 4260                this.linked_edit_ranges.clear();
 4261            }
 4262            let initial_buffer_versions =
 4263                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4264
 4265            this.buffer.update(cx, |buffer, cx| {
 4266                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4267            });
 4268            for (buffer, edits) in linked_edits {
 4269                buffer.update(cx, |buffer, cx| {
 4270                    let snapshot = buffer.snapshot();
 4271                    let edits = edits
 4272                        .into_iter()
 4273                        .map(|(range, text)| {
 4274                            use text::ToPoint as TP;
 4275                            let end_point = TP::to_point(&range.end, &snapshot);
 4276                            let start_point = TP::to_point(&range.start, &snapshot);
 4277                            (start_point..end_point, text)
 4278                        })
 4279                        .sorted_by_key(|(range, _)| range.start);
 4280                    buffer.edit(edits, None, cx);
 4281                })
 4282            }
 4283            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4284            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4285            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4286            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4287                .zip(new_selection_deltas)
 4288                .map(|(selection, delta)| Selection {
 4289                    id: selection.id,
 4290                    start: selection.start + delta,
 4291                    end: selection.end + delta,
 4292                    reversed: selection.reversed,
 4293                    goal: SelectionGoal::None,
 4294                })
 4295                .collect::<Vec<_>>();
 4296
 4297            let mut i = 0;
 4298            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4299                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4300                let start = map.buffer_snapshot.anchor_before(position);
 4301                let end = map.buffer_snapshot.anchor_after(position);
 4302                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4303                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4304                        Ordering::Less => i += 1,
 4305                        Ordering::Greater => break,
 4306                        Ordering::Equal => {
 4307                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4308                                Ordering::Less => i += 1,
 4309                                Ordering::Equal => break,
 4310                                Ordering::Greater => break,
 4311                            }
 4312                        }
 4313                    }
 4314                }
 4315                this.autoclose_regions.insert(
 4316                    i,
 4317                    AutocloseRegion {
 4318                        selection_id,
 4319                        range: start..end,
 4320                        pair,
 4321                    },
 4322                );
 4323            }
 4324
 4325            let had_active_edit_prediction = this.has_active_edit_prediction();
 4326            this.change_selections(
 4327                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4328                window,
 4329                cx,
 4330                |s| s.select(new_selections),
 4331            );
 4332
 4333            if !bracket_inserted
 4334                && let Some(on_type_format_task) =
 4335                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4336            {
 4337                on_type_format_task.detach_and_log_err(cx);
 4338            }
 4339
 4340            let editor_settings = EditorSettings::get_global(cx);
 4341            if bracket_inserted
 4342                && (editor_settings.auto_signature_help
 4343                    || editor_settings.show_signature_help_after_edits)
 4344            {
 4345                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4346            }
 4347
 4348            let trigger_in_words =
 4349                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4350            if this.hard_wrap.is_some() {
 4351                let latest: Range<Point> = this.selections.newest(cx).range();
 4352                if latest.is_empty()
 4353                    && this
 4354                        .buffer()
 4355                        .read(cx)
 4356                        .snapshot(cx)
 4357                        .line_len(MultiBufferRow(latest.start.row))
 4358                        == latest.start.column
 4359                {
 4360                    this.rewrap_impl(
 4361                        RewrapOptions {
 4362                            override_language_settings: true,
 4363                            preserve_existing_whitespace: true,
 4364                        },
 4365                        cx,
 4366                    )
 4367                }
 4368            }
 4369            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4370            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4371            this.refresh_edit_prediction(true, false, window, cx);
 4372            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4373        });
 4374    }
 4375
 4376    fn find_possible_emoji_shortcode_at_position(
 4377        snapshot: &MultiBufferSnapshot,
 4378        position: Point,
 4379    ) -> Option<String> {
 4380        let mut chars = Vec::new();
 4381        let mut found_colon = false;
 4382        for char in snapshot.reversed_chars_at(position).take(100) {
 4383            // Found a possible emoji shortcode in the middle of the buffer
 4384            if found_colon {
 4385                if char.is_whitespace() {
 4386                    chars.reverse();
 4387                    return Some(chars.iter().collect());
 4388                }
 4389                // If the previous character is not a whitespace, we are in the middle of a word
 4390                // and we only want to complete the shortcode if the word is made up of other emojis
 4391                let mut containing_word = String::new();
 4392                for ch in snapshot
 4393                    .reversed_chars_at(position)
 4394                    .skip(chars.len() + 1)
 4395                    .take(100)
 4396                {
 4397                    if ch.is_whitespace() {
 4398                        break;
 4399                    }
 4400                    containing_word.push(ch);
 4401                }
 4402                let containing_word = containing_word.chars().rev().collect::<String>();
 4403                if util::word_consists_of_emojis(containing_word.as_str()) {
 4404                    chars.reverse();
 4405                    return Some(chars.iter().collect());
 4406                }
 4407            }
 4408
 4409            if char.is_whitespace() || !char.is_ascii() {
 4410                return None;
 4411            }
 4412            if char == ':' {
 4413                found_colon = true;
 4414            } else {
 4415                chars.push(char);
 4416            }
 4417        }
 4418        // Found a possible emoji shortcode at the beginning of the buffer
 4419        chars.reverse();
 4420        Some(chars.iter().collect())
 4421    }
 4422
 4423    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4425        self.transact(window, cx, |this, window, cx| {
 4426            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4427                let selections = this.selections.all::<usize>(cx);
 4428                let multi_buffer = this.buffer.read(cx);
 4429                let buffer = multi_buffer.snapshot(cx);
 4430                selections
 4431                    .iter()
 4432                    .map(|selection| {
 4433                        let start_point = selection.start.to_point(&buffer);
 4434                        let mut existing_indent =
 4435                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4436                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4437                        let start = selection.start;
 4438                        let end = selection.end;
 4439                        let selection_is_empty = start == end;
 4440                        let language_scope = buffer.language_scope_at(start);
 4441                        let (
 4442                            comment_delimiter,
 4443                            doc_delimiter,
 4444                            insert_extra_newline,
 4445                            indent_on_newline,
 4446                            indent_on_extra_newline,
 4447                        ) = if let Some(language) = &language_scope {
 4448                            let mut insert_extra_newline =
 4449                                insert_extra_newline_brackets(&buffer, start..end, language)
 4450                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4451
 4452                            // Comment extension on newline is allowed only for cursor selections
 4453                            let comment_delimiter = maybe!({
 4454                                if !selection_is_empty {
 4455                                    return None;
 4456                                }
 4457
 4458                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4459                                    return None;
 4460                                }
 4461
 4462                                let delimiters = language.line_comment_prefixes();
 4463                                let max_len_of_delimiter =
 4464                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4465                                let (snapshot, range) =
 4466                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4467
 4468                                let num_of_whitespaces = snapshot
 4469                                    .chars_for_range(range.clone())
 4470                                    .take_while(|c| c.is_whitespace())
 4471                                    .count();
 4472                                let comment_candidate = snapshot
 4473                                    .chars_for_range(range.clone())
 4474                                    .skip(num_of_whitespaces)
 4475                                    .take(max_len_of_delimiter)
 4476                                    .collect::<String>();
 4477                                let (delimiter, trimmed_len) = delimiters
 4478                                    .iter()
 4479                                    .filter_map(|delimiter| {
 4480                                        let prefix = delimiter.trim_end();
 4481                                        if comment_candidate.starts_with(prefix) {
 4482                                            Some((delimiter, prefix.len()))
 4483                                        } else {
 4484                                            None
 4485                                        }
 4486                                    })
 4487                                    .max_by_key(|(_, len)| *len)?;
 4488
 4489                                if let Some(BlockCommentConfig {
 4490                                    start: block_start, ..
 4491                                }) = language.block_comment()
 4492                                {
 4493                                    let block_start_trimmed = block_start.trim_end();
 4494                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4495                                        let line_content = snapshot
 4496                                            .chars_for_range(range)
 4497                                            .skip(num_of_whitespaces)
 4498                                            .take(block_start_trimmed.len())
 4499                                            .collect::<String>();
 4500
 4501                                        if line_content.starts_with(block_start_trimmed) {
 4502                                            return None;
 4503                                        }
 4504                                    }
 4505                                }
 4506
 4507                                let cursor_is_placed_after_comment_marker =
 4508                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4509                                if cursor_is_placed_after_comment_marker {
 4510                                    Some(delimiter.clone())
 4511                                } else {
 4512                                    None
 4513                                }
 4514                            });
 4515
 4516                            let mut indent_on_newline = IndentSize::spaces(0);
 4517                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4518
 4519                            let doc_delimiter = maybe!({
 4520                                if !selection_is_empty {
 4521                                    return None;
 4522                                }
 4523
 4524                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4525                                    return None;
 4526                                }
 4527
 4528                                let BlockCommentConfig {
 4529                                    start: start_tag,
 4530                                    end: end_tag,
 4531                                    prefix: delimiter,
 4532                                    tab_size: len,
 4533                                } = language.documentation_comment()?;
 4534                                let is_within_block_comment = buffer
 4535                                    .language_scope_at(start_point)
 4536                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4537                                if !is_within_block_comment {
 4538                                    return None;
 4539                                }
 4540
 4541                                let (snapshot, range) =
 4542                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4543
 4544                                let num_of_whitespaces = snapshot
 4545                                    .chars_for_range(range.clone())
 4546                                    .take_while(|c| c.is_whitespace())
 4547                                    .count();
 4548
 4549                                // 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.
 4550                                let column = start_point.column;
 4551                                let cursor_is_after_start_tag = {
 4552                                    let start_tag_len = start_tag.len();
 4553                                    let start_tag_line = snapshot
 4554                                        .chars_for_range(range.clone())
 4555                                        .skip(num_of_whitespaces)
 4556                                        .take(start_tag_len)
 4557                                        .collect::<String>();
 4558                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4559                                        num_of_whitespaces + start_tag_len <= column as usize
 4560                                    } else {
 4561                                        false
 4562                                    }
 4563                                };
 4564
 4565                                let cursor_is_after_delimiter = {
 4566                                    let delimiter_trim = delimiter.trim_end();
 4567                                    let delimiter_line = snapshot
 4568                                        .chars_for_range(range.clone())
 4569                                        .skip(num_of_whitespaces)
 4570                                        .take(delimiter_trim.len())
 4571                                        .collect::<String>();
 4572                                    if delimiter_line.starts_with(delimiter_trim) {
 4573                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4574                                    } else {
 4575                                        false
 4576                                    }
 4577                                };
 4578
 4579                                let cursor_is_before_end_tag_if_exists = {
 4580                                    let mut char_position = 0u32;
 4581                                    let mut end_tag_offset = None;
 4582
 4583                                    'outer: for chunk in snapshot.text_for_range(range) {
 4584                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4585                                            let chars_before_match =
 4586                                                chunk[..byte_pos].chars().count() as u32;
 4587                                            end_tag_offset =
 4588                                                Some(char_position + chars_before_match);
 4589                                            break 'outer;
 4590                                        }
 4591                                        char_position += chunk.chars().count() as u32;
 4592                                    }
 4593
 4594                                    if let Some(end_tag_offset) = end_tag_offset {
 4595                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4596                                        if cursor_is_after_start_tag {
 4597                                            if cursor_is_before_end_tag {
 4598                                                insert_extra_newline = true;
 4599                                            }
 4600                                            let cursor_is_at_start_of_end_tag =
 4601                                                column == end_tag_offset;
 4602                                            if cursor_is_at_start_of_end_tag {
 4603                                                indent_on_extra_newline.len = *len;
 4604                                            }
 4605                                        }
 4606                                        cursor_is_before_end_tag
 4607                                    } else {
 4608                                        true
 4609                                    }
 4610                                };
 4611
 4612                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4613                                    && cursor_is_before_end_tag_if_exists
 4614                                {
 4615                                    if cursor_is_after_start_tag {
 4616                                        indent_on_newline.len = *len;
 4617                                    }
 4618                                    Some(delimiter.clone())
 4619                                } else {
 4620                                    None
 4621                                }
 4622                            });
 4623
 4624                            (
 4625                                comment_delimiter,
 4626                                doc_delimiter,
 4627                                insert_extra_newline,
 4628                                indent_on_newline,
 4629                                indent_on_extra_newline,
 4630                            )
 4631                        } else {
 4632                            (
 4633                                None,
 4634                                None,
 4635                                false,
 4636                                IndentSize::default(),
 4637                                IndentSize::default(),
 4638                            )
 4639                        };
 4640
 4641                        let prevent_auto_indent = doc_delimiter.is_some();
 4642                        let delimiter = comment_delimiter.or(doc_delimiter);
 4643
 4644                        let capacity_for_delimiter =
 4645                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4646                        let mut new_text = String::with_capacity(
 4647                            1 + capacity_for_delimiter
 4648                                + existing_indent.len as usize
 4649                                + indent_on_newline.len as usize
 4650                                + indent_on_extra_newline.len as usize,
 4651                        );
 4652                        new_text.push('\n');
 4653                        new_text.extend(existing_indent.chars());
 4654                        new_text.extend(indent_on_newline.chars());
 4655
 4656                        if let Some(delimiter) = &delimiter {
 4657                            new_text.push_str(delimiter);
 4658                        }
 4659
 4660                        if insert_extra_newline {
 4661                            new_text.push('\n');
 4662                            new_text.extend(existing_indent.chars());
 4663                            new_text.extend(indent_on_extra_newline.chars());
 4664                        }
 4665
 4666                        let anchor = buffer.anchor_after(end);
 4667                        let new_selection = selection.map(|_| anchor);
 4668                        (
 4669                            ((start..end, new_text), prevent_auto_indent),
 4670                            (insert_extra_newline, new_selection),
 4671                        )
 4672                    })
 4673                    .unzip()
 4674            };
 4675
 4676            let mut auto_indent_edits = Vec::new();
 4677            let mut edits = Vec::new();
 4678            for (edit, prevent_auto_indent) in edits_with_flags {
 4679                if prevent_auto_indent {
 4680                    edits.push(edit);
 4681                } else {
 4682                    auto_indent_edits.push(edit);
 4683                }
 4684            }
 4685            if !edits.is_empty() {
 4686                this.edit(edits, cx);
 4687            }
 4688            if !auto_indent_edits.is_empty() {
 4689                this.edit_with_autoindent(auto_indent_edits, cx);
 4690            }
 4691
 4692            let buffer = this.buffer.read(cx).snapshot(cx);
 4693            let new_selections = selection_info
 4694                .into_iter()
 4695                .map(|(extra_newline_inserted, new_selection)| {
 4696                    let mut cursor = new_selection.end.to_point(&buffer);
 4697                    if extra_newline_inserted {
 4698                        cursor.row -= 1;
 4699                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4700                    }
 4701                    new_selection.map(|_| cursor)
 4702                })
 4703                .collect();
 4704
 4705            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4706            this.refresh_edit_prediction(true, false, window, cx);
 4707        });
 4708    }
 4709
 4710    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4712
 4713        let buffer = self.buffer.read(cx);
 4714        let snapshot = buffer.snapshot(cx);
 4715
 4716        let mut edits = Vec::new();
 4717        let mut rows = Vec::new();
 4718
 4719        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4720            let cursor = selection.head();
 4721            let row = cursor.row;
 4722
 4723            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4724
 4725            let newline = "\n".to_string();
 4726            edits.push((start_of_line..start_of_line, newline));
 4727
 4728            rows.push(row + rows_inserted as u32);
 4729        }
 4730
 4731        self.transact(window, cx, |editor, window, cx| {
 4732            editor.edit(edits, cx);
 4733
 4734            editor.change_selections(Default::default(), window, cx, |s| {
 4735                let mut index = 0;
 4736                s.move_cursors_with(|map, _, _| {
 4737                    let row = rows[index];
 4738                    index += 1;
 4739
 4740                    let point = Point::new(row, 0);
 4741                    let boundary = map.next_line_boundary(point).1;
 4742                    let clipped = map.clip_point(boundary, Bias::Left);
 4743
 4744                    (clipped, SelectionGoal::None)
 4745                });
 4746            });
 4747
 4748            let mut indent_edits = Vec::new();
 4749            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4750            for row in rows {
 4751                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4752                for (row, indent) in indents {
 4753                    if indent.len == 0 {
 4754                        continue;
 4755                    }
 4756
 4757                    let text = match indent.kind {
 4758                        IndentKind::Space => " ".repeat(indent.len as usize),
 4759                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4760                    };
 4761                    let point = Point::new(row.0, 0);
 4762                    indent_edits.push((point..point, text));
 4763                }
 4764            }
 4765            editor.edit(indent_edits, cx);
 4766        });
 4767    }
 4768
 4769    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4771
 4772        let buffer = self.buffer.read(cx);
 4773        let snapshot = buffer.snapshot(cx);
 4774
 4775        let mut edits = Vec::new();
 4776        let mut rows = Vec::new();
 4777        let mut rows_inserted = 0;
 4778
 4779        for selection in self.selections.all_adjusted(cx) {
 4780            let cursor = selection.head();
 4781            let row = cursor.row;
 4782
 4783            let point = Point::new(row + 1, 0);
 4784            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4785
 4786            let newline = "\n".to_string();
 4787            edits.push((start_of_line..start_of_line, newline));
 4788
 4789            rows_inserted += 1;
 4790            rows.push(row + rows_inserted);
 4791        }
 4792
 4793        self.transact(window, cx, |editor, window, cx| {
 4794            editor.edit(edits, cx);
 4795
 4796            editor.change_selections(Default::default(), window, cx, |s| {
 4797                let mut index = 0;
 4798                s.move_cursors_with(|map, _, _| {
 4799                    let row = rows[index];
 4800                    index += 1;
 4801
 4802                    let point = Point::new(row, 0);
 4803                    let boundary = map.next_line_boundary(point).1;
 4804                    let clipped = map.clip_point(boundary, Bias::Left);
 4805
 4806                    (clipped, SelectionGoal::None)
 4807                });
 4808            });
 4809
 4810            let mut indent_edits = Vec::new();
 4811            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4812            for row in rows {
 4813                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4814                for (row, indent) in indents {
 4815                    if indent.len == 0 {
 4816                        continue;
 4817                    }
 4818
 4819                    let text = match indent.kind {
 4820                        IndentKind::Space => " ".repeat(indent.len as usize),
 4821                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4822                    };
 4823                    let point = Point::new(row.0, 0);
 4824                    indent_edits.push((point..point, text));
 4825                }
 4826            }
 4827            editor.edit(indent_edits, cx);
 4828        });
 4829    }
 4830
 4831    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4832        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4833            original_indent_columns: Vec::new(),
 4834        });
 4835        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4836    }
 4837
 4838    fn insert_with_autoindent_mode(
 4839        &mut self,
 4840        text: &str,
 4841        autoindent_mode: Option<AutoindentMode>,
 4842        window: &mut Window,
 4843        cx: &mut Context<Self>,
 4844    ) {
 4845        if self.read_only(cx) {
 4846            return;
 4847        }
 4848
 4849        let text: Arc<str> = text.into();
 4850        self.transact(window, cx, |this, window, cx| {
 4851            let old_selections = this.selections.all_adjusted(cx);
 4852            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4853                let anchors = {
 4854                    let snapshot = buffer.read(cx);
 4855                    old_selections
 4856                        .iter()
 4857                        .map(|s| {
 4858                            let anchor = snapshot.anchor_after(s.head());
 4859                            s.map(|_| anchor)
 4860                        })
 4861                        .collect::<Vec<_>>()
 4862                };
 4863                buffer.edit(
 4864                    old_selections
 4865                        .iter()
 4866                        .map(|s| (s.start..s.end, text.clone())),
 4867                    autoindent_mode,
 4868                    cx,
 4869                );
 4870                anchors
 4871            });
 4872
 4873            this.change_selections(Default::default(), window, cx, |s| {
 4874                s.select_anchors(selection_anchors);
 4875            });
 4876
 4877            cx.notify();
 4878        });
 4879    }
 4880
 4881    fn trigger_completion_on_input(
 4882        &mut self,
 4883        text: &str,
 4884        trigger_in_words: bool,
 4885        window: &mut Window,
 4886        cx: &mut Context<Self>,
 4887    ) {
 4888        let completions_source = self
 4889            .context_menu
 4890            .borrow()
 4891            .as_ref()
 4892            .and_then(|menu| match menu {
 4893                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4894                CodeContextMenu::CodeActions(_) => None,
 4895            });
 4896
 4897        match completions_source {
 4898            Some(CompletionsMenuSource::Words) => {
 4899                self.show_word_completions(&ShowWordCompletions, window, cx)
 4900            }
 4901            Some(CompletionsMenuSource::Normal)
 4902            | Some(CompletionsMenuSource::SnippetChoices)
 4903            | None
 4904                if self.is_completion_trigger(
 4905                    text,
 4906                    trigger_in_words,
 4907                    completions_source.is_some(),
 4908                    cx,
 4909                ) =>
 4910            {
 4911                self.show_completions(
 4912                    &ShowCompletions {
 4913                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4914                    },
 4915                    window,
 4916                    cx,
 4917                )
 4918            }
 4919            _ => {
 4920                self.hide_context_menu(window, cx);
 4921            }
 4922        }
 4923    }
 4924
 4925    fn is_completion_trigger(
 4926        &self,
 4927        text: &str,
 4928        trigger_in_words: bool,
 4929        menu_is_open: bool,
 4930        cx: &mut Context<Self>,
 4931    ) -> bool {
 4932        let position = self.selections.newest_anchor().head();
 4933        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4934            return false;
 4935        };
 4936
 4937        if let Some(completion_provider) = &self.completion_provider {
 4938            completion_provider.is_completion_trigger(
 4939                &buffer,
 4940                position.text_anchor,
 4941                text,
 4942                trigger_in_words,
 4943                menu_is_open,
 4944                cx,
 4945            )
 4946        } else {
 4947            false
 4948        }
 4949    }
 4950
 4951    /// If any empty selections is touching the start of its innermost containing autoclose
 4952    /// region, expand it to select the brackets.
 4953    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4954        let selections = self.selections.all::<usize>(cx);
 4955        let buffer = self.buffer.read(cx).read(cx);
 4956        let new_selections = self
 4957            .selections_with_autoclose_regions(selections, &buffer)
 4958            .map(|(mut selection, region)| {
 4959                if !selection.is_empty() {
 4960                    return selection;
 4961                }
 4962
 4963                if let Some(region) = region {
 4964                    let mut range = region.range.to_offset(&buffer);
 4965                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4966                        range.start -= region.pair.start.len();
 4967                        if buffer.contains_str_at(range.start, &region.pair.start)
 4968                            && buffer.contains_str_at(range.end, &region.pair.end)
 4969                        {
 4970                            range.end += region.pair.end.len();
 4971                            selection.start = range.start;
 4972                            selection.end = range.end;
 4973
 4974                            return selection;
 4975                        }
 4976                    }
 4977                }
 4978
 4979                let always_treat_brackets_as_autoclosed = buffer
 4980                    .language_settings_at(selection.start, cx)
 4981                    .always_treat_brackets_as_autoclosed;
 4982
 4983                if !always_treat_brackets_as_autoclosed {
 4984                    return selection;
 4985                }
 4986
 4987                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4988                    for (pair, enabled) in scope.brackets() {
 4989                        if !enabled || !pair.close {
 4990                            continue;
 4991                        }
 4992
 4993                        if buffer.contains_str_at(selection.start, &pair.end) {
 4994                            let pair_start_len = pair.start.len();
 4995                            if buffer.contains_str_at(
 4996                                selection.start.saturating_sub(pair_start_len),
 4997                                &pair.start,
 4998                            ) {
 4999                                selection.start -= pair_start_len;
 5000                                selection.end += pair.end.len();
 5001
 5002                                return selection;
 5003                            }
 5004                        }
 5005                    }
 5006                }
 5007
 5008                selection
 5009            })
 5010            .collect();
 5011
 5012        drop(buffer);
 5013        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5014            selections.select(new_selections)
 5015        });
 5016    }
 5017
 5018    /// Iterate the given selections, and for each one, find the smallest surrounding
 5019    /// autoclose region. This uses the ordering of the selections and the autoclose
 5020    /// regions to avoid repeated comparisons.
 5021    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5022        &'a self,
 5023        selections: impl IntoIterator<Item = Selection<D>>,
 5024        buffer: &'a MultiBufferSnapshot,
 5025    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5026        let mut i = 0;
 5027        let mut regions = self.autoclose_regions.as_slice();
 5028        selections.into_iter().map(move |selection| {
 5029            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5030
 5031            let mut enclosing = None;
 5032            while let Some(pair_state) = regions.get(i) {
 5033                if pair_state.range.end.to_offset(buffer) < range.start {
 5034                    regions = &regions[i + 1..];
 5035                    i = 0;
 5036                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5037                    break;
 5038                } else {
 5039                    if pair_state.selection_id == selection.id {
 5040                        enclosing = Some(pair_state);
 5041                    }
 5042                    i += 1;
 5043                }
 5044            }
 5045
 5046            (selection, enclosing)
 5047        })
 5048    }
 5049
 5050    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5051    fn invalidate_autoclose_regions(
 5052        &mut self,
 5053        mut selections: &[Selection<Anchor>],
 5054        buffer: &MultiBufferSnapshot,
 5055    ) {
 5056        self.autoclose_regions.retain(|state| {
 5057            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5058                return false;
 5059            }
 5060
 5061            let mut i = 0;
 5062            while let Some(selection) = selections.get(i) {
 5063                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5064                    selections = &selections[1..];
 5065                    continue;
 5066                }
 5067                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5068                    break;
 5069                }
 5070                if selection.id == state.selection_id {
 5071                    return true;
 5072                } else {
 5073                    i += 1;
 5074                }
 5075            }
 5076            false
 5077        });
 5078    }
 5079
 5080    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5081        let offset = position.to_offset(buffer);
 5082        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5083        if offset > word_range.start && kind == Some(CharKind::Word) {
 5084            Some(
 5085                buffer
 5086                    .text_for_range(word_range.start..offset)
 5087                    .collect::<String>(),
 5088            )
 5089        } else {
 5090            None
 5091        }
 5092    }
 5093
 5094    pub fn toggle_inline_values(
 5095        &mut self,
 5096        _: &ToggleInlineValues,
 5097        _: &mut Window,
 5098        cx: &mut Context<Self>,
 5099    ) {
 5100        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5101
 5102        self.refresh_inline_values(cx);
 5103    }
 5104
 5105    pub fn toggle_inlay_hints(
 5106        &mut self,
 5107        _: &ToggleInlayHints,
 5108        _: &mut Window,
 5109        cx: &mut Context<Self>,
 5110    ) {
 5111        self.refresh_inlay_hints(
 5112            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5113            cx,
 5114        );
 5115    }
 5116
 5117    pub fn inlay_hints_enabled(&self) -> bool {
 5118        self.inlay_hint_cache.enabled
 5119    }
 5120
 5121    pub fn inline_values_enabled(&self) -> bool {
 5122        self.inline_value_cache.enabled
 5123    }
 5124
 5125    #[cfg(any(test, feature = "test-support"))]
 5126    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5127        self.display_map
 5128            .read(cx)
 5129            .current_inlays()
 5130            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5131            .cloned()
 5132            .collect()
 5133    }
 5134
 5135    #[cfg(any(test, feature = "test-support"))]
 5136    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5137        self.display_map
 5138            .read(cx)
 5139            .current_inlays()
 5140            .cloned()
 5141            .collect()
 5142    }
 5143
 5144    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5145        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5146            return;
 5147        }
 5148
 5149        let reason_description = reason.description();
 5150        let ignore_debounce = matches!(
 5151            reason,
 5152            InlayHintRefreshReason::SettingsChange(_)
 5153                | InlayHintRefreshReason::Toggle(_)
 5154                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5155                | InlayHintRefreshReason::ModifiersChanged(_)
 5156        );
 5157        let (invalidate_cache, required_languages) = match reason {
 5158            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5159                match self.inlay_hint_cache.modifiers_override(enabled) {
 5160                    Some(enabled) => {
 5161                        if enabled {
 5162                            (InvalidationStrategy::RefreshRequested, None)
 5163                        } else {
 5164                            self.splice_inlays(
 5165                                &self
 5166                                    .visible_inlay_hints(cx)
 5167                                    .iter()
 5168                                    .map(|inlay| inlay.id)
 5169                                    .collect::<Vec<InlayId>>(),
 5170                                Vec::new(),
 5171                                cx,
 5172                            );
 5173                            return;
 5174                        }
 5175                    }
 5176                    None => return,
 5177                }
 5178            }
 5179            InlayHintRefreshReason::Toggle(enabled) => {
 5180                if self.inlay_hint_cache.toggle(enabled) {
 5181                    if enabled {
 5182                        (InvalidationStrategy::RefreshRequested, None)
 5183                    } else {
 5184                        self.splice_inlays(
 5185                            &self
 5186                                .visible_inlay_hints(cx)
 5187                                .iter()
 5188                                .map(|inlay| inlay.id)
 5189                                .collect::<Vec<InlayId>>(),
 5190                            Vec::new(),
 5191                            cx,
 5192                        );
 5193                        return;
 5194                    }
 5195                } else {
 5196                    return;
 5197                }
 5198            }
 5199            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5200                match self.inlay_hint_cache.update_settings(
 5201                    &self.buffer,
 5202                    new_settings,
 5203                    self.visible_inlay_hints(cx),
 5204                    cx,
 5205                ) {
 5206                    ControlFlow::Break(Some(InlaySplice {
 5207                        to_remove,
 5208                        to_insert,
 5209                    })) => {
 5210                        self.splice_inlays(&to_remove, to_insert, cx);
 5211                        return;
 5212                    }
 5213                    ControlFlow::Break(None) => return,
 5214                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5215                }
 5216            }
 5217            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5218                if let Some(InlaySplice {
 5219                    to_remove,
 5220                    to_insert,
 5221                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5222                {
 5223                    self.splice_inlays(&to_remove, to_insert, cx);
 5224                }
 5225                self.display_map.update(cx, |display_map, _| {
 5226                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5227                });
 5228                return;
 5229            }
 5230            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5231            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5232                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5233            }
 5234            InlayHintRefreshReason::RefreshRequested => {
 5235                (InvalidationStrategy::RefreshRequested, None)
 5236            }
 5237        };
 5238
 5239        if let Some(InlaySplice {
 5240            to_remove,
 5241            to_insert,
 5242        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5243            reason_description,
 5244            self.visible_excerpts(required_languages.as_ref(), cx),
 5245            invalidate_cache,
 5246            ignore_debounce,
 5247            cx,
 5248        ) {
 5249            self.splice_inlays(&to_remove, to_insert, cx);
 5250        }
 5251    }
 5252
 5253    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5254        self.display_map
 5255            .read(cx)
 5256            .current_inlays()
 5257            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5258            .cloned()
 5259            .collect()
 5260    }
 5261
 5262    pub fn visible_excerpts(
 5263        &self,
 5264        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5265        cx: &mut Context<Editor>,
 5266    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5267        let Some(project) = self.project() else {
 5268            return HashMap::default();
 5269        };
 5270        let project = project.read(cx);
 5271        let multi_buffer = self.buffer().read(cx);
 5272        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5273        let multi_buffer_visible_start = self
 5274            .scroll_manager
 5275            .anchor()
 5276            .anchor
 5277            .to_point(&multi_buffer_snapshot);
 5278        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5279            multi_buffer_visible_start
 5280                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5281            Bias::Left,
 5282        );
 5283        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5284        multi_buffer_snapshot
 5285            .range_to_buffer_ranges(multi_buffer_visible_range)
 5286            .into_iter()
 5287            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5288            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5289                let buffer_file = project::File::from_dyn(buffer.file())?;
 5290                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5291                let worktree_entry = buffer_worktree
 5292                    .read(cx)
 5293                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5294                if worktree_entry.is_ignored {
 5295                    return None;
 5296                }
 5297
 5298                let language = buffer.language()?;
 5299                if let Some(restrict_to_languages) = restrict_to_languages
 5300                    && !restrict_to_languages.contains(language)
 5301                {
 5302                    return None;
 5303                }
 5304                Some((
 5305                    excerpt_id,
 5306                    (
 5307                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5308                        buffer.version().clone(),
 5309                        excerpt_visible_range,
 5310                    ),
 5311                ))
 5312            })
 5313            .collect()
 5314    }
 5315
 5316    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5317        TextLayoutDetails {
 5318            text_system: window.text_system().clone(),
 5319            editor_style: self.style.clone().unwrap(),
 5320            rem_size: window.rem_size(),
 5321            scroll_anchor: self.scroll_manager.anchor(),
 5322            visible_rows: self.visible_line_count(),
 5323            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5324        }
 5325    }
 5326
 5327    pub fn splice_inlays(
 5328        &self,
 5329        to_remove: &[InlayId],
 5330        to_insert: Vec<Inlay>,
 5331        cx: &mut Context<Self>,
 5332    ) {
 5333        self.display_map.update(cx, |display_map, cx| {
 5334            display_map.splice_inlays(to_remove, to_insert, cx)
 5335        });
 5336        cx.notify();
 5337    }
 5338
 5339    fn trigger_on_type_formatting(
 5340        &self,
 5341        input: String,
 5342        window: &mut Window,
 5343        cx: &mut Context<Self>,
 5344    ) -> Option<Task<Result<()>>> {
 5345        if input.len() != 1 {
 5346            return None;
 5347        }
 5348
 5349        let project = self.project()?;
 5350        let position = self.selections.newest_anchor().head();
 5351        let (buffer, buffer_position) = self
 5352            .buffer
 5353            .read(cx)
 5354            .text_anchor_for_position(position, cx)?;
 5355
 5356        let settings = language_settings::language_settings(
 5357            buffer
 5358                .read(cx)
 5359                .language_at(buffer_position)
 5360                .map(|l| l.name()),
 5361            buffer.read(cx).file(),
 5362            cx,
 5363        );
 5364        if !settings.use_on_type_format {
 5365            return None;
 5366        }
 5367
 5368        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5369        // hence we do LSP request & edit on host side only — add formats to host's history.
 5370        let push_to_lsp_host_history = true;
 5371        // If this is not the host, append its history with new edits.
 5372        let push_to_client_history = project.read(cx).is_via_collab();
 5373
 5374        let on_type_formatting = project.update(cx, |project, cx| {
 5375            project.on_type_format(
 5376                buffer.clone(),
 5377                buffer_position,
 5378                input,
 5379                push_to_lsp_host_history,
 5380                cx,
 5381            )
 5382        });
 5383        Some(cx.spawn_in(window, async move |editor, cx| {
 5384            if let Some(transaction) = on_type_formatting.await? {
 5385                if push_to_client_history {
 5386                    buffer
 5387                        .update(cx, |buffer, _| {
 5388                            buffer.push_transaction(transaction, Instant::now());
 5389                            buffer.finalize_last_transaction();
 5390                        })
 5391                        .ok();
 5392                }
 5393                editor.update(cx, |editor, cx| {
 5394                    editor.refresh_document_highlights(cx);
 5395                })?;
 5396            }
 5397            Ok(())
 5398        }))
 5399    }
 5400
 5401    pub fn show_word_completions(
 5402        &mut self,
 5403        _: &ShowWordCompletions,
 5404        window: &mut Window,
 5405        cx: &mut Context<Self>,
 5406    ) {
 5407        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5408    }
 5409
 5410    pub fn show_completions(
 5411        &mut self,
 5412        options: &ShowCompletions,
 5413        window: &mut Window,
 5414        cx: &mut Context<Self>,
 5415    ) {
 5416        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5417    }
 5418
 5419    fn open_or_update_completions_menu(
 5420        &mut self,
 5421        requested_source: Option<CompletionsMenuSource>,
 5422        trigger: Option<&str>,
 5423        window: &mut Window,
 5424        cx: &mut Context<Self>,
 5425    ) {
 5426        if self.pending_rename.is_some() {
 5427            return;
 5428        }
 5429
 5430        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5431
 5432        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5433        // inserted and selected. To handle that case, the start of the selection is used so that
 5434        // the menu starts with all choices.
 5435        let position = self
 5436            .selections
 5437            .newest_anchor()
 5438            .start
 5439            .bias_right(&multibuffer_snapshot);
 5440        if position.diff_base_anchor.is_some() {
 5441            return;
 5442        }
 5443        let (buffer, buffer_position) =
 5444            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5445                output
 5446            } else {
 5447                return;
 5448            };
 5449        let buffer_snapshot = buffer.read(cx).snapshot();
 5450
 5451        let query: Option<Arc<String>> =
 5452            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5453
 5454        drop(multibuffer_snapshot);
 5455
 5456        let provider = match requested_source {
 5457            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5458            Some(CompletionsMenuSource::Words) => None,
 5459            Some(CompletionsMenuSource::SnippetChoices) => {
 5460                log::error!("bug: SnippetChoices requested_source is not handled");
 5461                None
 5462            }
 5463        };
 5464
 5465        let sort_completions = provider
 5466            .as_ref()
 5467            .is_some_and(|provider| provider.sort_completions());
 5468
 5469        let filter_completions = provider
 5470            .as_ref()
 5471            .is_none_or(|provider| provider.filter_completions());
 5472
 5473        let trigger_kind = match trigger {
 5474            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5475                CompletionTriggerKind::TRIGGER_CHARACTER
 5476            }
 5477            _ => CompletionTriggerKind::INVOKED,
 5478        };
 5479        let completion_context = CompletionContext {
 5480            trigger_character: trigger.and_then(|trigger| {
 5481                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5482                    Some(String::from(trigger))
 5483                } else {
 5484                    None
 5485                }
 5486            }),
 5487            trigger_kind,
 5488        };
 5489
 5490        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5491        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5492        // involve trigger chars, so this is skipped in that case.
 5493        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5494        {
 5495            let menu_is_open = matches!(
 5496                self.context_menu.borrow().as_ref(),
 5497                Some(CodeContextMenu::Completions(_))
 5498            );
 5499            if menu_is_open {
 5500                self.hide_context_menu(window, cx);
 5501            }
 5502        }
 5503
 5504        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5505            if filter_completions {
 5506                menu.filter(query.clone(), provider.clone(), window, cx);
 5507            }
 5508            // When `is_incomplete` is false, no need to re-query completions when the current query
 5509            // is a suffix of the initial query.
 5510            if !menu.is_incomplete {
 5511                // If the new query is a suffix of the old query (typing more characters) and
 5512                // the previous result was complete, the existing completions can be filtered.
 5513                //
 5514                // Note that this is always true for snippet completions.
 5515                let query_matches = match (&menu.initial_query, &query) {
 5516                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5517                    (None, _) => true,
 5518                    _ => false,
 5519                };
 5520                if query_matches {
 5521                    let position_matches = if menu.initial_position == position {
 5522                        true
 5523                    } else {
 5524                        let snapshot = self.buffer.read(cx).read(cx);
 5525                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5526                    };
 5527                    if position_matches {
 5528                        return;
 5529                    }
 5530                }
 5531            }
 5532        };
 5533
 5534        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5535            buffer_snapshot.surrounding_word(buffer_position, false)
 5536        {
 5537            let word_to_exclude = buffer_snapshot
 5538                .text_for_range(word_range.clone())
 5539                .collect::<String>();
 5540            (
 5541                buffer_snapshot.anchor_before(word_range.start)
 5542                    ..buffer_snapshot.anchor_after(buffer_position),
 5543                Some(word_to_exclude),
 5544            )
 5545        } else {
 5546            (buffer_position..buffer_position, None)
 5547        };
 5548
 5549        let language = buffer_snapshot
 5550            .language_at(buffer_position)
 5551            .map(|language| language.name());
 5552
 5553        let completion_settings =
 5554            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5555
 5556        let show_completion_documentation = buffer_snapshot
 5557            .settings_at(buffer_position, cx)
 5558            .show_completion_documentation;
 5559
 5560        // The document can be large, so stay in reasonable bounds when searching for words,
 5561        // otherwise completion pop-up might be slow to appear.
 5562        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5563        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5564        let min_word_search = buffer_snapshot.clip_point(
 5565            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5566            Bias::Left,
 5567        );
 5568        let max_word_search = buffer_snapshot.clip_point(
 5569            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5570            Bias::Right,
 5571        );
 5572        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5573            ..buffer_snapshot.point_to_offset(max_word_search);
 5574
 5575        let skip_digits = query
 5576            .as_ref()
 5577            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5578
 5579        let (mut words, provider_responses) = match &provider {
 5580            Some(provider) => {
 5581                let provider_responses = provider.completions(
 5582                    position.excerpt_id,
 5583                    &buffer,
 5584                    buffer_position,
 5585                    completion_context,
 5586                    window,
 5587                    cx,
 5588                );
 5589
 5590                let words = match completion_settings.words {
 5591                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5592                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5593                        .background_spawn(async move {
 5594                            buffer_snapshot.words_in_range(WordsQuery {
 5595                                fuzzy_contents: None,
 5596                                range: word_search_range,
 5597                                skip_digits,
 5598                            })
 5599                        }),
 5600                };
 5601
 5602                (words, provider_responses)
 5603            }
 5604            None => (
 5605                cx.background_spawn(async move {
 5606                    buffer_snapshot.words_in_range(WordsQuery {
 5607                        fuzzy_contents: None,
 5608                        range: word_search_range,
 5609                        skip_digits,
 5610                    })
 5611                }),
 5612                Task::ready(Ok(Vec::new())),
 5613            ),
 5614        };
 5615
 5616        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5617
 5618        let id = post_inc(&mut self.next_completion_id);
 5619        let task = cx.spawn_in(window, async move |editor, cx| {
 5620            let Ok(()) = editor.update(cx, |this, _| {
 5621                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5622            }) else {
 5623                return;
 5624            };
 5625
 5626            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5627            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5628            let mut completions = Vec::new();
 5629            let mut is_incomplete = false;
 5630            if let Some(provider_responses) = provider_responses.await.log_err()
 5631                && !provider_responses.is_empty()
 5632            {
 5633                for response in provider_responses {
 5634                    completions.extend(response.completions);
 5635                    is_incomplete = is_incomplete || response.is_incomplete;
 5636                }
 5637                if completion_settings.words == WordsCompletionMode::Fallback {
 5638                    words = Task::ready(BTreeMap::default());
 5639                }
 5640            }
 5641
 5642            let mut words = words.await;
 5643            if let Some(word_to_exclude) = &word_to_exclude {
 5644                words.remove(word_to_exclude);
 5645            }
 5646            for lsp_completion in &completions {
 5647                words.remove(&lsp_completion.new_text);
 5648            }
 5649            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5650                replace_range: word_replace_range.clone(),
 5651                new_text: word.clone(),
 5652                label: CodeLabel::plain(word, None),
 5653                icon_path: None,
 5654                documentation: None,
 5655                source: CompletionSource::BufferWord {
 5656                    word_range,
 5657                    resolved: false,
 5658                },
 5659                insert_text_mode: Some(InsertTextMode::AS_IS),
 5660                confirm: None,
 5661            }));
 5662
 5663            let menu = if completions.is_empty() {
 5664                None
 5665            } else {
 5666                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5667                    let languages = editor
 5668                        .workspace
 5669                        .as_ref()
 5670                        .and_then(|(workspace, _)| workspace.upgrade())
 5671                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5672                    let menu = CompletionsMenu::new(
 5673                        id,
 5674                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5675                        sort_completions,
 5676                        show_completion_documentation,
 5677                        position,
 5678                        query.clone(),
 5679                        is_incomplete,
 5680                        buffer.clone(),
 5681                        completions.into(),
 5682                        snippet_sort_order,
 5683                        languages,
 5684                        language,
 5685                        cx,
 5686                    );
 5687
 5688                    let query = if filter_completions { query } else { None };
 5689                    let matches_task = if let Some(query) = query {
 5690                        menu.do_async_filtering(query, cx)
 5691                    } else {
 5692                        Task::ready(menu.unfiltered_matches())
 5693                    };
 5694                    (menu, matches_task)
 5695                }) else {
 5696                    return;
 5697                };
 5698
 5699                let matches = matches_task.await;
 5700
 5701                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5702                    // Newer menu already set, so exit.
 5703                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5704                        editor.context_menu.borrow().as_ref()
 5705                        && prev_menu.id > id
 5706                    {
 5707                        return;
 5708                    };
 5709
 5710                    // Only valid to take prev_menu because it the new menu is immediately set
 5711                    // below, or the menu is hidden.
 5712                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5713                        editor.context_menu.borrow_mut().take()
 5714                    {
 5715                        let position_matches =
 5716                            if prev_menu.initial_position == menu.initial_position {
 5717                                true
 5718                            } else {
 5719                                let snapshot = editor.buffer.read(cx).read(cx);
 5720                                prev_menu.initial_position.to_offset(&snapshot)
 5721                                    == menu.initial_position.to_offset(&snapshot)
 5722                            };
 5723                        if position_matches {
 5724                            // Preserve markdown cache before `set_filter_results` because it will
 5725                            // try to populate the documentation cache.
 5726                            menu.preserve_markdown_cache(prev_menu);
 5727                        }
 5728                    };
 5729
 5730                    menu.set_filter_results(matches, provider, window, cx);
 5731                }) else {
 5732                    return;
 5733                };
 5734
 5735                menu.visible().then_some(menu)
 5736            };
 5737
 5738            editor
 5739                .update_in(cx, |editor, window, cx| {
 5740                    if editor.focus_handle.is_focused(window)
 5741                        && let Some(menu) = menu
 5742                    {
 5743                        *editor.context_menu.borrow_mut() =
 5744                            Some(CodeContextMenu::Completions(menu));
 5745
 5746                        crate::hover_popover::hide_hover(editor, cx);
 5747                        if editor.show_edit_predictions_in_menu() {
 5748                            editor.update_visible_edit_prediction(window, cx);
 5749                        } else {
 5750                            editor.discard_edit_prediction(false, cx);
 5751                        }
 5752
 5753                        cx.notify();
 5754                        return;
 5755                    }
 5756
 5757                    if editor.completion_tasks.len() <= 1 {
 5758                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5759                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5760                        // If it was already hidden and we don't show edit predictions in the menu,
 5761                        // we should also show the edit prediction when available.
 5762                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5763                            editor.update_visible_edit_prediction(window, cx);
 5764                        }
 5765                    }
 5766                })
 5767                .ok();
 5768        });
 5769
 5770        self.completion_tasks.push((id, task));
 5771    }
 5772
 5773    #[cfg(feature = "test-support")]
 5774    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5775        let menu = self.context_menu.borrow();
 5776        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5777            let completions = menu.completions.borrow();
 5778            Some(completions.to_vec())
 5779        } else {
 5780            None
 5781        }
 5782    }
 5783
 5784    pub fn with_completions_menu_matching_id<R>(
 5785        &self,
 5786        id: CompletionId,
 5787        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5788    ) -> R {
 5789        let mut context_menu = self.context_menu.borrow_mut();
 5790        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5791            return f(None);
 5792        };
 5793        if completions_menu.id != id {
 5794            return f(None);
 5795        }
 5796        f(Some(completions_menu))
 5797    }
 5798
 5799    pub fn confirm_completion(
 5800        &mut self,
 5801        action: &ConfirmCompletion,
 5802        window: &mut Window,
 5803        cx: &mut Context<Self>,
 5804    ) -> Option<Task<Result<()>>> {
 5805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5806        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5807    }
 5808
 5809    pub fn confirm_completion_insert(
 5810        &mut self,
 5811        _: &ConfirmCompletionInsert,
 5812        window: &mut Window,
 5813        cx: &mut Context<Self>,
 5814    ) -> Option<Task<Result<()>>> {
 5815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5816        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5817    }
 5818
 5819    pub fn confirm_completion_replace(
 5820        &mut self,
 5821        _: &ConfirmCompletionReplace,
 5822        window: &mut Window,
 5823        cx: &mut Context<Self>,
 5824    ) -> Option<Task<Result<()>>> {
 5825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5826        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5827    }
 5828
 5829    pub fn compose_completion(
 5830        &mut self,
 5831        action: &ComposeCompletion,
 5832        window: &mut Window,
 5833        cx: &mut Context<Self>,
 5834    ) -> Option<Task<Result<()>>> {
 5835        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5836        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5837    }
 5838
 5839    fn do_completion(
 5840        &mut self,
 5841        item_ix: Option<usize>,
 5842        intent: CompletionIntent,
 5843        window: &mut Window,
 5844        cx: &mut Context<Editor>,
 5845    ) -> Option<Task<Result<()>>> {
 5846        use language::ToOffset as _;
 5847
 5848        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5849        else {
 5850            return None;
 5851        };
 5852
 5853        let candidate_id = {
 5854            let entries = completions_menu.entries.borrow();
 5855            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5856            if self.show_edit_predictions_in_menu() {
 5857                self.discard_edit_prediction(true, cx);
 5858            }
 5859            mat.candidate_id
 5860        };
 5861
 5862        let completion = completions_menu
 5863            .completions
 5864            .borrow()
 5865            .get(candidate_id)?
 5866            .clone();
 5867        cx.stop_propagation();
 5868
 5869        let buffer_handle = completions_menu.buffer.clone();
 5870
 5871        let CompletionEdit {
 5872            new_text,
 5873            snippet,
 5874            replace_range,
 5875        } = process_completion_for_edit(
 5876            &completion,
 5877            intent,
 5878            &buffer_handle,
 5879            &completions_menu.initial_position.text_anchor,
 5880            cx,
 5881        );
 5882
 5883        let buffer = buffer_handle.read(cx);
 5884        let snapshot = self.buffer.read(cx).snapshot(cx);
 5885        let newest_anchor = self.selections.newest_anchor();
 5886        let replace_range_multibuffer = {
 5887            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5888            let multibuffer_anchor = snapshot
 5889                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5890                .unwrap()
 5891                ..snapshot
 5892                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5893                    .unwrap();
 5894            multibuffer_anchor.start.to_offset(&snapshot)
 5895                ..multibuffer_anchor.end.to_offset(&snapshot)
 5896        };
 5897        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5898            return None;
 5899        }
 5900
 5901        let old_text = buffer
 5902            .text_for_range(replace_range.clone())
 5903            .collect::<String>();
 5904        let lookbehind = newest_anchor
 5905            .start
 5906            .text_anchor
 5907            .to_offset(buffer)
 5908            .saturating_sub(replace_range.start);
 5909        let lookahead = replace_range
 5910            .end
 5911            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5912        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5913        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5914
 5915        let selections = self.selections.all::<usize>(cx);
 5916        let mut ranges = Vec::new();
 5917        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5918
 5919        for selection in &selections {
 5920            let range = if selection.id == newest_anchor.id {
 5921                replace_range_multibuffer.clone()
 5922            } else {
 5923                let mut range = selection.range();
 5924
 5925                // if prefix is present, don't duplicate it
 5926                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5927                    range.start = range.start.saturating_sub(lookbehind);
 5928
 5929                    // if suffix is also present, mimic the newest cursor and replace it
 5930                    if selection.id != newest_anchor.id
 5931                        && snapshot.contains_str_at(range.end, suffix)
 5932                    {
 5933                        range.end += lookahead;
 5934                    }
 5935                }
 5936                range
 5937            };
 5938
 5939            ranges.push(range.clone());
 5940
 5941            if !self.linked_edit_ranges.is_empty() {
 5942                let start_anchor = snapshot.anchor_before(range.start);
 5943                let end_anchor = snapshot.anchor_after(range.end);
 5944                if let Some(ranges) = self
 5945                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5946                {
 5947                    for (buffer, edits) in ranges {
 5948                        linked_edits
 5949                            .entry(buffer.clone())
 5950                            .or_default()
 5951                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5952                    }
 5953                }
 5954            }
 5955        }
 5956
 5957        let common_prefix_len = old_text
 5958            .chars()
 5959            .zip(new_text.chars())
 5960            .take_while(|(a, b)| a == b)
 5961            .map(|(a, _)| a.len_utf8())
 5962            .sum::<usize>();
 5963
 5964        cx.emit(EditorEvent::InputHandled {
 5965            utf16_range_to_replace: None,
 5966            text: new_text[common_prefix_len..].into(),
 5967        });
 5968
 5969        self.transact(window, cx, |editor, window, cx| {
 5970            if let Some(mut snippet) = snippet {
 5971                snippet.text = new_text.to_string();
 5972                editor
 5973                    .insert_snippet(&ranges, snippet, window, cx)
 5974                    .log_err();
 5975            } else {
 5976                editor.buffer.update(cx, |multi_buffer, cx| {
 5977                    let auto_indent = match completion.insert_text_mode {
 5978                        Some(InsertTextMode::AS_IS) => None,
 5979                        _ => editor.autoindent_mode.clone(),
 5980                    };
 5981                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5982                    multi_buffer.edit(edits, auto_indent, cx);
 5983                });
 5984            }
 5985            for (buffer, edits) in linked_edits {
 5986                buffer.update(cx, |buffer, cx| {
 5987                    let snapshot = buffer.snapshot();
 5988                    let edits = edits
 5989                        .into_iter()
 5990                        .map(|(range, text)| {
 5991                            use text::ToPoint as TP;
 5992                            let end_point = TP::to_point(&range.end, &snapshot);
 5993                            let start_point = TP::to_point(&range.start, &snapshot);
 5994                            (start_point..end_point, text)
 5995                        })
 5996                        .sorted_by_key(|(range, _)| range.start);
 5997                    buffer.edit(edits, None, cx);
 5998                })
 5999            }
 6000
 6001            editor.refresh_edit_prediction(true, false, window, cx);
 6002        });
 6003        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6004
 6005        let show_new_completions_on_confirm = completion
 6006            .confirm
 6007            .as_ref()
 6008            .is_some_and(|confirm| confirm(intent, window, cx));
 6009        if show_new_completions_on_confirm {
 6010            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6011        }
 6012
 6013        let provider = self.completion_provider.as_ref()?;
 6014        drop(completion);
 6015        let apply_edits = provider.apply_additional_edits_for_completion(
 6016            buffer_handle,
 6017            completions_menu.completions.clone(),
 6018            candidate_id,
 6019            true,
 6020            cx,
 6021        );
 6022
 6023        let editor_settings = EditorSettings::get_global(cx);
 6024        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6025            // After the code completion is finished, users often want to know what signatures are needed.
 6026            // so we should automatically call signature_help
 6027            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6028        }
 6029
 6030        Some(cx.foreground_executor().spawn(async move {
 6031            apply_edits.await?;
 6032            Ok(())
 6033        }))
 6034    }
 6035
 6036    pub fn toggle_code_actions(
 6037        &mut self,
 6038        action: &ToggleCodeActions,
 6039        window: &mut Window,
 6040        cx: &mut Context<Self>,
 6041    ) {
 6042        let quick_launch = action.quick_launch;
 6043        let mut context_menu = self.context_menu.borrow_mut();
 6044        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6045            if code_actions.deployed_from == action.deployed_from {
 6046                // Toggle if we're selecting the same one
 6047                *context_menu = None;
 6048                cx.notify();
 6049                return;
 6050            } else {
 6051                // Otherwise, clear it and start a new one
 6052                *context_menu = None;
 6053                cx.notify();
 6054            }
 6055        }
 6056        drop(context_menu);
 6057        let snapshot = self.snapshot(window, cx);
 6058        let deployed_from = action.deployed_from.clone();
 6059        let action = action.clone();
 6060        self.completion_tasks.clear();
 6061        self.discard_edit_prediction(false, cx);
 6062
 6063        let multibuffer_point = match &action.deployed_from {
 6064            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6065                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6066            }
 6067            _ => self.selections.newest::<Point>(cx).head(),
 6068        };
 6069        let Some((buffer, buffer_row)) = snapshot
 6070            .buffer_snapshot
 6071            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6072            .and_then(|(buffer_snapshot, range)| {
 6073                self.buffer()
 6074                    .read(cx)
 6075                    .buffer(buffer_snapshot.remote_id())
 6076                    .map(|buffer| (buffer, range.start.row))
 6077            })
 6078        else {
 6079            return;
 6080        };
 6081        let buffer_id = buffer.read(cx).remote_id();
 6082        let tasks = self
 6083            .tasks
 6084            .get(&(buffer_id, buffer_row))
 6085            .map(|t| Arc::new(t.to_owned()));
 6086
 6087        if !self.focus_handle.is_focused(window) {
 6088            return;
 6089        }
 6090        let project = self.project.clone();
 6091
 6092        let code_actions_task = match deployed_from {
 6093            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6094            _ => self.code_actions(buffer_row, window, cx),
 6095        };
 6096
 6097        let runnable_task = match deployed_from {
 6098            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6099            _ => {
 6100                let mut task_context_task = Task::ready(None);
 6101                if let Some(tasks) = &tasks
 6102                    && let Some(project) = project
 6103                {
 6104                    task_context_task =
 6105                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6106                }
 6107
 6108                cx.spawn_in(window, {
 6109                    let buffer = buffer.clone();
 6110                    async move |editor, cx| {
 6111                        let task_context = task_context_task.await;
 6112
 6113                        let resolved_tasks =
 6114                            tasks
 6115                                .zip(task_context.clone())
 6116                                .map(|(tasks, task_context)| ResolvedTasks {
 6117                                    templates: tasks.resolve(&task_context).collect(),
 6118                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6119                                        multibuffer_point.row,
 6120                                        tasks.column,
 6121                                    )),
 6122                                });
 6123                        let debug_scenarios = editor
 6124                            .update(cx, |editor, cx| {
 6125                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6126                            })?
 6127                            .await;
 6128                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6129                    }
 6130                })
 6131            }
 6132        };
 6133
 6134        cx.spawn_in(window, async move |editor, cx| {
 6135            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6136            let code_actions = code_actions_task.await;
 6137            let spawn_straight_away = quick_launch
 6138                && resolved_tasks
 6139                    .as_ref()
 6140                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6141                && code_actions
 6142                    .as_ref()
 6143                    .is_none_or(|actions| actions.is_empty())
 6144                && debug_scenarios.is_empty();
 6145
 6146            editor.update_in(cx, |editor, window, cx| {
 6147                crate::hover_popover::hide_hover(editor, cx);
 6148                let actions = CodeActionContents::new(
 6149                    resolved_tasks,
 6150                    code_actions,
 6151                    debug_scenarios,
 6152                    task_context.unwrap_or_default(),
 6153                );
 6154
 6155                // Don't show the menu if there are no actions available
 6156                if actions.is_empty() {
 6157                    cx.notify();
 6158                    return Task::ready(Ok(()));
 6159                }
 6160
 6161                *editor.context_menu.borrow_mut() =
 6162                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6163                        buffer,
 6164                        actions,
 6165                        selected_item: Default::default(),
 6166                        scroll_handle: UniformListScrollHandle::default(),
 6167                        deployed_from,
 6168                    }));
 6169                cx.notify();
 6170                if spawn_straight_away
 6171                    && let Some(task) = editor.confirm_code_action(
 6172                        &ConfirmCodeAction { item_ix: Some(0) },
 6173                        window,
 6174                        cx,
 6175                    )
 6176                {
 6177                    return task;
 6178                }
 6179
 6180                Task::ready(Ok(()))
 6181            })
 6182        })
 6183        .detach_and_log_err(cx);
 6184    }
 6185
 6186    fn debug_scenarios(
 6187        &mut self,
 6188        resolved_tasks: &Option<ResolvedTasks>,
 6189        buffer: &Entity<Buffer>,
 6190        cx: &mut App,
 6191    ) -> Task<Vec<task::DebugScenario>> {
 6192        maybe!({
 6193            let project = self.project()?;
 6194            let dap_store = project.read(cx).dap_store();
 6195            let mut scenarios = vec![];
 6196            let resolved_tasks = resolved_tasks.as_ref()?;
 6197            let buffer = buffer.read(cx);
 6198            let language = buffer.language()?;
 6199            let file = buffer.file();
 6200            let debug_adapter = language_settings(language.name().into(), file, cx)
 6201                .debuggers
 6202                .first()
 6203                .map(SharedString::from)
 6204                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6205
 6206            dap_store.update(cx, |dap_store, cx| {
 6207                for (_, task) in &resolved_tasks.templates {
 6208                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6209                        task.original_task().clone(),
 6210                        debug_adapter.clone().into(),
 6211                        task.display_label().to_owned().into(),
 6212                        cx,
 6213                    );
 6214                    scenarios.push(maybe_scenario);
 6215                }
 6216            });
 6217            Some(cx.background_spawn(async move {
 6218                futures::future::join_all(scenarios)
 6219                    .await
 6220                    .into_iter()
 6221                    .flatten()
 6222                    .collect::<Vec<_>>()
 6223            }))
 6224        })
 6225        .unwrap_or_else(|| Task::ready(vec![]))
 6226    }
 6227
 6228    fn code_actions(
 6229        &mut self,
 6230        buffer_row: u32,
 6231        window: &mut Window,
 6232        cx: &mut Context<Self>,
 6233    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6234        let mut task = self.code_actions_task.take();
 6235        cx.spawn_in(window, async move |editor, cx| {
 6236            while let Some(prev_task) = task {
 6237                prev_task.await.log_err();
 6238                task = editor
 6239                    .update(cx, |this, _| this.code_actions_task.take())
 6240                    .ok()?;
 6241            }
 6242
 6243            editor
 6244                .update(cx, |editor, cx| {
 6245                    editor
 6246                        .available_code_actions
 6247                        .clone()
 6248                        .and_then(|(location, code_actions)| {
 6249                            let snapshot = location.buffer.read(cx).snapshot();
 6250                            let point_range = location.range.to_point(&snapshot);
 6251                            let point_range = point_range.start.row..=point_range.end.row;
 6252                            if point_range.contains(&buffer_row) {
 6253                                Some(code_actions)
 6254                            } else {
 6255                                None
 6256                            }
 6257                        })
 6258                })
 6259                .ok()
 6260                .flatten()
 6261        })
 6262    }
 6263
 6264    pub fn confirm_code_action(
 6265        &mut self,
 6266        action: &ConfirmCodeAction,
 6267        window: &mut Window,
 6268        cx: &mut Context<Self>,
 6269    ) -> Option<Task<Result<()>>> {
 6270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6271
 6272        let actions_menu =
 6273            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6274                menu
 6275            } else {
 6276                return None;
 6277            };
 6278
 6279        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6280        let action = actions_menu.actions.get(action_ix)?;
 6281        let title = action.label();
 6282        let buffer = actions_menu.buffer;
 6283        let workspace = self.workspace()?;
 6284
 6285        match action {
 6286            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6287                workspace.update(cx, |workspace, cx| {
 6288                    workspace.schedule_resolved_task(
 6289                        task_source_kind,
 6290                        resolved_task,
 6291                        false,
 6292                        window,
 6293                        cx,
 6294                    );
 6295
 6296                    Some(Task::ready(Ok(())))
 6297                })
 6298            }
 6299            CodeActionsItem::CodeAction {
 6300                excerpt_id,
 6301                action,
 6302                provider,
 6303            } => {
 6304                let apply_code_action =
 6305                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6306                let workspace = workspace.downgrade();
 6307                Some(cx.spawn_in(window, async move |editor, cx| {
 6308                    let project_transaction = apply_code_action.await?;
 6309                    Self::open_project_transaction(
 6310                        &editor,
 6311                        workspace,
 6312                        project_transaction,
 6313                        title,
 6314                        cx,
 6315                    )
 6316                    .await
 6317                }))
 6318            }
 6319            CodeActionsItem::DebugScenario(scenario) => {
 6320                let context = actions_menu.actions.context;
 6321
 6322                workspace.update(cx, |workspace, cx| {
 6323                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6324                    workspace.start_debug_session(
 6325                        scenario,
 6326                        context,
 6327                        Some(buffer),
 6328                        None,
 6329                        window,
 6330                        cx,
 6331                    );
 6332                });
 6333                Some(Task::ready(Ok(())))
 6334            }
 6335        }
 6336    }
 6337
 6338    pub async fn open_project_transaction(
 6339        editor: &WeakEntity<Editor>,
 6340        workspace: WeakEntity<Workspace>,
 6341        transaction: ProjectTransaction,
 6342        title: String,
 6343        cx: &mut AsyncWindowContext,
 6344    ) -> Result<()> {
 6345        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6346        cx.update(|_, cx| {
 6347            entries.sort_unstable_by_key(|(buffer, _)| {
 6348                buffer.read(cx).file().map(|f| f.path().clone())
 6349            });
 6350        })?;
 6351
 6352        // If the project transaction's edits are all contained within this editor, then
 6353        // avoid opening a new editor to display them.
 6354
 6355        if let Some((buffer, transaction)) = entries.first() {
 6356            if entries.len() == 1 {
 6357                let excerpt = editor.update(cx, |editor, cx| {
 6358                    editor
 6359                        .buffer()
 6360                        .read(cx)
 6361                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6362                })?;
 6363                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6364                    && excerpted_buffer == *buffer
 6365                {
 6366                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6367                        let excerpt_range = excerpt_range.to_offset(buffer);
 6368                        buffer
 6369                            .edited_ranges_for_transaction::<usize>(transaction)
 6370                            .all(|range| {
 6371                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6372                            })
 6373                    })?;
 6374
 6375                    if all_edits_within_excerpt {
 6376                        return Ok(());
 6377                    }
 6378                }
 6379            }
 6380        } else {
 6381            return Ok(());
 6382        }
 6383
 6384        let mut ranges_to_highlight = Vec::new();
 6385        let excerpt_buffer = cx.new(|cx| {
 6386            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6387            for (buffer_handle, transaction) in &entries {
 6388                let edited_ranges = buffer_handle
 6389                    .read(cx)
 6390                    .edited_ranges_for_transaction::<Point>(transaction)
 6391                    .collect::<Vec<_>>();
 6392                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6393                    PathKey::for_buffer(buffer_handle, cx),
 6394                    buffer_handle.clone(),
 6395                    edited_ranges,
 6396                    DEFAULT_MULTIBUFFER_CONTEXT,
 6397                    cx,
 6398                );
 6399
 6400                ranges_to_highlight.extend(ranges);
 6401            }
 6402            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6403            multibuffer
 6404        })?;
 6405
 6406        workspace.update_in(cx, |workspace, window, cx| {
 6407            let project = workspace.project().clone();
 6408            let editor =
 6409                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6410            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6411            editor.update(cx, |editor, cx| {
 6412                editor.highlight_background::<Self>(
 6413                    &ranges_to_highlight,
 6414                    |theme| theme.colors().editor_highlighted_line_background,
 6415                    cx,
 6416                );
 6417            });
 6418        })?;
 6419
 6420        Ok(())
 6421    }
 6422
 6423    pub fn clear_code_action_providers(&mut self) {
 6424        self.code_action_providers.clear();
 6425        self.available_code_actions.take();
 6426    }
 6427
 6428    pub fn add_code_action_provider(
 6429        &mut self,
 6430        provider: Rc<dyn CodeActionProvider>,
 6431        window: &mut Window,
 6432        cx: &mut Context<Self>,
 6433    ) {
 6434        if self
 6435            .code_action_providers
 6436            .iter()
 6437            .any(|existing_provider| existing_provider.id() == provider.id())
 6438        {
 6439            return;
 6440        }
 6441
 6442        self.code_action_providers.push(provider);
 6443        self.refresh_code_actions(window, cx);
 6444    }
 6445
 6446    pub fn remove_code_action_provider(
 6447        &mut self,
 6448        id: Arc<str>,
 6449        window: &mut Window,
 6450        cx: &mut Context<Self>,
 6451    ) {
 6452        self.code_action_providers
 6453            .retain(|provider| provider.id() != id);
 6454        self.refresh_code_actions(window, cx);
 6455    }
 6456
 6457    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6458        !self.code_action_providers.is_empty()
 6459            && EditorSettings::get_global(cx).toolbar.code_actions
 6460    }
 6461
 6462    pub fn has_available_code_actions(&self) -> bool {
 6463        self.available_code_actions
 6464            .as_ref()
 6465            .is_some_and(|(_, actions)| !actions.is_empty())
 6466    }
 6467
 6468    fn render_inline_code_actions(
 6469        &self,
 6470        icon_size: ui::IconSize,
 6471        display_row: DisplayRow,
 6472        is_active: bool,
 6473        cx: &mut Context<Self>,
 6474    ) -> AnyElement {
 6475        let show_tooltip = !self.context_menu_visible();
 6476        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6477            .icon_size(icon_size)
 6478            .shape(ui::IconButtonShape::Square)
 6479            .icon_color(ui::Color::Hidden)
 6480            .toggle_state(is_active)
 6481            .when(show_tooltip, |this| {
 6482                this.tooltip({
 6483                    let focus_handle = self.focus_handle.clone();
 6484                    move |window, cx| {
 6485                        Tooltip::for_action_in(
 6486                            "Toggle Code Actions",
 6487                            &ToggleCodeActions {
 6488                                deployed_from: None,
 6489                                quick_launch: false,
 6490                            },
 6491                            &focus_handle,
 6492                            window,
 6493                            cx,
 6494                        )
 6495                    }
 6496                })
 6497            })
 6498            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6499                window.focus(&editor.focus_handle(cx));
 6500                editor.toggle_code_actions(
 6501                    &crate::actions::ToggleCodeActions {
 6502                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6503                            display_row,
 6504                        )),
 6505                        quick_launch: false,
 6506                    },
 6507                    window,
 6508                    cx,
 6509                );
 6510            }))
 6511            .into_any_element()
 6512    }
 6513
 6514    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6515        &self.context_menu
 6516    }
 6517
 6518    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6519        let newest_selection = self.selections.newest_anchor().clone();
 6520        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6521        let buffer = self.buffer.read(cx);
 6522        if newest_selection.head().diff_base_anchor.is_some() {
 6523            return None;
 6524        }
 6525        let (start_buffer, start) =
 6526            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6527        let (end_buffer, end) =
 6528            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6529        if start_buffer != end_buffer {
 6530            return None;
 6531        }
 6532
 6533        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6534            cx.background_executor()
 6535                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6536                .await;
 6537
 6538            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6539                let providers = this.code_action_providers.clone();
 6540                let tasks = this
 6541                    .code_action_providers
 6542                    .iter()
 6543                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6544                    .collect::<Vec<_>>();
 6545                (providers, tasks)
 6546            })?;
 6547
 6548            let mut actions = Vec::new();
 6549            for (provider, provider_actions) in
 6550                providers.into_iter().zip(future::join_all(tasks).await)
 6551            {
 6552                if let Some(provider_actions) = provider_actions.log_err() {
 6553                    actions.extend(provider_actions.into_iter().map(|action| {
 6554                        AvailableCodeAction {
 6555                            excerpt_id: newest_selection.start.excerpt_id,
 6556                            action,
 6557                            provider: provider.clone(),
 6558                        }
 6559                    }));
 6560                }
 6561            }
 6562
 6563            this.update(cx, |this, cx| {
 6564                this.available_code_actions = if actions.is_empty() {
 6565                    None
 6566                } else {
 6567                    Some((
 6568                        Location {
 6569                            buffer: start_buffer,
 6570                            range: start..end,
 6571                        },
 6572                        actions.into(),
 6573                    ))
 6574                };
 6575                cx.notify();
 6576            })
 6577        }));
 6578        None
 6579    }
 6580
 6581    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6582        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6583            self.show_git_blame_inline = false;
 6584
 6585            self.show_git_blame_inline_delay_task =
 6586                Some(cx.spawn_in(window, async move |this, cx| {
 6587                    cx.background_executor().timer(delay).await;
 6588
 6589                    this.update(cx, |this, cx| {
 6590                        this.show_git_blame_inline = true;
 6591                        cx.notify();
 6592                    })
 6593                    .log_err();
 6594                }));
 6595        }
 6596    }
 6597
 6598    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6599        let snapshot = self.snapshot(window, cx);
 6600        let cursor = self.selections.newest::<Point>(cx).head();
 6601        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6602        else {
 6603            return;
 6604        };
 6605
 6606        let Some(blame) = self.blame.as_ref() else {
 6607            return;
 6608        };
 6609
 6610        let row_info = RowInfo {
 6611            buffer_id: Some(buffer.remote_id()),
 6612            buffer_row: Some(point.row),
 6613            ..Default::default()
 6614        };
 6615        let Some(blame_entry) = blame
 6616            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6617            .flatten()
 6618        else {
 6619            return;
 6620        };
 6621
 6622        let anchor = self.selections.newest_anchor().head();
 6623        let position = self.to_pixel_point(anchor, &snapshot, window);
 6624        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6625            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6626        };
 6627    }
 6628
 6629    fn show_blame_popover(
 6630        &mut self,
 6631        blame_entry: &BlameEntry,
 6632        position: gpui::Point<Pixels>,
 6633        ignore_timeout: bool,
 6634        cx: &mut Context<Self>,
 6635    ) {
 6636        if let Some(state) = &mut self.inline_blame_popover {
 6637            state.hide_task.take();
 6638        } else {
 6639            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6640            let blame_entry = blame_entry.clone();
 6641            let show_task = cx.spawn(async move |editor, cx| {
 6642                if !ignore_timeout {
 6643                    cx.background_executor()
 6644                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6645                        .await;
 6646                }
 6647                editor
 6648                    .update(cx, |editor, cx| {
 6649                        editor.inline_blame_popover_show_task.take();
 6650                        let Some(blame) = editor.blame.as_ref() else {
 6651                            return;
 6652                        };
 6653                        let blame = blame.read(cx);
 6654                        let details = blame.details_for_entry(&blame_entry);
 6655                        let markdown = cx.new(|cx| {
 6656                            Markdown::new(
 6657                                details
 6658                                    .as_ref()
 6659                                    .map(|message| message.message.clone())
 6660                                    .unwrap_or_default(),
 6661                                None,
 6662                                None,
 6663                                cx,
 6664                            )
 6665                        });
 6666                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6667                            position,
 6668                            hide_task: None,
 6669                            popover_bounds: None,
 6670                            popover_state: InlineBlamePopoverState {
 6671                                scroll_handle: ScrollHandle::new(),
 6672                                commit_message: details,
 6673                                markdown,
 6674                            },
 6675                            keyboard_grace: ignore_timeout,
 6676                        });
 6677                        cx.notify();
 6678                    })
 6679                    .ok();
 6680            });
 6681            self.inline_blame_popover_show_task = Some(show_task);
 6682        }
 6683    }
 6684
 6685    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6686        self.inline_blame_popover_show_task.take();
 6687        if let Some(state) = &mut self.inline_blame_popover {
 6688            let hide_task = cx.spawn(async move |editor, cx| {
 6689                cx.background_executor()
 6690                    .timer(std::time::Duration::from_millis(100))
 6691                    .await;
 6692                editor
 6693                    .update(cx, |editor, cx| {
 6694                        editor.inline_blame_popover.take();
 6695                        cx.notify();
 6696                    })
 6697                    .ok();
 6698            });
 6699            state.hide_task = Some(hide_task);
 6700        }
 6701    }
 6702
 6703    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6704        if self.pending_rename.is_some() {
 6705            return None;
 6706        }
 6707
 6708        let provider = self.semantics_provider.clone()?;
 6709        let buffer = self.buffer.read(cx);
 6710        let newest_selection = self.selections.newest_anchor().clone();
 6711        let cursor_position = newest_selection.head();
 6712        let (cursor_buffer, cursor_buffer_position) =
 6713            buffer.text_anchor_for_position(cursor_position, cx)?;
 6714        let (tail_buffer, tail_buffer_position) =
 6715            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6716        if cursor_buffer != tail_buffer {
 6717            return None;
 6718        }
 6719
 6720        let snapshot = cursor_buffer.read(cx).snapshot();
 6721        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6722        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6723        if start_word_range != end_word_range {
 6724            self.document_highlights_task.take();
 6725            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6726            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6727            return None;
 6728        }
 6729
 6730        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6731        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6732            cx.background_executor()
 6733                .timer(Duration::from_millis(debounce))
 6734                .await;
 6735
 6736            let highlights = if let Some(highlights) = cx
 6737                .update(|cx| {
 6738                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6739                })
 6740                .ok()
 6741                .flatten()
 6742            {
 6743                highlights.await.log_err()
 6744            } else {
 6745                None
 6746            };
 6747
 6748            if let Some(highlights) = highlights {
 6749                this.update(cx, |this, cx| {
 6750                    if this.pending_rename.is_some() {
 6751                        return;
 6752                    }
 6753
 6754                    let buffer = this.buffer.read(cx);
 6755                    if buffer
 6756                        .text_anchor_for_position(cursor_position, cx)
 6757                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6758                    {
 6759                        return;
 6760                    }
 6761
 6762                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6763                    let mut write_ranges = Vec::new();
 6764                    let mut read_ranges = Vec::new();
 6765                    for highlight in highlights {
 6766                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6767                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6768                        {
 6769                            let start = highlight
 6770                                .range
 6771                                .start
 6772                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6773                            let end = highlight
 6774                                .range
 6775                                .end
 6776                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6777                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6778                                continue;
 6779                            }
 6780
 6781                            let range = Anchor {
 6782                                buffer_id: Some(buffer_id),
 6783                                excerpt_id,
 6784                                text_anchor: start,
 6785                                diff_base_anchor: None,
 6786                            }..Anchor {
 6787                                buffer_id: Some(buffer_id),
 6788                                excerpt_id,
 6789                                text_anchor: end,
 6790                                diff_base_anchor: None,
 6791                            };
 6792                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6793                                write_ranges.push(range);
 6794                            } else {
 6795                                read_ranges.push(range);
 6796                            }
 6797                        }
 6798                    }
 6799
 6800                    this.highlight_background::<DocumentHighlightRead>(
 6801                        &read_ranges,
 6802                        |theme| theme.colors().editor_document_highlight_read_background,
 6803                        cx,
 6804                    );
 6805                    this.highlight_background::<DocumentHighlightWrite>(
 6806                        &write_ranges,
 6807                        |theme| theme.colors().editor_document_highlight_write_background,
 6808                        cx,
 6809                    );
 6810                    cx.notify();
 6811                })
 6812                .log_err();
 6813            }
 6814        }));
 6815        None
 6816    }
 6817
 6818    fn prepare_highlight_query_from_selection(
 6819        &mut self,
 6820        cx: &mut Context<Editor>,
 6821    ) -> Option<(String, Range<Anchor>)> {
 6822        if matches!(self.mode, EditorMode::SingleLine) {
 6823            return None;
 6824        }
 6825        if !EditorSettings::get_global(cx).selection_highlight {
 6826            return None;
 6827        }
 6828        if self.selections.count() != 1 || self.selections.line_mode {
 6829            return None;
 6830        }
 6831        let selection = self.selections.newest::<Point>(cx);
 6832        if selection.is_empty() || selection.start.row != selection.end.row {
 6833            return None;
 6834        }
 6835        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6836        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6837        let query = multi_buffer_snapshot
 6838            .text_for_range(selection_anchor_range.clone())
 6839            .collect::<String>();
 6840        if query.trim().is_empty() {
 6841            return None;
 6842        }
 6843        Some((query, selection_anchor_range))
 6844    }
 6845
 6846    fn update_selection_occurrence_highlights(
 6847        &mut self,
 6848        query_text: String,
 6849        query_range: Range<Anchor>,
 6850        multi_buffer_range_to_query: Range<Point>,
 6851        use_debounce: bool,
 6852        window: &mut Window,
 6853        cx: &mut Context<Editor>,
 6854    ) -> Task<()> {
 6855        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6856        cx.spawn_in(window, async move |editor, cx| {
 6857            if use_debounce {
 6858                cx.background_executor()
 6859                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6860                    .await;
 6861            }
 6862            let match_task = cx.background_spawn(async move {
 6863                let buffer_ranges = multi_buffer_snapshot
 6864                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6865                    .into_iter()
 6866                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6867                let mut match_ranges = Vec::new();
 6868                let Ok(regex) = project::search::SearchQuery::text(
 6869                    query_text.clone(),
 6870                    false,
 6871                    false,
 6872                    false,
 6873                    Default::default(),
 6874                    Default::default(),
 6875                    false,
 6876                    None,
 6877                ) else {
 6878                    return Vec::default();
 6879                };
 6880                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6881                    match_ranges.extend(
 6882                        regex
 6883                            .search(buffer_snapshot, Some(search_range.clone()))
 6884                            .await
 6885                            .into_iter()
 6886                            .filter_map(|match_range| {
 6887                                let match_start = buffer_snapshot
 6888                                    .anchor_after(search_range.start + match_range.start);
 6889                                let match_end = buffer_snapshot
 6890                                    .anchor_before(search_range.start + match_range.end);
 6891                                let match_anchor_range = Anchor::range_in_buffer(
 6892                                    excerpt_id,
 6893                                    buffer_snapshot.remote_id(),
 6894                                    match_start..match_end,
 6895                                );
 6896                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6897                            }),
 6898                    );
 6899                }
 6900                match_ranges
 6901            });
 6902            let match_ranges = match_task.await;
 6903            editor
 6904                .update_in(cx, |editor, _, cx| {
 6905                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6906                    if !match_ranges.is_empty() {
 6907                        editor.highlight_background::<SelectedTextHighlight>(
 6908                            &match_ranges,
 6909                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6910                            cx,
 6911                        )
 6912                    }
 6913                })
 6914                .log_err();
 6915        })
 6916    }
 6917
 6918    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6919        struct NewlineFold;
 6920        let type_id = std::any::TypeId::of::<NewlineFold>();
 6921        if !self.mode.is_single_line() {
 6922            return;
 6923        }
 6924        let snapshot = self.snapshot(window, cx);
 6925        if snapshot.buffer_snapshot.max_point().row == 0 {
 6926            return;
 6927        }
 6928        let task = cx.background_spawn(async move {
 6929            let new_newlines = snapshot
 6930                .buffer_chars_at(0)
 6931                .filter_map(|(c, i)| {
 6932                    if c == '\n' {
 6933                        Some(
 6934                            snapshot.buffer_snapshot.anchor_after(i)
 6935                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6936                        )
 6937                    } else {
 6938                        None
 6939                    }
 6940                })
 6941                .collect::<Vec<_>>();
 6942            let existing_newlines = snapshot
 6943                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6944                .filter_map(|fold| {
 6945                    if fold.placeholder.type_tag == Some(type_id) {
 6946                        Some(fold.range.start..fold.range.end)
 6947                    } else {
 6948                        None
 6949                    }
 6950                })
 6951                .collect::<Vec<_>>();
 6952
 6953            (new_newlines, existing_newlines)
 6954        });
 6955        self.folding_newlines = cx.spawn(async move |this, cx| {
 6956            let (new_newlines, existing_newlines) = task.await;
 6957            if new_newlines == existing_newlines {
 6958                return;
 6959            }
 6960            let placeholder = FoldPlaceholder {
 6961                render: Arc::new(move |_, _, cx| {
 6962                    div()
 6963                        .bg(cx.theme().status().hint_background)
 6964                        .border_b_1()
 6965                        .size_full()
 6966                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6967                        .border_color(cx.theme().status().hint)
 6968                        .child("\\n")
 6969                        .into_any()
 6970                }),
 6971                constrain_width: false,
 6972                merge_adjacent: false,
 6973                type_tag: Some(type_id),
 6974            };
 6975            let creases = new_newlines
 6976                .into_iter()
 6977                .map(|range| Crease::simple(range, placeholder.clone()))
 6978                .collect();
 6979            this.update(cx, |this, cx| {
 6980                this.display_map.update(cx, |display_map, cx| {
 6981                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6982                    display_map.fold(creases, cx);
 6983                });
 6984            })
 6985            .ok();
 6986        });
 6987    }
 6988
 6989    fn refresh_selected_text_highlights(
 6990        &mut self,
 6991        on_buffer_edit: bool,
 6992        window: &mut Window,
 6993        cx: &mut Context<Editor>,
 6994    ) {
 6995        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6996        else {
 6997            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6998            self.quick_selection_highlight_task.take();
 6999            self.debounced_selection_highlight_task.take();
 7000            return;
 7001        };
 7002        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7003        if on_buffer_edit
 7004            || self
 7005                .quick_selection_highlight_task
 7006                .as_ref()
 7007                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7008        {
 7009            let multi_buffer_visible_start = self
 7010                .scroll_manager
 7011                .anchor()
 7012                .anchor
 7013                .to_point(&multi_buffer_snapshot);
 7014            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7015                multi_buffer_visible_start
 7016                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7017                Bias::Left,
 7018            );
 7019            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7020            self.quick_selection_highlight_task = Some((
 7021                query_range.clone(),
 7022                self.update_selection_occurrence_highlights(
 7023                    query_text.clone(),
 7024                    query_range.clone(),
 7025                    multi_buffer_visible_range,
 7026                    false,
 7027                    window,
 7028                    cx,
 7029                ),
 7030            ));
 7031        }
 7032        if on_buffer_edit
 7033            || self
 7034                .debounced_selection_highlight_task
 7035                .as_ref()
 7036                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7037        {
 7038            let multi_buffer_start = multi_buffer_snapshot
 7039                .anchor_before(0)
 7040                .to_point(&multi_buffer_snapshot);
 7041            let multi_buffer_end = multi_buffer_snapshot
 7042                .anchor_after(multi_buffer_snapshot.len())
 7043                .to_point(&multi_buffer_snapshot);
 7044            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7045            self.debounced_selection_highlight_task = Some((
 7046                query_range.clone(),
 7047                self.update_selection_occurrence_highlights(
 7048                    query_text,
 7049                    query_range,
 7050                    multi_buffer_full_range,
 7051                    true,
 7052                    window,
 7053                    cx,
 7054                ),
 7055            ));
 7056        }
 7057    }
 7058
 7059    pub fn refresh_edit_prediction(
 7060        &mut self,
 7061        debounce: bool,
 7062        user_requested: bool,
 7063        window: &mut Window,
 7064        cx: &mut Context<Self>,
 7065    ) -> Option<()> {
 7066        if DisableAiSettings::get_global(cx).disable_ai {
 7067            return None;
 7068        }
 7069
 7070        let provider = self.edit_prediction_provider()?;
 7071        let cursor = self.selections.newest_anchor().head();
 7072        let (buffer, cursor_buffer_position) =
 7073            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7074
 7075        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7076            self.discard_edit_prediction(false, cx);
 7077            return None;
 7078        }
 7079
 7080        if !user_requested
 7081            && (!self.should_show_edit_predictions()
 7082                || !self.is_focused(window)
 7083                || buffer.read(cx).is_empty())
 7084        {
 7085            self.discard_edit_prediction(false, cx);
 7086            return None;
 7087        }
 7088
 7089        self.update_visible_edit_prediction(window, cx);
 7090        provider.refresh(
 7091            self.project.clone(),
 7092            buffer,
 7093            cursor_buffer_position,
 7094            debounce,
 7095            cx,
 7096        );
 7097        Some(())
 7098    }
 7099
 7100    fn show_edit_predictions_in_menu(&self) -> bool {
 7101        match self.edit_prediction_settings {
 7102            EditPredictionSettings::Disabled => false,
 7103            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7104        }
 7105    }
 7106
 7107    pub fn edit_predictions_enabled(&self) -> bool {
 7108        match self.edit_prediction_settings {
 7109            EditPredictionSettings::Disabled => false,
 7110            EditPredictionSettings::Enabled { .. } => true,
 7111        }
 7112    }
 7113
 7114    fn edit_prediction_requires_modifier(&self) -> bool {
 7115        match self.edit_prediction_settings {
 7116            EditPredictionSettings::Disabled => false,
 7117            EditPredictionSettings::Enabled {
 7118                preview_requires_modifier,
 7119                ..
 7120            } => preview_requires_modifier,
 7121        }
 7122    }
 7123
 7124    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7125        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7126            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7127            self.discard_edit_prediction(false, cx);
 7128        } else {
 7129            let selection = self.selections.newest_anchor();
 7130            let cursor = selection.head();
 7131
 7132            if let Some((buffer, cursor_buffer_position)) =
 7133                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134            {
 7135                self.edit_prediction_settings =
 7136                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7137            }
 7138        }
 7139    }
 7140
 7141    fn edit_prediction_settings_at_position(
 7142        &self,
 7143        buffer: &Entity<Buffer>,
 7144        buffer_position: language::Anchor,
 7145        cx: &App,
 7146    ) -> EditPredictionSettings {
 7147        if !self.mode.is_full()
 7148            || !self.show_edit_predictions_override.unwrap_or(true)
 7149            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7150        {
 7151            return EditPredictionSettings::Disabled;
 7152        }
 7153
 7154        let buffer = buffer.read(cx);
 7155
 7156        let file = buffer.file();
 7157
 7158        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7159            return EditPredictionSettings::Disabled;
 7160        };
 7161
 7162        let by_provider = matches!(
 7163            self.menu_edit_predictions_policy,
 7164            MenuEditPredictionsPolicy::ByProvider
 7165        );
 7166
 7167        let show_in_menu = by_provider
 7168            && self
 7169                .edit_prediction_provider
 7170                .as_ref()
 7171                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7172
 7173        let preview_requires_modifier =
 7174            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7175
 7176        EditPredictionSettings::Enabled {
 7177            show_in_menu,
 7178            preview_requires_modifier,
 7179        }
 7180    }
 7181
 7182    fn should_show_edit_predictions(&self) -> bool {
 7183        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7184    }
 7185
 7186    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7187        matches!(
 7188            self.edit_prediction_preview,
 7189            EditPredictionPreview::Active { .. }
 7190        )
 7191    }
 7192
 7193    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7194        let cursor = self.selections.newest_anchor().head();
 7195        if let Some((buffer, cursor_position)) =
 7196            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7197        {
 7198            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7199        } else {
 7200            false
 7201        }
 7202    }
 7203
 7204    pub fn supports_minimap(&self, cx: &App) -> bool {
 7205        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7206    }
 7207
 7208    fn edit_predictions_enabled_in_buffer(
 7209        &self,
 7210        buffer: &Entity<Buffer>,
 7211        buffer_position: language::Anchor,
 7212        cx: &App,
 7213    ) -> bool {
 7214        maybe!({
 7215            if self.read_only(cx) {
 7216                return Some(false);
 7217            }
 7218            let provider = self.edit_prediction_provider()?;
 7219            if !provider.is_enabled(buffer, buffer_position, cx) {
 7220                return Some(false);
 7221            }
 7222            let buffer = buffer.read(cx);
 7223            let Some(file) = buffer.file() else {
 7224                return Some(true);
 7225            };
 7226            let settings = all_language_settings(Some(file), cx);
 7227            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7228        })
 7229        .unwrap_or(false)
 7230    }
 7231
 7232    fn cycle_edit_prediction(
 7233        &mut self,
 7234        direction: Direction,
 7235        window: &mut Window,
 7236        cx: &mut Context<Self>,
 7237    ) -> Option<()> {
 7238        let provider = self.edit_prediction_provider()?;
 7239        let cursor = self.selections.newest_anchor().head();
 7240        let (buffer, cursor_buffer_position) =
 7241            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7242        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7243            return None;
 7244        }
 7245
 7246        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7247        self.update_visible_edit_prediction(window, cx);
 7248
 7249        Some(())
 7250    }
 7251
 7252    pub fn show_edit_prediction(
 7253        &mut self,
 7254        _: &ShowEditPrediction,
 7255        window: &mut Window,
 7256        cx: &mut Context<Self>,
 7257    ) {
 7258        if !self.has_active_edit_prediction() {
 7259            self.refresh_edit_prediction(false, true, window, cx);
 7260            return;
 7261        }
 7262
 7263        self.update_visible_edit_prediction(window, cx);
 7264    }
 7265
 7266    pub fn display_cursor_names(
 7267        &mut self,
 7268        _: &DisplayCursorNames,
 7269        window: &mut Window,
 7270        cx: &mut Context<Self>,
 7271    ) {
 7272        self.show_cursor_names(window, cx);
 7273    }
 7274
 7275    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7276        self.show_cursor_names = true;
 7277        cx.notify();
 7278        cx.spawn_in(window, async move |this, cx| {
 7279            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7280            this.update(cx, |this, cx| {
 7281                this.show_cursor_names = false;
 7282                cx.notify()
 7283            })
 7284            .ok()
 7285        })
 7286        .detach();
 7287    }
 7288
 7289    pub fn next_edit_prediction(
 7290        &mut self,
 7291        _: &NextEditPrediction,
 7292        window: &mut Window,
 7293        cx: &mut Context<Self>,
 7294    ) {
 7295        if self.has_active_edit_prediction() {
 7296            self.cycle_edit_prediction(Direction::Next, window, cx);
 7297        } else {
 7298            let is_copilot_disabled = self
 7299                .refresh_edit_prediction(false, true, window, cx)
 7300                .is_none();
 7301            if is_copilot_disabled {
 7302                cx.propagate();
 7303            }
 7304        }
 7305    }
 7306
 7307    pub fn previous_edit_prediction(
 7308        &mut self,
 7309        _: &PreviousEditPrediction,
 7310        window: &mut Window,
 7311        cx: &mut Context<Self>,
 7312    ) {
 7313        if self.has_active_edit_prediction() {
 7314            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7315        } else {
 7316            let is_copilot_disabled = self
 7317                .refresh_edit_prediction(false, true, window, cx)
 7318                .is_none();
 7319            if is_copilot_disabled {
 7320                cx.propagate();
 7321            }
 7322        }
 7323    }
 7324
 7325    pub fn accept_edit_prediction(
 7326        &mut self,
 7327        _: &AcceptEditPrediction,
 7328        window: &mut Window,
 7329        cx: &mut Context<Self>,
 7330    ) {
 7331        if self.show_edit_predictions_in_menu() {
 7332            self.hide_context_menu(window, cx);
 7333        }
 7334
 7335        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7336            return;
 7337        };
 7338
 7339        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7340
 7341        match &active_edit_prediction.completion {
 7342            EditPrediction::Move { target, .. } => {
 7343                let target = *target;
 7344
 7345                if let Some(position_map) = &self.last_position_map {
 7346                    if position_map
 7347                        .visible_row_range
 7348                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7349                        || !self.edit_prediction_requires_modifier()
 7350                    {
 7351                        self.unfold_ranges(&[target..target], true, false, cx);
 7352                        // Note that this is also done in vim's handler of the Tab action.
 7353                        self.change_selections(
 7354                            SelectionEffects::scroll(Autoscroll::newest()),
 7355                            window,
 7356                            cx,
 7357                            |selections| {
 7358                                selections.select_anchor_ranges([target..target]);
 7359                            },
 7360                        );
 7361                        self.clear_row_highlights::<EditPredictionPreview>();
 7362
 7363                        self.edit_prediction_preview
 7364                            .set_previous_scroll_position(None);
 7365                    } else {
 7366                        self.edit_prediction_preview
 7367                            .set_previous_scroll_position(Some(
 7368                                position_map.snapshot.scroll_anchor,
 7369                            ));
 7370
 7371                        self.highlight_rows::<EditPredictionPreview>(
 7372                            target..target,
 7373                            cx.theme().colors().editor_highlighted_line_background,
 7374                            RowHighlightOptions {
 7375                                autoscroll: true,
 7376                                ..Default::default()
 7377                            },
 7378                            cx,
 7379                        );
 7380                        self.request_autoscroll(Autoscroll::fit(), cx);
 7381                    }
 7382                }
 7383            }
 7384            EditPrediction::Edit { edits, .. } => {
 7385                if let Some(provider) = self.edit_prediction_provider() {
 7386                    provider.accept(cx);
 7387                }
 7388
 7389                // Store the transaction ID and selections before applying the edit
 7390                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7391
 7392                let snapshot = self.buffer.read(cx).snapshot(cx);
 7393                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7394
 7395                self.buffer.update(cx, |buffer, cx| {
 7396                    buffer.edit(edits.iter().cloned(), None, cx)
 7397                });
 7398
 7399                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7400                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7401                });
 7402
 7403                let selections = self.selections.disjoint_anchors();
 7404                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7405                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7406                    if has_new_transaction {
 7407                        self.selection_history
 7408                            .insert_transaction(transaction_id_now, selections);
 7409                    }
 7410                }
 7411
 7412                self.update_visible_edit_prediction(window, cx);
 7413                if self.active_edit_prediction.is_none() {
 7414                    self.refresh_edit_prediction(true, true, window, cx);
 7415                }
 7416
 7417                cx.notify();
 7418            }
 7419        }
 7420
 7421        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7422    }
 7423
 7424    pub fn accept_partial_edit_prediction(
 7425        &mut self,
 7426        _: &AcceptPartialEditPrediction,
 7427        window: &mut Window,
 7428        cx: &mut Context<Self>,
 7429    ) {
 7430        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7431            return;
 7432        };
 7433        if self.selections.count() != 1 {
 7434            return;
 7435        }
 7436
 7437        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7438
 7439        match &active_edit_prediction.completion {
 7440            EditPrediction::Move { target, .. } => {
 7441                let target = *target;
 7442                self.change_selections(
 7443                    SelectionEffects::scroll(Autoscroll::newest()),
 7444                    window,
 7445                    cx,
 7446                    |selections| {
 7447                        selections.select_anchor_ranges([target..target]);
 7448                    },
 7449                );
 7450            }
 7451            EditPrediction::Edit { edits, .. } => {
 7452                // Find an insertion that starts at the cursor position.
 7453                let snapshot = self.buffer.read(cx).snapshot(cx);
 7454                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7455                let insertion = edits.iter().find_map(|(range, text)| {
 7456                    let range = range.to_offset(&snapshot);
 7457                    if range.is_empty() && range.start == cursor_offset {
 7458                        Some(text)
 7459                    } else {
 7460                        None
 7461                    }
 7462                });
 7463
 7464                if let Some(text) = insertion {
 7465                    let mut partial_completion = text
 7466                        .chars()
 7467                        .by_ref()
 7468                        .take_while(|c| c.is_alphabetic())
 7469                        .collect::<String>();
 7470                    if partial_completion.is_empty() {
 7471                        partial_completion = text
 7472                            .chars()
 7473                            .by_ref()
 7474                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7475                            .collect::<String>();
 7476                    }
 7477
 7478                    cx.emit(EditorEvent::InputHandled {
 7479                        utf16_range_to_replace: None,
 7480                        text: partial_completion.clone().into(),
 7481                    });
 7482
 7483                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7484
 7485                    self.refresh_edit_prediction(true, true, window, cx);
 7486                    cx.notify();
 7487                } else {
 7488                    self.accept_edit_prediction(&Default::default(), window, cx);
 7489                }
 7490            }
 7491        }
 7492    }
 7493
 7494    fn discard_edit_prediction(
 7495        &mut self,
 7496        should_report_edit_prediction_event: bool,
 7497        cx: &mut Context<Self>,
 7498    ) -> bool {
 7499        if should_report_edit_prediction_event {
 7500            let completion_id = self
 7501                .active_edit_prediction
 7502                .as_ref()
 7503                .and_then(|active_completion| active_completion.completion_id.clone());
 7504
 7505            self.report_edit_prediction_event(completion_id, false, cx);
 7506        }
 7507
 7508        if let Some(provider) = self.edit_prediction_provider() {
 7509            provider.discard(cx);
 7510        }
 7511
 7512        self.take_active_edit_prediction(cx)
 7513    }
 7514
 7515    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7516        let Some(provider) = self.edit_prediction_provider() else {
 7517            return;
 7518        };
 7519
 7520        let Some((_, buffer, _)) = self
 7521            .buffer
 7522            .read(cx)
 7523            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7524        else {
 7525            return;
 7526        };
 7527
 7528        let extension = buffer
 7529            .read(cx)
 7530            .file()
 7531            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7532
 7533        let event_type = match accepted {
 7534            true => "Edit Prediction Accepted",
 7535            false => "Edit Prediction Discarded",
 7536        };
 7537        telemetry::event!(
 7538            event_type,
 7539            provider = provider.name(),
 7540            prediction_id = id,
 7541            suggestion_accepted = accepted,
 7542            file_extension = extension,
 7543        );
 7544    }
 7545
 7546    pub fn has_active_edit_prediction(&self) -> bool {
 7547        self.active_edit_prediction.is_some()
 7548    }
 7549
 7550    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7551        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7552            return false;
 7553        };
 7554
 7555        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7556        self.clear_highlights::<EditPredictionHighlight>(cx);
 7557        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7558        true
 7559    }
 7560
 7561    /// Returns true when we're displaying the edit prediction popover below the cursor
 7562    /// like we are not previewing and the LSP autocomplete menu is visible
 7563    /// or we are in `when_holding_modifier` mode.
 7564    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7565        if self.edit_prediction_preview_is_active()
 7566            || !self.show_edit_predictions_in_menu()
 7567            || !self.edit_predictions_enabled()
 7568        {
 7569            return false;
 7570        }
 7571
 7572        if self.has_visible_completions_menu() {
 7573            return true;
 7574        }
 7575
 7576        has_completion && self.edit_prediction_requires_modifier()
 7577    }
 7578
 7579    fn handle_modifiers_changed(
 7580        &mut self,
 7581        modifiers: Modifiers,
 7582        position_map: &PositionMap,
 7583        window: &mut Window,
 7584        cx: &mut Context<Self>,
 7585    ) {
 7586        if self.show_edit_predictions_in_menu() {
 7587            self.update_edit_prediction_preview(&modifiers, window, cx);
 7588        }
 7589
 7590        self.update_selection_mode(&modifiers, position_map, window, cx);
 7591
 7592        let mouse_position = window.mouse_position();
 7593        if !position_map.text_hitbox.is_hovered(window) {
 7594            return;
 7595        }
 7596
 7597        self.update_hovered_link(
 7598            position_map.point_for_position(mouse_position),
 7599            &position_map.snapshot,
 7600            modifiers,
 7601            window,
 7602            cx,
 7603        )
 7604    }
 7605
 7606    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7607        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7608        if invert {
 7609            match multi_cursor_setting {
 7610                MultiCursorModifier::Alt => modifiers.alt,
 7611                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7612            }
 7613        } else {
 7614            match multi_cursor_setting {
 7615                MultiCursorModifier::Alt => modifiers.secondary(),
 7616                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7617            }
 7618        }
 7619    }
 7620
 7621    fn columnar_selection_mode(
 7622        modifiers: &Modifiers,
 7623        cx: &mut Context<Self>,
 7624    ) -> Option<ColumnarMode> {
 7625        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7626            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7627                Some(ColumnarMode::FromMouse)
 7628            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7629                Some(ColumnarMode::FromSelection)
 7630            } else {
 7631                None
 7632            }
 7633        } else {
 7634            None
 7635        }
 7636    }
 7637
 7638    fn update_selection_mode(
 7639        &mut self,
 7640        modifiers: &Modifiers,
 7641        position_map: &PositionMap,
 7642        window: &mut Window,
 7643        cx: &mut Context<Self>,
 7644    ) {
 7645        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7646            return;
 7647        };
 7648        if self.selections.pending.is_none() {
 7649            return;
 7650        }
 7651
 7652        let mouse_position = window.mouse_position();
 7653        let point_for_position = position_map.point_for_position(mouse_position);
 7654        let position = point_for_position.previous_valid;
 7655
 7656        self.select(
 7657            SelectPhase::BeginColumnar {
 7658                position,
 7659                reset: false,
 7660                mode,
 7661                goal_column: point_for_position.exact_unclipped.column(),
 7662            },
 7663            window,
 7664            cx,
 7665        );
 7666    }
 7667
 7668    fn update_edit_prediction_preview(
 7669        &mut self,
 7670        modifiers: &Modifiers,
 7671        window: &mut Window,
 7672        cx: &mut Context<Self>,
 7673    ) {
 7674        let mut modifiers_held = false;
 7675        if let Some(accept_keystroke) = self
 7676            .accept_edit_prediction_keybind(false, window, cx)
 7677            .keystroke()
 7678        {
 7679            modifiers_held = modifiers_held
 7680                || (&accept_keystroke.modifiers == modifiers
 7681                    && accept_keystroke.modifiers.modified());
 7682        };
 7683        if let Some(accept_partial_keystroke) = self
 7684            .accept_edit_prediction_keybind(true, window, cx)
 7685            .keystroke()
 7686        {
 7687            modifiers_held = modifiers_held
 7688                || (&accept_partial_keystroke.modifiers == modifiers
 7689                    && accept_partial_keystroke.modifiers.modified());
 7690        }
 7691
 7692        if modifiers_held {
 7693            if matches!(
 7694                self.edit_prediction_preview,
 7695                EditPredictionPreview::Inactive { .. }
 7696            ) {
 7697                self.edit_prediction_preview = EditPredictionPreview::Active {
 7698                    previous_scroll_position: None,
 7699                    since: Instant::now(),
 7700                };
 7701
 7702                self.update_visible_edit_prediction(window, cx);
 7703                cx.notify();
 7704            }
 7705        } else if let EditPredictionPreview::Active {
 7706            previous_scroll_position,
 7707            since,
 7708        } = self.edit_prediction_preview
 7709        {
 7710            if let (Some(previous_scroll_position), Some(position_map)) =
 7711                (previous_scroll_position, self.last_position_map.as_ref())
 7712            {
 7713                self.set_scroll_position(
 7714                    previous_scroll_position
 7715                        .scroll_position(&position_map.snapshot.display_snapshot),
 7716                    window,
 7717                    cx,
 7718                );
 7719            }
 7720
 7721            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7722                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7723            };
 7724            self.clear_row_highlights::<EditPredictionPreview>();
 7725            self.update_visible_edit_prediction(window, cx);
 7726            cx.notify();
 7727        }
 7728    }
 7729
 7730    fn update_visible_edit_prediction(
 7731        &mut self,
 7732        _window: &mut Window,
 7733        cx: &mut Context<Self>,
 7734    ) -> Option<()> {
 7735        if DisableAiSettings::get_global(cx).disable_ai {
 7736            return None;
 7737        }
 7738
 7739        let selection = self.selections.newest_anchor();
 7740        let cursor = selection.head();
 7741        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7742        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7743        let excerpt_id = cursor.excerpt_id;
 7744
 7745        let show_in_menu = self.show_edit_predictions_in_menu();
 7746        let completions_menu_has_precedence = !show_in_menu
 7747            && (self.context_menu.borrow().is_some()
 7748                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7749
 7750        if completions_menu_has_precedence
 7751            || !offset_selection.is_empty()
 7752            || self
 7753                .active_edit_prediction
 7754                .as_ref()
 7755                .is_some_and(|completion| {
 7756                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7757                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7758                    !invalidation_range.contains(&offset_selection.head())
 7759                })
 7760        {
 7761            self.discard_edit_prediction(false, cx);
 7762            return None;
 7763        }
 7764
 7765        self.take_active_edit_prediction(cx);
 7766        let Some(provider) = self.edit_prediction_provider() else {
 7767            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7768            return None;
 7769        };
 7770
 7771        let (buffer, cursor_buffer_position) =
 7772            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7773
 7774        self.edit_prediction_settings =
 7775            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7776
 7777        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7778            self.discard_edit_prediction(false, cx);
 7779            return None;
 7780        };
 7781
 7782        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7783
 7784        if self.edit_prediction_indent_conflict {
 7785            let cursor_point = cursor.to_point(&multibuffer);
 7786
 7787            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7788
 7789            if let Some((_, indent)) = indents.iter().next()
 7790                && indent.len == cursor_point.column
 7791            {
 7792                self.edit_prediction_indent_conflict = false;
 7793            }
 7794        }
 7795
 7796        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7797        let edits = edit_prediction
 7798            .edits
 7799            .into_iter()
 7800            .flat_map(|(range, new_text)| {
 7801                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7802                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7803                Some((start..end, new_text))
 7804            })
 7805            .collect::<Vec<_>>();
 7806        if edits.is_empty() {
 7807            return None;
 7808        }
 7809
 7810        let first_edit_start = edits.first().unwrap().0.start;
 7811        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7812        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7813
 7814        let last_edit_end = edits.last().unwrap().0.end;
 7815        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7816        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7817
 7818        let cursor_row = cursor.to_point(&multibuffer).row;
 7819
 7820        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7821
 7822        let mut inlay_ids = Vec::new();
 7823        let invalidation_row_range;
 7824        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7825            Some(cursor_row..edit_end_row)
 7826        } else if cursor_row > edit_end_row {
 7827            Some(edit_start_row..cursor_row)
 7828        } else {
 7829            None
 7830        };
 7831        let supports_jump = self
 7832            .edit_prediction_provider
 7833            .as_ref()
 7834            .map(|provider| provider.provider.supports_jump_to_edit())
 7835            .unwrap_or(true);
 7836
 7837        let is_move = supports_jump
 7838            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7839        let completion = if is_move {
 7840            invalidation_row_range =
 7841                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7842            let target = first_edit_start;
 7843            EditPrediction::Move { target, snapshot }
 7844        } else {
 7845            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7846                && !self.edit_predictions_hidden_for_vim_mode;
 7847
 7848            if show_completions_in_buffer {
 7849                if edits
 7850                    .iter()
 7851                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7852                {
 7853                    let mut inlays = Vec::new();
 7854                    for (range, new_text) in &edits {
 7855                        let inlay = Inlay::edit_prediction(
 7856                            post_inc(&mut self.next_inlay_id),
 7857                            range.start,
 7858                            new_text.as_str(),
 7859                        );
 7860                        inlay_ids.push(inlay.id);
 7861                        inlays.push(inlay);
 7862                    }
 7863
 7864                    self.splice_inlays(&[], inlays, cx);
 7865                } else {
 7866                    let background_color = cx.theme().status().deleted_background;
 7867                    self.highlight_text::<EditPredictionHighlight>(
 7868                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7869                        HighlightStyle {
 7870                            background_color: Some(background_color),
 7871                            ..Default::default()
 7872                        },
 7873                        cx,
 7874                    );
 7875                }
 7876            }
 7877
 7878            invalidation_row_range = edit_start_row..edit_end_row;
 7879
 7880            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7881                if provider.show_tab_accept_marker() {
 7882                    EditDisplayMode::TabAccept
 7883                } else {
 7884                    EditDisplayMode::Inline
 7885                }
 7886            } else {
 7887                EditDisplayMode::DiffPopover
 7888            };
 7889
 7890            EditPrediction::Edit {
 7891                edits,
 7892                edit_preview: edit_prediction.edit_preview,
 7893                display_mode,
 7894                snapshot,
 7895            }
 7896        };
 7897
 7898        let invalidation_range = multibuffer
 7899            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7900            ..multibuffer.anchor_after(Point::new(
 7901                invalidation_row_range.end,
 7902                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7903            ));
 7904
 7905        self.stale_edit_prediction_in_menu = None;
 7906        self.active_edit_prediction = Some(EditPredictionState {
 7907            inlay_ids,
 7908            completion,
 7909            completion_id: edit_prediction.id,
 7910            invalidation_range,
 7911        });
 7912
 7913        cx.notify();
 7914
 7915        Some(())
 7916    }
 7917
 7918    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7919        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7920    }
 7921
 7922    fn clear_tasks(&mut self) {
 7923        self.tasks.clear()
 7924    }
 7925
 7926    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7927        if self.tasks.insert(key, value).is_some() {
 7928            // This case should hopefully be rare, but just in case...
 7929            log::error!(
 7930                "multiple different run targets found on a single line, only the last target will be rendered"
 7931            )
 7932        }
 7933    }
 7934
 7935    /// Get all display points of breakpoints that will be rendered within editor
 7936    ///
 7937    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7938    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7939    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7940    fn active_breakpoints(
 7941        &self,
 7942        range: Range<DisplayRow>,
 7943        window: &mut Window,
 7944        cx: &mut Context<Self>,
 7945    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7946        let mut breakpoint_display_points = HashMap::default();
 7947
 7948        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7949            return breakpoint_display_points;
 7950        };
 7951
 7952        let snapshot = self.snapshot(window, cx);
 7953
 7954        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7955        let Some(project) = self.project() else {
 7956            return breakpoint_display_points;
 7957        };
 7958
 7959        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7960            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7961
 7962        for (buffer_snapshot, range, excerpt_id) in
 7963            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7964        {
 7965            let Some(buffer) = project
 7966                .read(cx)
 7967                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7968            else {
 7969                continue;
 7970            };
 7971            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7972                &buffer,
 7973                Some(
 7974                    buffer_snapshot.anchor_before(range.start)
 7975                        ..buffer_snapshot.anchor_after(range.end),
 7976                ),
 7977                buffer_snapshot,
 7978                cx,
 7979            );
 7980            for (breakpoint, state) in breakpoints {
 7981                let multi_buffer_anchor =
 7982                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7983                let position = multi_buffer_anchor
 7984                    .to_point(multi_buffer_snapshot)
 7985                    .to_display_point(&snapshot);
 7986
 7987                breakpoint_display_points.insert(
 7988                    position.row(),
 7989                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7990                );
 7991            }
 7992        }
 7993
 7994        breakpoint_display_points
 7995    }
 7996
 7997    fn breakpoint_context_menu(
 7998        &self,
 7999        anchor: Anchor,
 8000        window: &mut Window,
 8001        cx: &mut Context<Self>,
 8002    ) -> Entity<ui::ContextMenu> {
 8003        let weak_editor = cx.weak_entity();
 8004        let focus_handle = self.focus_handle(cx);
 8005
 8006        let row = self
 8007            .buffer
 8008            .read(cx)
 8009            .snapshot(cx)
 8010            .summary_for_anchor::<Point>(&anchor)
 8011            .row;
 8012
 8013        let breakpoint = self
 8014            .breakpoint_at_row(row, window, cx)
 8015            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8016
 8017        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8018            "Edit Log Breakpoint"
 8019        } else {
 8020            "Set Log Breakpoint"
 8021        };
 8022
 8023        let condition_breakpoint_msg = if breakpoint
 8024            .as_ref()
 8025            .is_some_and(|bp| bp.1.condition.is_some())
 8026        {
 8027            "Edit Condition Breakpoint"
 8028        } else {
 8029            "Set Condition Breakpoint"
 8030        };
 8031
 8032        let hit_condition_breakpoint_msg = if breakpoint
 8033            .as_ref()
 8034            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8035        {
 8036            "Edit Hit Condition Breakpoint"
 8037        } else {
 8038            "Set Hit Condition Breakpoint"
 8039        };
 8040
 8041        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8042            "Unset Breakpoint"
 8043        } else {
 8044            "Set Breakpoint"
 8045        };
 8046
 8047        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8048
 8049        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8050            BreakpointState::Enabled => Some("Disable"),
 8051            BreakpointState::Disabled => Some("Enable"),
 8052        });
 8053
 8054        let (anchor, breakpoint) =
 8055            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8056
 8057        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8058            menu.on_blur_subscription(Subscription::new(|| {}))
 8059                .context(focus_handle)
 8060                .when(run_to_cursor, |this| {
 8061                    let weak_editor = weak_editor.clone();
 8062                    this.entry("Run to cursor", None, move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |editor, cx| {
 8065                                editor.change_selections(
 8066                                    SelectionEffects::no_scroll(),
 8067                                    window,
 8068                                    cx,
 8069                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8070                                );
 8071                            })
 8072                            .ok();
 8073
 8074                        window.dispatch_action(Box::new(RunToCursor), cx);
 8075                    })
 8076                    .separator()
 8077                })
 8078                .when_some(toggle_state_msg, |this, msg| {
 8079                    this.entry(msg, None, {
 8080                        let weak_editor = weak_editor.clone();
 8081                        let breakpoint = breakpoint.clone();
 8082                        move |_window, cx| {
 8083                            weak_editor
 8084                                .update(cx, |this, cx| {
 8085                                    this.edit_breakpoint_at_anchor(
 8086                                        anchor,
 8087                                        breakpoint.as_ref().clone(),
 8088                                        BreakpointEditAction::InvertState,
 8089                                        cx,
 8090                                    );
 8091                                })
 8092                                .log_err();
 8093                        }
 8094                    })
 8095                })
 8096                .entry(set_breakpoint_msg, None, {
 8097                    let weak_editor = weak_editor.clone();
 8098                    let breakpoint = breakpoint.clone();
 8099                    move |_window, cx| {
 8100                        weak_editor
 8101                            .update(cx, |this, cx| {
 8102                                this.edit_breakpoint_at_anchor(
 8103                                    anchor,
 8104                                    breakpoint.as_ref().clone(),
 8105                                    BreakpointEditAction::Toggle,
 8106                                    cx,
 8107                                );
 8108                            })
 8109                            .log_err();
 8110                    }
 8111                })
 8112                .entry(log_breakpoint_msg, None, {
 8113                    let breakpoint = breakpoint.clone();
 8114                    let weak_editor = weak_editor.clone();
 8115                    move |window, cx| {
 8116                        weak_editor
 8117                            .update(cx, |this, cx| {
 8118                                this.add_edit_breakpoint_block(
 8119                                    anchor,
 8120                                    breakpoint.as_ref(),
 8121                                    BreakpointPromptEditAction::Log,
 8122                                    window,
 8123                                    cx,
 8124                                );
 8125                            })
 8126                            .log_err();
 8127                    }
 8128                })
 8129                .entry(condition_breakpoint_msg, None, {
 8130                    let breakpoint = breakpoint.clone();
 8131                    let weak_editor = weak_editor.clone();
 8132                    move |window, cx| {
 8133                        weak_editor
 8134                            .update(cx, |this, cx| {
 8135                                this.add_edit_breakpoint_block(
 8136                                    anchor,
 8137                                    breakpoint.as_ref(),
 8138                                    BreakpointPromptEditAction::Condition,
 8139                                    window,
 8140                                    cx,
 8141                                );
 8142                            })
 8143                            .log_err();
 8144                    }
 8145                })
 8146                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8147                    weak_editor
 8148                        .update(cx, |this, cx| {
 8149                            this.add_edit_breakpoint_block(
 8150                                anchor,
 8151                                breakpoint.as_ref(),
 8152                                BreakpointPromptEditAction::HitCondition,
 8153                                window,
 8154                                cx,
 8155                            );
 8156                        })
 8157                        .log_err();
 8158                })
 8159        })
 8160    }
 8161
 8162    fn render_breakpoint(
 8163        &self,
 8164        position: Anchor,
 8165        row: DisplayRow,
 8166        breakpoint: &Breakpoint,
 8167        state: Option<BreakpointSessionState>,
 8168        cx: &mut Context<Self>,
 8169    ) -> IconButton {
 8170        let is_rejected = state.is_some_and(|s| !s.verified);
 8171        // Is it a breakpoint that shows up when hovering over gutter?
 8172        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8173            (false, false),
 8174            |PhantomBreakpointIndicator {
 8175                 is_active,
 8176                 display_row,
 8177                 collides_with_existing_breakpoint,
 8178             }| {
 8179                (
 8180                    is_active && display_row == row,
 8181                    collides_with_existing_breakpoint,
 8182                )
 8183            },
 8184        );
 8185
 8186        let (color, icon) = {
 8187            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8188                (false, false) => ui::IconName::DebugBreakpoint,
 8189                (true, false) => ui::IconName::DebugLogBreakpoint,
 8190                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8191                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8192            };
 8193
 8194            let color = if is_phantom {
 8195                Color::Hint
 8196            } else if is_rejected {
 8197                Color::Disabled
 8198            } else {
 8199                Color::Debugger
 8200            };
 8201
 8202            (color, icon)
 8203        };
 8204
 8205        let breakpoint = Arc::from(breakpoint.clone());
 8206
 8207        let alt_as_text = gpui::Keystroke {
 8208            modifiers: Modifiers::secondary_key(),
 8209            ..Default::default()
 8210        };
 8211        let primary_action_text = if breakpoint.is_disabled() {
 8212            "Enable breakpoint"
 8213        } else if is_phantom && !collides_with_existing {
 8214            "Set breakpoint"
 8215        } else {
 8216            "Unset breakpoint"
 8217        };
 8218        let focus_handle = self.focus_handle.clone();
 8219
 8220        let meta = if is_rejected {
 8221            SharedString::from("No executable code is associated with this line.")
 8222        } else if collides_with_existing && !breakpoint.is_disabled() {
 8223            SharedString::from(format!(
 8224                "{alt_as_text}-click to disable,\nright-click for more options."
 8225            ))
 8226        } else {
 8227            SharedString::from("Right-click for more options.")
 8228        };
 8229        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8230            .icon_size(IconSize::XSmall)
 8231            .size(ui::ButtonSize::None)
 8232            .when(is_rejected, |this| {
 8233                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8234            })
 8235            .icon_color(color)
 8236            .style(ButtonStyle::Transparent)
 8237            .on_click(cx.listener({
 8238                move |editor, event: &ClickEvent, window, cx| {
 8239                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8240                        BreakpointEditAction::InvertState
 8241                    } else {
 8242                        BreakpointEditAction::Toggle
 8243                    };
 8244
 8245                    window.focus(&editor.focus_handle(cx));
 8246                    editor.edit_breakpoint_at_anchor(
 8247                        position,
 8248                        breakpoint.as_ref().clone(),
 8249                        edit_action,
 8250                        cx,
 8251                    );
 8252                }
 8253            }))
 8254            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8255                editor.set_breakpoint_context_menu(
 8256                    row,
 8257                    Some(position),
 8258                    event.position(),
 8259                    window,
 8260                    cx,
 8261                );
 8262            }))
 8263            .tooltip(move |window, cx| {
 8264                Tooltip::with_meta_in(
 8265                    primary_action_text,
 8266                    Some(&ToggleBreakpoint),
 8267                    meta.clone(),
 8268                    &focus_handle,
 8269                    window,
 8270                    cx,
 8271                )
 8272            })
 8273    }
 8274
 8275    fn build_tasks_context(
 8276        project: &Entity<Project>,
 8277        buffer: &Entity<Buffer>,
 8278        buffer_row: u32,
 8279        tasks: &Arc<RunnableTasks>,
 8280        cx: &mut Context<Self>,
 8281    ) -> Task<Option<task::TaskContext>> {
 8282        let position = Point::new(buffer_row, tasks.column);
 8283        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8284        let location = Location {
 8285            buffer: buffer.clone(),
 8286            range: range_start..range_start,
 8287        };
 8288        // Fill in the environmental variables from the tree-sitter captures
 8289        let mut captured_task_variables = TaskVariables::default();
 8290        for (capture_name, value) in tasks.extra_variables.clone() {
 8291            captured_task_variables.insert(
 8292                task::VariableName::Custom(capture_name.into()),
 8293                value.clone(),
 8294            );
 8295        }
 8296        project.update(cx, |project, cx| {
 8297            project.task_store().update(cx, |task_store, cx| {
 8298                task_store.task_context_for_location(captured_task_variables, location, cx)
 8299            })
 8300        })
 8301    }
 8302
 8303    pub fn spawn_nearest_task(
 8304        &mut self,
 8305        action: &SpawnNearestTask,
 8306        window: &mut Window,
 8307        cx: &mut Context<Self>,
 8308    ) {
 8309        let Some((workspace, _)) = self.workspace.clone() else {
 8310            return;
 8311        };
 8312        let Some(project) = self.project.clone() else {
 8313            return;
 8314        };
 8315
 8316        // Try to find a closest, enclosing node using tree-sitter that has a task
 8317        let Some((buffer, buffer_row, tasks)) = self
 8318            .find_enclosing_node_task(cx)
 8319            // Or find the task that's closest in row-distance.
 8320            .or_else(|| self.find_closest_task(cx))
 8321        else {
 8322            return;
 8323        };
 8324
 8325        let reveal_strategy = action.reveal;
 8326        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8327        cx.spawn_in(window, async move |_, cx| {
 8328            let context = task_context.await?;
 8329            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8330
 8331            let resolved = &mut resolved_task.resolved;
 8332            resolved.reveal = reveal_strategy;
 8333
 8334            workspace
 8335                .update_in(cx, |workspace, window, cx| {
 8336                    workspace.schedule_resolved_task(
 8337                        task_source_kind,
 8338                        resolved_task,
 8339                        false,
 8340                        window,
 8341                        cx,
 8342                    );
 8343                })
 8344                .ok()
 8345        })
 8346        .detach();
 8347    }
 8348
 8349    fn find_closest_task(
 8350        &mut self,
 8351        cx: &mut Context<Self>,
 8352    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8353        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8354
 8355        let ((buffer_id, row), tasks) = self
 8356            .tasks
 8357            .iter()
 8358            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8359
 8360        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8361        let tasks = Arc::new(tasks.to_owned());
 8362        Some((buffer, *row, tasks))
 8363    }
 8364
 8365    fn find_enclosing_node_task(
 8366        &mut self,
 8367        cx: &mut Context<Self>,
 8368    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8369        let snapshot = self.buffer.read(cx).snapshot(cx);
 8370        let offset = self.selections.newest::<usize>(cx).head();
 8371        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8372        let buffer_id = excerpt.buffer().remote_id();
 8373
 8374        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8375        let mut cursor = layer.node().walk();
 8376
 8377        while cursor.goto_first_child_for_byte(offset).is_some() {
 8378            if cursor.node().end_byte() == offset {
 8379                cursor.goto_next_sibling();
 8380            }
 8381        }
 8382
 8383        // Ascend to the smallest ancestor that contains the range and has a task.
 8384        loop {
 8385            let node = cursor.node();
 8386            let node_range = node.byte_range();
 8387            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8388
 8389            // Check if this node contains our offset
 8390            if node_range.start <= offset && node_range.end >= offset {
 8391                // If it contains offset, check for task
 8392                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8393                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8394                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8395                }
 8396            }
 8397
 8398            if !cursor.goto_parent() {
 8399                break;
 8400            }
 8401        }
 8402        None
 8403    }
 8404
 8405    fn render_run_indicator(
 8406        &self,
 8407        _style: &EditorStyle,
 8408        is_active: bool,
 8409        row: DisplayRow,
 8410        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8411        cx: &mut Context<Self>,
 8412    ) -> IconButton {
 8413        let color = Color::Muted;
 8414        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8415
 8416        IconButton::new(
 8417            ("run_indicator", row.0 as usize),
 8418            ui::IconName::PlayOutlined,
 8419        )
 8420        .shape(ui::IconButtonShape::Square)
 8421        .icon_size(IconSize::XSmall)
 8422        .icon_color(color)
 8423        .toggle_state(is_active)
 8424        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8425            let quick_launch = match e {
 8426                ClickEvent::Keyboard(_) => true,
 8427                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8428            };
 8429
 8430            window.focus(&editor.focus_handle(cx));
 8431            editor.toggle_code_actions(
 8432                &ToggleCodeActions {
 8433                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8434                    quick_launch,
 8435                },
 8436                window,
 8437                cx,
 8438            );
 8439        }))
 8440        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8441            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8442        }))
 8443    }
 8444
 8445    pub fn context_menu_visible(&self) -> bool {
 8446        !self.edit_prediction_preview_is_active()
 8447            && self
 8448                .context_menu
 8449                .borrow()
 8450                .as_ref()
 8451                .is_some_and(|menu| menu.visible())
 8452    }
 8453
 8454    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8455        self.context_menu
 8456            .borrow()
 8457            .as_ref()
 8458            .map(|menu| menu.origin())
 8459    }
 8460
 8461    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8462        self.context_menu_options = Some(options);
 8463    }
 8464
 8465    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8466    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8467
 8468    fn render_edit_prediction_popover(
 8469        &mut self,
 8470        text_bounds: &Bounds<Pixels>,
 8471        content_origin: gpui::Point<Pixels>,
 8472        right_margin: Pixels,
 8473        editor_snapshot: &EditorSnapshot,
 8474        visible_row_range: Range<DisplayRow>,
 8475        scroll_top: f32,
 8476        scroll_bottom: f32,
 8477        line_layouts: &[LineWithInvisibles],
 8478        line_height: Pixels,
 8479        scroll_pixel_position: gpui::Point<Pixels>,
 8480        newest_selection_head: Option<DisplayPoint>,
 8481        editor_width: Pixels,
 8482        style: &EditorStyle,
 8483        window: &mut Window,
 8484        cx: &mut App,
 8485    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8486        if self.mode().is_minimap() {
 8487            return None;
 8488        }
 8489        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8490
 8491        if self.edit_prediction_visible_in_cursor_popover(true) {
 8492            return None;
 8493        }
 8494
 8495        match &active_edit_prediction.completion {
 8496            EditPrediction::Move { target, .. } => {
 8497                let target_display_point = target.to_display_point(editor_snapshot);
 8498
 8499                if self.edit_prediction_requires_modifier() {
 8500                    if !self.edit_prediction_preview_is_active() {
 8501                        return None;
 8502                    }
 8503
 8504                    self.render_edit_prediction_modifier_jump_popover(
 8505                        text_bounds,
 8506                        content_origin,
 8507                        visible_row_range,
 8508                        line_layouts,
 8509                        line_height,
 8510                        scroll_pixel_position,
 8511                        newest_selection_head,
 8512                        target_display_point,
 8513                        window,
 8514                        cx,
 8515                    )
 8516                } else {
 8517                    self.render_edit_prediction_eager_jump_popover(
 8518                        text_bounds,
 8519                        content_origin,
 8520                        editor_snapshot,
 8521                        visible_row_range,
 8522                        scroll_top,
 8523                        scroll_bottom,
 8524                        line_height,
 8525                        scroll_pixel_position,
 8526                        target_display_point,
 8527                        editor_width,
 8528                        window,
 8529                        cx,
 8530                    )
 8531                }
 8532            }
 8533            EditPrediction::Edit {
 8534                display_mode: EditDisplayMode::Inline,
 8535                ..
 8536            } => None,
 8537            EditPrediction::Edit {
 8538                display_mode: EditDisplayMode::TabAccept,
 8539                edits,
 8540                ..
 8541            } => {
 8542                let range = &edits.first()?.0;
 8543                let target_display_point = range.end.to_display_point(editor_snapshot);
 8544
 8545                self.render_edit_prediction_end_of_line_popover(
 8546                    "Accept",
 8547                    editor_snapshot,
 8548                    visible_row_range,
 8549                    target_display_point,
 8550                    line_height,
 8551                    scroll_pixel_position,
 8552                    content_origin,
 8553                    editor_width,
 8554                    window,
 8555                    cx,
 8556                )
 8557            }
 8558            EditPrediction::Edit {
 8559                edits,
 8560                edit_preview,
 8561                display_mode: EditDisplayMode::DiffPopover,
 8562                snapshot,
 8563            } => self.render_edit_prediction_diff_popover(
 8564                text_bounds,
 8565                content_origin,
 8566                right_margin,
 8567                editor_snapshot,
 8568                visible_row_range,
 8569                line_layouts,
 8570                line_height,
 8571                scroll_pixel_position,
 8572                newest_selection_head,
 8573                editor_width,
 8574                style,
 8575                edits,
 8576                edit_preview,
 8577                snapshot,
 8578                window,
 8579                cx,
 8580            ),
 8581        }
 8582    }
 8583
 8584    fn render_edit_prediction_modifier_jump_popover(
 8585        &mut self,
 8586        text_bounds: &Bounds<Pixels>,
 8587        content_origin: gpui::Point<Pixels>,
 8588        visible_row_range: Range<DisplayRow>,
 8589        line_layouts: &[LineWithInvisibles],
 8590        line_height: Pixels,
 8591        scroll_pixel_position: gpui::Point<Pixels>,
 8592        newest_selection_head: Option<DisplayPoint>,
 8593        target_display_point: DisplayPoint,
 8594        window: &mut Window,
 8595        cx: &mut App,
 8596    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8597        let scrolled_content_origin =
 8598            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8599
 8600        const SCROLL_PADDING_Y: Pixels = px(12.);
 8601
 8602        if target_display_point.row() < visible_row_range.start {
 8603            return self.render_edit_prediction_scroll_popover(
 8604                |_| SCROLL_PADDING_Y,
 8605                IconName::ArrowUp,
 8606                visible_row_range,
 8607                line_layouts,
 8608                newest_selection_head,
 8609                scrolled_content_origin,
 8610                window,
 8611                cx,
 8612            );
 8613        } else if target_display_point.row() >= visible_row_range.end {
 8614            return self.render_edit_prediction_scroll_popover(
 8615                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8616                IconName::ArrowDown,
 8617                visible_row_range,
 8618                line_layouts,
 8619                newest_selection_head,
 8620                scrolled_content_origin,
 8621                window,
 8622                cx,
 8623            );
 8624        }
 8625
 8626        const POLE_WIDTH: Pixels = px(2.);
 8627
 8628        let line_layout =
 8629            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8630        let target_column = target_display_point.column() as usize;
 8631
 8632        let target_x = line_layout.x_for_index(target_column);
 8633        let target_y =
 8634            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8635
 8636        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8637
 8638        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8639        border_color.l += 0.001;
 8640
 8641        let mut element = v_flex()
 8642            .items_end()
 8643            .when(flag_on_right, |el| el.items_start())
 8644            .child(if flag_on_right {
 8645                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8646                    .rounded_bl(px(0.))
 8647                    .rounded_tl(px(0.))
 8648                    .border_l_2()
 8649                    .border_color(border_color)
 8650            } else {
 8651                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8652                    .rounded_br(px(0.))
 8653                    .rounded_tr(px(0.))
 8654                    .border_r_2()
 8655                    .border_color(border_color)
 8656            })
 8657            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8658            .into_any();
 8659
 8660        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8661
 8662        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8663            - point(
 8664                if flag_on_right {
 8665                    POLE_WIDTH
 8666                } else {
 8667                    size.width - POLE_WIDTH
 8668                },
 8669                size.height - line_height,
 8670            );
 8671
 8672        origin.x = origin.x.max(content_origin.x);
 8673
 8674        element.prepaint_at(origin, window, cx);
 8675
 8676        Some((element, origin))
 8677    }
 8678
 8679    fn render_edit_prediction_scroll_popover(
 8680        &mut self,
 8681        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8682        scroll_icon: IconName,
 8683        visible_row_range: Range<DisplayRow>,
 8684        line_layouts: &[LineWithInvisibles],
 8685        newest_selection_head: Option<DisplayPoint>,
 8686        scrolled_content_origin: gpui::Point<Pixels>,
 8687        window: &mut Window,
 8688        cx: &mut App,
 8689    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8690        let mut element = self
 8691            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8692            .into_any();
 8693
 8694        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8695
 8696        let cursor = newest_selection_head?;
 8697        let cursor_row_layout =
 8698            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8699        let cursor_column = cursor.column() as usize;
 8700
 8701        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8702
 8703        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8704
 8705        element.prepaint_at(origin, window, cx);
 8706        Some((element, origin))
 8707    }
 8708
 8709    fn render_edit_prediction_eager_jump_popover(
 8710        &mut self,
 8711        text_bounds: &Bounds<Pixels>,
 8712        content_origin: gpui::Point<Pixels>,
 8713        editor_snapshot: &EditorSnapshot,
 8714        visible_row_range: Range<DisplayRow>,
 8715        scroll_top: f32,
 8716        scroll_bottom: f32,
 8717        line_height: Pixels,
 8718        scroll_pixel_position: gpui::Point<Pixels>,
 8719        target_display_point: DisplayPoint,
 8720        editor_width: Pixels,
 8721        window: &mut Window,
 8722        cx: &mut App,
 8723    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8724        if target_display_point.row().as_f32() < scroll_top {
 8725            let mut element = self
 8726                .render_edit_prediction_line_popover(
 8727                    "Jump to Edit",
 8728                    Some(IconName::ArrowUp),
 8729                    window,
 8730                    cx,
 8731                )?
 8732                .into_any();
 8733
 8734            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8735            let offset = point(
 8736                (text_bounds.size.width - size.width) / 2.,
 8737                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8738            );
 8739
 8740            let origin = text_bounds.origin + offset;
 8741            element.prepaint_at(origin, window, cx);
 8742            Some((element, origin))
 8743        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8744            let mut element = self
 8745                .render_edit_prediction_line_popover(
 8746                    "Jump to Edit",
 8747                    Some(IconName::ArrowDown),
 8748                    window,
 8749                    cx,
 8750                )?
 8751                .into_any();
 8752
 8753            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8754            let offset = point(
 8755                (text_bounds.size.width - size.width) / 2.,
 8756                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8757            );
 8758
 8759            let origin = text_bounds.origin + offset;
 8760            element.prepaint_at(origin, window, cx);
 8761            Some((element, origin))
 8762        } else {
 8763            self.render_edit_prediction_end_of_line_popover(
 8764                "Jump to Edit",
 8765                editor_snapshot,
 8766                visible_row_range,
 8767                target_display_point,
 8768                line_height,
 8769                scroll_pixel_position,
 8770                content_origin,
 8771                editor_width,
 8772                window,
 8773                cx,
 8774            )
 8775        }
 8776    }
 8777
 8778    fn render_edit_prediction_end_of_line_popover(
 8779        self: &mut Editor,
 8780        label: &'static str,
 8781        editor_snapshot: &EditorSnapshot,
 8782        visible_row_range: Range<DisplayRow>,
 8783        target_display_point: DisplayPoint,
 8784        line_height: Pixels,
 8785        scroll_pixel_position: gpui::Point<Pixels>,
 8786        content_origin: gpui::Point<Pixels>,
 8787        editor_width: Pixels,
 8788        window: &mut Window,
 8789        cx: &mut App,
 8790    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8791        let target_line_end = DisplayPoint::new(
 8792            target_display_point.row(),
 8793            editor_snapshot.line_len(target_display_point.row()),
 8794        );
 8795
 8796        let mut element = self
 8797            .render_edit_prediction_line_popover(label, None, window, cx)?
 8798            .into_any();
 8799
 8800        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8801
 8802        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8803
 8804        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8805        let mut origin = start_point
 8806            + line_origin
 8807            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8808        origin.x = origin.x.max(content_origin.x);
 8809
 8810        let max_x = content_origin.x + editor_width - size.width;
 8811
 8812        if origin.x > max_x {
 8813            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8814
 8815            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8816                origin.y += offset;
 8817                IconName::ArrowUp
 8818            } else {
 8819                origin.y -= offset;
 8820                IconName::ArrowDown
 8821            };
 8822
 8823            element = self
 8824                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8825                .into_any();
 8826
 8827            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8828
 8829            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8830        }
 8831
 8832        element.prepaint_at(origin, window, cx);
 8833        Some((element, origin))
 8834    }
 8835
 8836    fn render_edit_prediction_diff_popover(
 8837        self: &Editor,
 8838        text_bounds: &Bounds<Pixels>,
 8839        content_origin: gpui::Point<Pixels>,
 8840        right_margin: Pixels,
 8841        editor_snapshot: &EditorSnapshot,
 8842        visible_row_range: Range<DisplayRow>,
 8843        line_layouts: &[LineWithInvisibles],
 8844        line_height: Pixels,
 8845        scroll_pixel_position: gpui::Point<Pixels>,
 8846        newest_selection_head: Option<DisplayPoint>,
 8847        editor_width: Pixels,
 8848        style: &EditorStyle,
 8849        edits: &Vec<(Range<Anchor>, String)>,
 8850        edit_preview: &Option<language::EditPreview>,
 8851        snapshot: &language::BufferSnapshot,
 8852        window: &mut Window,
 8853        cx: &mut App,
 8854    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8855        let edit_start = edits
 8856            .first()
 8857            .unwrap()
 8858            .0
 8859            .start
 8860            .to_display_point(editor_snapshot);
 8861        let edit_end = edits
 8862            .last()
 8863            .unwrap()
 8864            .0
 8865            .end
 8866            .to_display_point(editor_snapshot);
 8867
 8868        let is_visible = visible_row_range.contains(&edit_start.row())
 8869            || visible_row_range.contains(&edit_end.row());
 8870        if !is_visible {
 8871            return None;
 8872        }
 8873
 8874        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8875            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8876        } else {
 8877            // Fallback for providers without edit_preview
 8878            crate::edit_prediction_fallback_text(edits, cx)
 8879        };
 8880
 8881        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8882        let line_count = highlighted_edits.text.lines().count();
 8883
 8884        const BORDER_WIDTH: Pixels = px(1.);
 8885
 8886        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8887        let has_keybind = keybind.is_some();
 8888
 8889        let mut element = h_flex()
 8890            .items_start()
 8891            .child(
 8892                h_flex()
 8893                    .bg(cx.theme().colors().editor_background)
 8894                    .border(BORDER_WIDTH)
 8895                    .shadow_xs()
 8896                    .border_color(cx.theme().colors().border)
 8897                    .rounded_l_lg()
 8898                    .when(line_count > 1, |el| el.rounded_br_lg())
 8899                    .pr_1()
 8900                    .child(styled_text),
 8901            )
 8902            .child(
 8903                h_flex()
 8904                    .h(line_height + BORDER_WIDTH * 2.)
 8905                    .px_1p5()
 8906                    .gap_1()
 8907                    // Workaround: For some reason, there's a gap if we don't do this
 8908                    .ml(-BORDER_WIDTH)
 8909                    .shadow(vec![gpui::BoxShadow {
 8910                        color: gpui::black().opacity(0.05),
 8911                        offset: point(px(1.), px(1.)),
 8912                        blur_radius: px(2.),
 8913                        spread_radius: px(0.),
 8914                    }])
 8915                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8916                    .border(BORDER_WIDTH)
 8917                    .border_color(cx.theme().colors().border)
 8918                    .rounded_r_lg()
 8919                    .id("edit_prediction_diff_popover_keybind")
 8920                    .when(!has_keybind, |el| {
 8921                        let status_colors = cx.theme().status();
 8922
 8923                        el.bg(status_colors.error_background)
 8924                            .border_color(status_colors.error.opacity(0.6))
 8925                            .child(Icon::new(IconName::Info).color(Color::Error))
 8926                            .cursor_default()
 8927                            .hoverable_tooltip(move |_window, cx| {
 8928                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8929                            })
 8930                    })
 8931                    .children(keybind),
 8932            )
 8933            .into_any();
 8934
 8935        let longest_row =
 8936            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8937        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8938            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8939        } else {
 8940            layout_line(
 8941                longest_row,
 8942                editor_snapshot,
 8943                style,
 8944                editor_width,
 8945                |_| false,
 8946                window,
 8947                cx,
 8948            )
 8949            .width
 8950        };
 8951
 8952        let viewport_bounds =
 8953            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8954                right: -right_margin,
 8955                ..Default::default()
 8956            });
 8957
 8958        let x_after_longest =
 8959            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8960                - scroll_pixel_position.x;
 8961
 8962        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8963
 8964        // Fully visible if it can be displayed within the window (allow overlapping other
 8965        // panes). However, this is only allowed if the popover starts within text_bounds.
 8966        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8967            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8968
 8969        let mut origin = if can_position_to_the_right {
 8970            point(
 8971                x_after_longest,
 8972                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8973                    - scroll_pixel_position.y,
 8974            )
 8975        } else {
 8976            let cursor_row = newest_selection_head.map(|head| head.row());
 8977            let above_edit = edit_start
 8978                .row()
 8979                .0
 8980                .checked_sub(line_count as u32)
 8981                .map(DisplayRow);
 8982            let below_edit = Some(edit_end.row() + 1);
 8983            let above_cursor =
 8984                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8985            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8986
 8987            // Place the edit popover adjacent to the edit if there is a location
 8988            // available that is onscreen and does not obscure the cursor. Otherwise,
 8989            // place it adjacent to the cursor.
 8990            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8991                .into_iter()
 8992                .flatten()
 8993                .find(|&start_row| {
 8994                    let end_row = start_row + line_count as u32;
 8995                    visible_row_range.contains(&start_row)
 8996                        && visible_row_range.contains(&end_row)
 8997                        && cursor_row
 8998                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 8999                })?;
 9000
 9001            content_origin
 9002                + point(
 9003                    -scroll_pixel_position.x,
 9004                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9005                )
 9006        };
 9007
 9008        origin.x -= BORDER_WIDTH;
 9009
 9010        window.defer_draw(element, origin, 1);
 9011
 9012        // Do not return an element, since it will already be drawn due to defer_draw.
 9013        None
 9014    }
 9015
 9016    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9017        px(30.)
 9018    }
 9019
 9020    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9021        if self.read_only(cx) {
 9022            cx.theme().players().read_only()
 9023        } else {
 9024            self.style.as_ref().unwrap().local_player
 9025        }
 9026    }
 9027
 9028    fn render_edit_prediction_accept_keybind(
 9029        &self,
 9030        window: &mut Window,
 9031        cx: &App,
 9032    ) -> Option<AnyElement> {
 9033        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9034        let accept_keystroke = accept_binding.keystroke()?;
 9035
 9036        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9037
 9038        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 9039            Color::Accent
 9040        } else {
 9041            Color::Muted
 9042        };
 9043
 9044        h_flex()
 9045            .px_0p5()
 9046            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9047            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9048            .text_size(TextSize::XSmall.rems(cx))
 9049            .child(h_flex().children(ui::render_modifiers(
 9050                &accept_keystroke.modifiers,
 9051                PlatformStyle::platform(),
 9052                Some(modifiers_color),
 9053                Some(IconSize::XSmall.rems().into()),
 9054                true,
 9055            )))
 9056            .when(is_platform_style_mac, |parent| {
 9057                parent.child(accept_keystroke.key.clone())
 9058            })
 9059            .when(!is_platform_style_mac, |parent| {
 9060                parent.child(
 9061                    Key::new(
 9062                        util::capitalize(&accept_keystroke.key),
 9063                        Some(Color::Default),
 9064                    )
 9065                    .size(Some(IconSize::XSmall.rems().into())),
 9066                )
 9067            })
 9068            .into_any()
 9069            .into()
 9070    }
 9071
 9072    fn render_edit_prediction_line_popover(
 9073        &self,
 9074        label: impl Into<SharedString>,
 9075        icon: Option<IconName>,
 9076        window: &mut Window,
 9077        cx: &App,
 9078    ) -> Option<Stateful<Div>> {
 9079        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9080
 9081        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9082        let has_keybind = keybind.is_some();
 9083
 9084        let result = h_flex()
 9085            .id("ep-line-popover")
 9086            .py_0p5()
 9087            .pl_1()
 9088            .pr(padding_right)
 9089            .gap_1()
 9090            .rounded_md()
 9091            .border_1()
 9092            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9093            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9094            .shadow_xs()
 9095            .when(!has_keybind, |el| {
 9096                let status_colors = cx.theme().status();
 9097
 9098                el.bg(status_colors.error_background)
 9099                    .border_color(status_colors.error.opacity(0.6))
 9100                    .pl_2()
 9101                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9102                    .cursor_default()
 9103                    .hoverable_tooltip(move |_window, cx| {
 9104                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9105                    })
 9106            })
 9107            .children(keybind)
 9108            .child(
 9109                Label::new(label)
 9110                    .size(LabelSize::Small)
 9111                    .when(!has_keybind, |el| {
 9112                        el.color(cx.theme().status().error.into()).strikethrough()
 9113                    }),
 9114            )
 9115            .when(!has_keybind, |el| {
 9116                el.child(
 9117                    h_flex().ml_1().child(
 9118                        Icon::new(IconName::Info)
 9119                            .size(IconSize::Small)
 9120                            .color(cx.theme().status().error.into()),
 9121                    ),
 9122                )
 9123            })
 9124            .when_some(icon, |element, icon| {
 9125                element.child(
 9126                    div()
 9127                        .mt(px(1.5))
 9128                        .child(Icon::new(icon).size(IconSize::Small)),
 9129                )
 9130            });
 9131
 9132        Some(result)
 9133    }
 9134
 9135    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9136        let accent_color = cx.theme().colors().text_accent;
 9137        let editor_bg_color = cx.theme().colors().editor_background;
 9138        editor_bg_color.blend(accent_color.opacity(0.1))
 9139    }
 9140
 9141    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9142        let accent_color = cx.theme().colors().text_accent;
 9143        let editor_bg_color = cx.theme().colors().editor_background;
 9144        editor_bg_color.blend(accent_color.opacity(0.6))
 9145    }
 9146    fn get_prediction_provider_icon_name(
 9147        provider: &Option<RegisteredEditPredictionProvider>,
 9148    ) -> IconName {
 9149        match provider {
 9150            Some(provider) => match provider.provider.name() {
 9151                "copilot" => IconName::Copilot,
 9152                "supermaven" => IconName::Supermaven,
 9153                _ => IconName::ZedPredict,
 9154            },
 9155            None => IconName::ZedPredict,
 9156        }
 9157    }
 9158
 9159    fn render_edit_prediction_cursor_popover(
 9160        &self,
 9161        min_width: Pixels,
 9162        max_width: Pixels,
 9163        cursor_point: Point,
 9164        style: &EditorStyle,
 9165        accept_keystroke: Option<&gpui::Keystroke>,
 9166        _window: &Window,
 9167        cx: &mut Context<Editor>,
 9168    ) -> Option<AnyElement> {
 9169        let provider = self.edit_prediction_provider.as_ref()?;
 9170        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9171
 9172        if provider.provider.needs_terms_acceptance(cx) {
 9173            return Some(
 9174                h_flex()
 9175                    .min_w(min_width)
 9176                    .flex_1()
 9177                    .px_2()
 9178                    .py_1()
 9179                    .gap_3()
 9180                    .elevation_2(cx)
 9181                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9182                    .id("accept-terms")
 9183                    .cursor_pointer()
 9184                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9185                    .on_click(cx.listener(|this, _event, window, cx| {
 9186                        cx.stop_propagation();
 9187                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9188                        window.dispatch_action(
 9189                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9190                            cx,
 9191                        );
 9192                    }))
 9193                    .child(
 9194                        h_flex()
 9195                            .flex_1()
 9196                            .gap_2()
 9197                            .child(Icon::new(provider_icon))
 9198                            .child(Label::new("Accept Terms of Service"))
 9199                            .child(div().w_full())
 9200                            .child(
 9201                                Icon::new(IconName::ArrowUpRight)
 9202                                    .color(Color::Muted)
 9203                                    .size(IconSize::Small),
 9204                            )
 9205                            .into_any_element(),
 9206                    )
 9207                    .into_any(),
 9208            );
 9209        }
 9210
 9211        let is_refreshing = provider.provider.is_refreshing(cx);
 9212
 9213        fn pending_completion_container(icon: IconName) -> Div {
 9214            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9215        }
 9216
 9217        let completion = match &self.active_edit_prediction {
 9218            Some(prediction) => {
 9219                if !self.has_visible_completions_menu() {
 9220                    const RADIUS: Pixels = px(6.);
 9221                    const BORDER_WIDTH: Pixels = px(1.);
 9222
 9223                    return Some(
 9224                        h_flex()
 9225                            .elevation_2(cx)
 9226                            .border(BORDER_WIDTH)
 9227                            .border_color(cx.theme().colors().border)
 9228                            .when(accept_keystroke.is_none(), |el| {
 9229                                el.border_color(cx.theme().status().error)
 9230                            })
 9231                            .rounded(RADIUS)
 9232                            .rounded_tl(px(0.))
 9233                            .overflow_hidden()
 9234                            .child(div().px_1p5().child(match &prediction.completion {
 9235                                EditPrediction::Move { target, snapshot } => {
 9236                                    use text::ToPoint as _;
 9237                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9238                                    {
 9239                                        Icon::new(IconName::ZedPredictDown)
 9240                                    } else {
 9241                                        Icon::new(IconName::ZedPredictUp)
 9242                                    }
 9243                                }
 9244                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9245                            }))
 9246                            .child(
 9247                                h_flex()
 9248                                    .gap_1()
 9249                                    .py_1()
 9250                                    .px_2()
 9251                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9252                                    .border_l_1()
 9253                                    .border_color(cx.theme().colors().border)
 9254                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9255                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9256                                        el.child(
 9257                                            Label::new("Hold")
 9258                                                .size(LabelSize::Small)
 9259                                                .when(accept_keystroke.is_none(), |el| {
 9260                                                    el.strikethrough()
 9261                                                })
 9262                                                .line_height_style(LineHeightStyle::UiLabel),
 9263                                        )
 9264                                    })
 9265                                    .id("edit_prediction_cursor_popover_keybind")
 9266                                    .when(accept_keystroke.is_none(), |el| {
 9267                                        let status_colors = cx.theme().status();
 9268
 9269                                        el.bg(status_colors.error_background)
 9270                                            .border_color(status_colors.error.opacity(0.6))
 9271                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9272                                            .cursor_default()
 9273                                            .hoverable_tooltip(move |_window, cx| {
 9274                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9275                                                    .into()
 9276                                            })
 9277                                    })
 9278                                    .when_some(
 9279                                        accept_keystroke.as_ref(),
 9280                                        |el, accept_keystroke| {
 9281                                            el.child(h_flex().children(ui::render_modifiers(
 9282                                                &accept_keystroke.modifiers,
 9283                                                PlatformStyle::platform(),
 9284                                                Some(Color::Default),
 9285                                                Some(IconSize::XSmall.rems().into()),
 9286                                                false,
 9287                                            )))
 9288                                        },
 9289                                    ),
 9290                            )
 9291                            .into_any(),
 9292                    );
 9293                }
 9294
 9295                self.render_edit_prediction_cursor_popover_preview(
 9296                    prediction,
 9297                    cursor_point,
 9298                    style,
 9299                    cx,
 9300                )?
 9301            }
 9302
 9303            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9304                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9305                    stale_completion,
 9306                    cursor_point,
 9307                    style,
 9308                    cx,
 9309                )?,
 9310
 9311                None => pending_completion_container(provider_icon)
 9312                    .child(Label::new("...").size(LabelSize::Small)),
 9313            },
 9314
 9315            None => pending_completion_container(provider_icon)
 9316                .child(Label::new("...").size(LabelSize::Small)),
 9317        };
 9318
 9319        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9320            completion
 9321                .with_animation(
 9322                    "loading-completion",
 9323                    Animation::new(Duration::from_secs(2))
 9324                        .repeat()
 9325                        .with_easing(pulsating_between(0.4, 0.8)),
 9326                    |label, delta| label.opacity(delta),
 9327                )
 9328                .into_any_element()
 9329        } else {
 9330            completion.into_any_element()
 9331        };
 9332
 9333        let has_completion = self.active_edit_prediction.is_some();
 9334
 9335        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9336        Some(
 9337            h_flex()
 9338                .min_w(min_width)
 9339                .max_w(max_width)
 9340                .flex_1()
 9341                .elevation_2(cx)
 9342                .border_color(cx.theme().colors().border)
 9343                .child(
 9344                    div()
 9345                        .flex_1()
 9346                        .py_1()
 9347                        .px_2()
 9348                        .overflow_hidden()
 9349                        .child(completion),
 9350                )
 9351                .when_some(accept_keystroke, |el, accept_keystroke| {
 9352                    if !accept_keystroke.modifiers.modified() {
 9353                        return el;
 9354                    }
 9355
 9356                    el.child(
 9357                        h_flex()
 9358                            .h_full()
 9359                            .border_l_1()
 9360                            .rounded_r_lg()
 9361                            .border_color(cx.theme().colors().border)
 9362                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9363                            .gap_1()
 9364                            .py_1()
 9365                            .px_2()
 9366                            .child(
 9367                                h_flex()
 9368                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9369                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9370                                    .child(h_flex().children(ui::render_modifiers(
 9371                                        &accept_keystroke.modifiers,
 9372                                        PlatformStyle::platform(),
 9373                                        Some(if !has_completion {
 9374                                            Color::Muted
 9375                                        } else {
 9376                                            Color::Default
 9377                                        }),
 9378                                        None,
 9379                                        false,
 9380                                    ))),
 9381                            )
 9382                            .child(Label::new("Preview").into_any_element())
 9383                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9384                    )
 9385                })
 9386                .into_any(),
 9387        )
 9388    }
 9389
 9390    fn render_edit_prediction_cursor_popover_preview(
 9391        &self,
 9392        completion: &EditPredictionState,
 9393        cursor_point: Point,
 9394        style: &EditorStyle,
 9395        cx: &mut Context<Editor>,
 9396    ) -> Option<Div> {
 9397        use text::ToPoint as _;
 9398
 9399        fn render_relative_row_jump(
 9400            prefix: impl Into<String>,
 9401            current_row: u32,
 9402            target_row: u32,
 9403        ) -> Div {
 9404            let (row_diff, arrow) = if target_row < current_row {
 9405                (current_row - target_row, IconName::ArrowUp)
 9406            } else {
 9407                (target_row - current_row, IconName::ArrowDown)
 9408            };
 9409
 9410            h_flex()
 9411                .child(
 9412                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9413                        .color(Color::Muted)
 9414                        .size(LabelSize::Small),
 9415                )
 9416                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9417        }
 9418
 9419        let supports_jump = self
 9420            .edit_prediction_provider
 9421            .as_ref()
 9422            .map(|provider| provider.provider.supports_jump_to_edit())
 9423            .unwrap_or(true);
 9424
 9425        match &completion.completion {
 9426            EditPrediction::Move {
 9427                target, snapshot, ..
 9428            } => {
 9429                if !supports_jump {
 9430                    return None;
 9431                }
 9432
 9433                Some(
 9434                    h_flex()
 9435                        .px_2()
 9436                        .gap_2()
 9437                        .flex_1()
 9438                        .child(
 9439                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9440                                Icon::new(IconName::ZedPredictDown)
 9441                            } else {
 9442                                Icon::new(IconName::ZedPredictUp)
 9443                            },
 9444                        )
 9445                        .child(Label::new("Jump to Edit")),
 9446                )
 9447            }
 9448
 9449            EditPrediction::Edit {
 9450                edits,
 9451                edit_preview,
 9452                snapshot,
 9453                display_mode: _,
 9454            } => {
 9455                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9456
 9457                let (highlighted_edits, has_more_lines) =
 9458                    if let Some(edit_preview) = edit_preview.as_ref() {
 9459                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9460                            .first_line_preview()
 9461                    } else {
 9462                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9463                    };
 9464
 9465                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9466                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9467
 9468                let preview = h_flex()
 9469                    .gap_1()
 9470                    .min_w_16()
 9471                    .child(styled_text)
 9472                    .when(has_more_lines, |parent| parent.child(""));
 9473
 9474                let left = if supports_jump && first_edit_row != cursor_point.row {
 9475                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9476                        .into_any_element()
 9477                } else {
 9478                    let icon_name =
 9479                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9480                    Icon::new(icon_name).into_any_element()
 9481                };
 9482
 9483                Some(
 9484                    h_flex()
 9485                        .h_full()
 9486                        .flex_1()
 9487                        .gap_2()
 9488                        .pr_1()
 9489                        .overflow_x_hidden()
 9490                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9491                        .child(left)
 9492                        .child(preview),
 9493                )
 9494            }
 9495        }
 9496    }
 9497
 9498    pub fn render_context_menu(
 9499        &self,
 9500        style: &EditorStyle,
 9501        max_height_in_lines: u32,
 9502        window: &mut Window,
 9503        cx: &mut Context<Editor>,
 9504    ) -> Option<AnyElement> {
 9505        let menu = self.context_menu.borrow();
 9506        let menu = menu.as_ref()?;
 9507        if !menu.visible() {
 9508            return None;
 9509        };
 9510        Some(menu.render(style, max_height_in_lines, window, cx))
 9511    }
 9512
 9513    fn render_context_menu_aside(
 9514        &mut self,
 9515        max_size: Size<Pixels>,
 9516        window: &mut Window,
 9517        cx: &mut Context<Editor>,
 9518    ) -> Option<AnyElement> {
 9519        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9520            if menu.visible() {
 9521                menu.render_aside(max_size, window, cx)
 9522            } else {
 9523                None
 9524            }
 9525        })
 9526    }
 9527
 9528    fn hide_context_menu(
 9529        &mut self,
 9530        window: &mut Window,
 9531        cx: &mut Context<Self>,
 9532    ) -> Option<CodeContextMenu> {
 9533        cx.notify();
 9534        self.completion_tasks.clear();
 9535        let context_menu = self.context_menu.borrow_mut().take();
 9536        self.stale_edit_prediction_in_menu.take();
 9537        self.update_visible_edit_prediction(window, cx);
 9538        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9539            && let Some(completion_provider) = &self.completion_provider
 9540        {
 9541            completion_provider.selection_changed(None, window, cx);
 9542        }
 9543        context_menu
 9544    }
 9545
 9546    fn show_snippet_choices(
 9547        &mut self,
 9548        choices: &Vec<String>,
 9549        selection: Range<Anchor>,
 9550        cx: &mut Context<Self>,
 9551    ) {
 9552        let Some((_, buffer, _)) = self
 9553            .buffer()
 9554            .read(cx)
 9555            .excerpt_containing(selection.start, cx)
 9556        else {
 9557            return;
 9558        };
 9559        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9560        else {
 9561            return;
 9562        };
 9563        if buffer != end_buffer {
 9564            log::error!("expected anchor range to have matching buffer IDs");
 9565            return;
 9566        }
 9567
 9568        let id = post_inc(&mut self.next_completion_id);
 9569        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9570        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9571            CompletionsMenu::new_snippet_choices(
 9572                id,
 9573                true,
 9574                choices,
 9575                selection,
 9576                buffer,
 9577                snippet_sort_order,
 9578            ),
 9579        ));
 9580    }
 9581
 9582    pub fn insert_snippet(
 9583        &mut self,
 9584        insertion_ranges: &[Range<usize>],
 9585        snippet: Snippet,
 9586        window: &mut Window,
 9587        cx: &mut Context<Self>,
 9588    ) -> Result<()> {
 9589        struct Tabstop<T> {
 9590            is_end_tabstop: bool,
 9591            ranges: Vec<Range<T>>,
 9592            choices: Option<Vec<String>>,
 9593        }
 9594
 9595        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9596            let snippet_text: Arc<str> = snippet.text.clone().into();
 9597            let edits = insertion_ranges
 9598                .iter()
 9599                .cloned()
 9600                .map(|range| (range, snippet_text.clone()));
 9601            let autoindent_mode = AutoindentMode::Block {
 9602                original_indent_columns: Vec::new(),
 9603            };
 9604            buffer.edit(edits, Some(autoindent_mode), cx);
 9605
 9606            let snapshot = &*buffer.read(cx);
 9607            let snippet = &snippet;
 9608            snippet
 9609                .tabstops
 9610                .iter()
 9611                .map(|tabstop| {
 9612                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9613                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9614                    });
 9615                    let mut tabstop_ranges = tabstop
 9616                        .ranges
 9617                        .iter()
 9618                        .flat_map(|tabstop_range| {
 9619                            let mut delta = 0_isize;
 9620                            insertion_ranges.iter().map(move |insertion_range| {
 9621                                let insertion_start = insertion_range.start as isize + delta;
 9622                                delta +=
 9623                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9624
 9625                                let start = ((insertion_start + tabstop_range.start) as usize)
 9626                                    .min(snapshot.len());
 9627                                let end = ((insertion_start + tabstop_range.end) as usize)
 9628                                    .min(snapshot.len());
 9629                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9630                            })
 9631                        })
 9632                        .collect::<Vec<_>>();
 9633                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9634
 9635                    Tabstop {
 9636                        is_end_tabstop,
 9637                        ranges: tabstop_ranges,
 9638                        choices: tabstop.choices.clone(),
 9639                    }
 9640                })
 9641                .collect::<Vec<_>>()
 9642        });
 9643        if let Some(tabstop) = tabstops.first() {
 9644            self.change_selections(Default::default(), window, cx, |s| {
 9645                // Reverse order so that the first range is the newest created selection.
 9646                // Completions will use it and autoscroll will prioritize it.
 9647                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9648            });
 9649
 9650            if let Some(choices) = &tabstop.choices
 9651                && let Some(selection) = tabstop.ranges.first()
 9652            {
 9653                self.show_snippet_choices(choices, selection.clone(), cx)
 9654            }
 9655
 9656            // If we're already at the last tabstop and it's at the end of the snippet,
 9657            // we're done, we don't need to keep the state around.
 9658            if !tabstop.is_end_tabstop {
 9659                let choices = tabstops
 9660                    .iter()
 9661                    .map(|tabstop| tabstop.choices.clone())
 9662                    .collect();
 9663
 9664                let ranges = tabstops
 9665                    .into_iter()
 9666                    .map(|tabstop| tabstop.ranges)
 9667                    .collect::<Vec<_>>();
 9668
 9669                self.snippet_stack.push(SnippetState {
 9670                    active_index: 0,
 9671                    ranges,
 9672                    choices,
 9673                });
 9674            }
 9675
 9676            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9677            if self.autoclose_regions.is_empty() {
 9678                let snapshot = self.buffer.read(cx).snapshot(cx);
 9679                let mut all_selections = self.selections.all::<Point>(cx);
 9680                for selection in &mut all_selections {
 9681                    let selection_head = selection.head();
 9682                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9683                        continue;
 9684                    };
 9685
 9686                    let mut bracket_pair = None;
 9687                    let max_lookup_length = scope
 9688                        .brackets()
 9689                        .map(|(pair, _)| {
 9690                            pair.start
 9691                                .as_str()
 9692                                .chars()
 9693                                .count()
 9694                                .max(pair.end.as_str().chars().count())
 9695                        })
 9696                        .max();
 9697                    if let Some(max_lookup_length) = max_lookup_length {
 9698                        let next_text = snapshot
 9699                            .chars_at(selection_head)
 9700                            .take(max_lookup_length)
 9701                            .collect::<String>();
 9702                        let prev_text = snapshot
 9703                            .reversed_chars_at(selection_head)
 9704                            .take(max_lookup_length)
 9705                            .collect::<String>();
 9706
 9707                        for (pair, enabled) in scope.brackets() {
 9708                            if enabled
 9709                                && pair.close
 9710                                && prev_text.starts_with(pair.start.as_str())
 9711                                && next_text.starts_with(pair.end.as_str())
 9712                            {
 9713                                bracket_pair = Some(pair.clone());
 9714                                break;
 9715                            }
 9716                        }
 9717                    }
 9718
 9719                    if let Some(pair) = bracket_pair {
 9720                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9721                        let autoclose_enabled =
 9722                            self.use_autoclose && snapshot_settings.use_autoclose;
 9723                        if autoclose_enabled {
 9724                            let start = snapshot.anchor_after(selection_head);
 9725                            let end = snapshot.anchor_after(selection_head);
 9726                            self.autoclose_regions.push(AutocloseRegion {
 9727                                selection_id: selection.id,
 9728                                range: start..end,
 9729                                pair,
 9730                            });
 9731                        }
 9732                    }
 9733                }
 9734            }
 9735        }
 9736        Ok(())
 9737    }
 9738
 9739    pub fn move_to_next_snippet_tabstop(
 9740        &mut self,
 9741        window: &mut Window,
 9742        cx: &mut Context<Self>,
 9743    ) -> bool {
 9744        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9745    }
 9746
 9747    pub fn move_to_prev_snippet_tabstop(
 9748        &mut self,
 9749        window: &mut Window,
 9750        cx: &mut Context<Self>,
 9751    ) -> bool {
 9752        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9753    }
 9754
 9755    pub fn move_to_snippet_tabstop(
 9756        &mut self,
 9757        bias: Bias,
 9758        window: &mut Window,
 9759        cx: &mut Context<Self>,
 9760    ) -> bool {
 9761        if let Some(mut snippet) = self.snippet_stack.pop() {
 9762            match bias {
 9763                Bias::Left => {
 9764                    if snippet.active_index > 0 {
 9765                        snippet.active_index -= 1;
 9766                    } else {
 9767                        self.snippet_stack.push(snippet);
 9768                        return false;
 9769                    }
 9770                }
 9771                Bias::Right => {
 9772                    if snippet.active_index + 1 < snippet.ranges.len() {
 9773                        snippet.active_index += 1;
 9774                    } else {
 9775                        self.snippet_stack.push(snippet);
 9776                        return false;
 9777                    }
 9778                }
 9779            }
 9780            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9781                self.change_selections(Default::default(), window, cx, |s| {
 9782                    // Reverse order so that the first range is the newest created selection.
 9783                    // Completions will use it and autoscroll will prioritize it.
 9784                    s.select_ranges(current_ranges.iter().rev().cloned())
 9785                });
 9786
 9787                if let Some(choices) = &snippet.choices[snippet.active_index]
 9788                    && let Some(selection) = current_ranges.first()
 9789                {
 9790                    self.show_snippet_choices(choices, selection.clone(), cx);
 9791                }
 9792
 9793                // If snippet state is not at the last tabstop, push it back on the stack
 9794                if snippet.active_index + 1 < snippet.ranges.len() {
 9795                    self.snippet_stack.push(snippet);
 9796                }
 9797                return true;
 9798            }
 9799        }
 9800
 9801        false
 9802    }
 9803
 9804    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9805        self.transact(window, cx, |this, window, cx| {
 9806            this.select_all(&SelectAll, window, cx);
 9807            this.insert("", window, cx);
 9808        });
 9809    }
 9810
 9811    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9812        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9813        self.transact(window, cx, |this, window, cx| {
 9814            this.select_autoclose_pair(window, cx);
 9815            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9816            if !this.linked_edit_ranges.is_empty() {
 9817                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9818                let snapshot = this.buffer.read(cx).snapshot(cx);
 9819
 9820                for selection in selections.iter() {
 9821                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9822                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9823                    if selection_start.buffer_id != selection_end.buffer_id {
 9824                        continue;
 9825                    }
 9826                    if let Some(ranges) =
 9827                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9828                    {
 9829                        for (buffer, entries) in ranges {
 9830                            linked_ranges.entry(buffer).or_default().extend(entries);
 9831                        }
 9832                    }
 9833                }
 9834            }
 9835
 9836            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9837            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9838            for selection in &mut selections {
 9839                if selection.is_empty() {
 9840                    let old_head = selection.head();
 9841                    let mut new_head =
 9842                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9843                            .to_point(&display_map);
 9844                    if let Some((buffer, line_buffer_range)) = display_map
 9845                        .buffer_snapshot
 9846                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9847                    {
 9848                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9849                        let indent_len = match indent_size.kind {
 9850                            IndentKind::Space => {
 9851                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9852                            }
 9853                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9854                        };
 9855                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9856                            let indent_len = indent_len.get();
 9857                            new_head = cmp::min(
 9858                                new_head,
 9859                                MultiBufferPoint::new(
 9860                                    old_head.row,
 9861                                    ((old_head.column - 1) / indent_len) * indent_len,
 9862                                ),
 9863                            );
 9864                        }
 9865                    }
 9866
 9867                    selection.set_head(new_head, SelectionGoal::None);
 9868                }
 9869            }
 9870
 9871            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9872            this.insert("", window, cx);
 9873            let empty_str: Arc<str> = Arc::from("");
 9874            for (buffer, edits) in linked_ranges {
 9875                let snapshot = buffer.read(cx).snapshot();
 9876                use text::ToPoint as TP;
 9877
 9878                let edits = edits
 9879                    .into_iter()
 9880                    .map(|range| {
 9881                        let end_point = TP::to_point(&range.end, &snapshot);
 9882                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9883
 9884                        if end_point == start_point {
 9885                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9886                                .saturating_sub(1);
 9887                            start_point =
 9888                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9889                        };
 9890
 9891                        (start_point..end_point, empty_str.clone())
 9892                    })
 9893                    .sorted_by_key(|(range, _)| range.start)
 9894                    .collect::<Vec<_>>();
 9895                buffer.update(cx, |this, cx| {
 9896                    this.edit(edits, None, cx);
 9897                })
 9898            }
 9899            this.refresh_edit_prediction(true, false, window, cx);
 9900            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9901        });
 9902    }
 9903
 9904    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9905        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9906        self.transact(window, cx, |this, window, cx| {
 9907            this.change_selections(Default::default(), window, cx, |s| {
 9908                s.move_with(|map, selection| {
 9909                    if selection.is_empty() {
 9910                        let cursor = movement::right(map, selection.head());
 9911                        selection.end = cursor;
 9912                        selection.reversed = true;
 9913                        selection.goal = SelectionGoal::None;
 9914                    }
 9915                })
 9916            });
 9917            this.insert("", window, cx);
 9918            this.refresh_edit_prediction(true, false, window, cx);
 9919        });
 9920    }
 9921
 9922    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9923        if self.mode.is_single_line() {
 9924            cx.propagate();
 9925            return;
 9926        }
 9927
 9928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9929        if self.move_to_prev_snippet_tabstop(window, cx) {
 9930            return;
 9931        }
 9932        self.outdent(&Outdent, window, cx);
 9933    }
 9934
 9935    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9936        if self.mode.is_single_line() {
 9937            cx.propagate();
 9938            return;
 9939        }
 9940
 9941        if self.move_to_next_snippet_tabstop(window, cx) {
 9942            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9943            return;
 9944        }
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        let mut selections = self.selections.all_adjusted(cx);
 9950        let buffer = self.buffer.read(cx);
 9951        let snapshot = buffer.snapshot(cx);
 9952        let rows_iter = selections.iter().map(|s| s.head().row);
 9953        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9954
 9955        let has_some_cursor_in_whitespace = selections
 9956            .iter()
 9957            .filter(|selection| selection.is_empty())
 9958            .any(|selection| {
 9959                let cursor = selection.head();
 9960                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9961                cursor.column < current_indent.len
 9962            });
 9963
 9964        let mut edits = Vec::new();
 9965        let mut prev_edited_row = 0;
 9966        let mut row_delta = 0;
 9967        for selection in &mut selections {
 9968            if selection.start.row != prev_edited_row {
 9969                row_delta = 0;
 9970            }
 9971            prev_edited_row = selection.end.row;
 9972
 9973            // If the selection is non-empty, then increase the indentation of the selected lines.
 9974            if !selection.is_empty() {
 9975                row_delta =
 9976                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9977                continue;
 9978            }
 9979
 9980            let cursor = selection.head();
 9981            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9982            if let Some(suggested_indent) =
 9983                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9984            {
 9985                // Don't do anything if already at suggested indent
 9986                // and there is any other cursor which is not
 9987                if has_some_cursor_in_whitespace
 9988                    && cursor.column == current_indent.len
 9989                    && current_indent.len == suggested_indent.len
 9990                {
 9991                    continue;
 9992                }
 9993
 9994                // Adjust line and move cursor to suggested indent
 9995                // if cursor is not at suggested indent
 9996                if cursor.column < suggested_indent.len
 9997                    && cursor.column <= current_indent.len
 9998                    && current_indent.len <= suggested_indent.len
 9999                {
10000                    selection.start = Point::new(cursor.row, suggested_indent.len);
10001                    selection.end = selection.start;
10002                    if row_delta == 0 {
10003                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10004                            cursor.row,
10005                            current_indent,
10006                            suggested_indent,
10007                        ));
10008                        row_delta = suggested_indent.len - current_indent.len;
10009                    }
10010                    continue;
10011                }
10012
10013                // If current indent is more than suggested indent
10014                // only move cursor to current indent and skip indent
10015                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10016                    selection.start = Point::new(cursor.row, current_indent.len);
10017                    selection.end = selection.start;
10018                    continue;
10019                }
10020            }
10021
10022            // Otherwise, insert a hard or soft tab.
10023            let settings = buffer.language_settings_at(cursor, cx);
10024            let tab_size = if settings.hard_tabs {
10025                IndentSize::tab()
10026            } else {
10027                let tab_size = settings.tab_size.get();
10028                let indent_remainder = snapshot
10029                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10030                    .flat_map(str::chars)
10031                    .fold(row_delta % tab_size, |counter: u32, c| {
10032                        if c == '\t' {
10033                            0
10034                        } else {
10035                            (counter + 1) % tab_size
10036                        }
10037                    });
10038
10039                let chars_to_next_tab_stop = tab_size - indent_remainder;
10040                IndentSize::spaces(chars_to_next_tab_stop)
10041            };
10042            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10043            selection.end = selection.start;
10044            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10045            row_delta += tab_size.len;
10046        }
10047
10048        self.transact(window, cx, |this, window, cx| {
10049            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10050            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10051            this.refresh_edit_prediction(true, false, window, cx);
10052        });
10053    }
10054
10055    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10056        if self.read_only(cx) {
10057            return;
10058        }
10059        if self.mode.is_single_line() {
10060            cx.propagate();
10061            return;
10062        }
10063
10064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10065        let mut selections = self.selections.all::<Point>(cx);
10066        let mut prev_edited_row = 0;
10067        let mut row_delta = 0;
10068        let mut edits = Vec::new();
10069        let buffer = self.buffer.read(cx);
10070        let snapshot = buffer.snapshot(cx);
10071        for selection in &mut selections {
10072            if selection.start.row != prev_edited_row {
10073                row_delta = 0;
10074            }
10075            prev_edited_row = selection.end.row;
10076
10077            row_delta =
10078                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10079        }
10080
10081        self.transact(window, cx, |this, window, cx| {
10082            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10083            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10084        });
10085    }
10086
10087    fn indent_selection(
10088        buffer: &MultiBuffer,
10089        snapshot: &MultiBufferSnapshot,
10090        selection: &mut Selection<Point>,
10091        edits: &mut Vec<(Range<Point>, String)>,
10092        delta_for_start_row: u32,
10093        cx: &App,
10094    ) -> u32 {
10095        let settings = buffer.language_settings_at(selection.start, cx);
10096        let tab_size = settings.tab_size.get();
10097        let indent_kind = if settings.hard_tabs {
10098            IndentKind::Tab
10099        } else {
10100            IndentKind::Space
10101        };
10102        let mut start_row = selection.start.row;
10103        let mut end_row = selection.end.row + 1;
10104
10105        // If a selection ends at the beginning of a line, don't indent
10106        // that last line.
10107        if selection.end.column == 0 && selection.end.row > selection.start.row {
10108            end_row -= 1;
10109        }
10110
10111        // Avoid re-indenting a row that has already been indented by a
10112        // previous selection, but still update this selection's column
10113        // to reflect that indentation.
10114        if delta_for_start_row > 0 {
10115            start_row += 1;
10116            selection.start.column += delta_for_start_row;
10117            if selection.end.row == selection.start.row {
10118                selection.end.column += delta_for_start_row;
10119            }
10120        }
10121
10122        let mut delta_for_end_row = 0;
10123        let has_multiple_rows = start_row + 1 != end_row;
10124        for row in start_row..end_row {
10125            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10126            let indent_delta = match (current_indent.kind, indent_kind) {
10127                (IndentKind::Space, IndentKind::Space) => {
10128                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10129                    IndentSize::spaces(columns_to_next_tab_stop)
10130                }
10131                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10132                (_, IndentKind::Tab) => IndentSize::tab(),
10133            };
10134
10135            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10136                0
10137            } else {
10138                selection.start.column
10139            };
10140            let row_start = Point::new(row, start);
10141            edits.push((
10142                row_start..row_start,
10143                indent_delta.chars().collect::<String>(),
10144            ));
10145
10146            // Update this selection's endpoints to reflect the indentation.
10147            if row == selection.start.row {
10148                selection.start.column += indent_delta.len;
10149            }
10150            if row == selection.end.row {
10151                selection.end.column += indent_delta.len;
10152                delta_for_end_row = indent_delta.len;
10153            }
10154        }
10155
10156        if selection.start.row == selection.end.row {
10157            delta_for_start_row + delta_for_end_row
10158        } else {
10159            delta_for_end_row
10160        }
10161    }
10162
10163    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10164        if self.read_only(cx) {
10165            return;
10166        }
10167        if self.mode.is_single_line() {
10168            cx.propagate();
10169            return;
10170        }
10171
10172        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10174        let selections = self.selections.all::<Point>(cx);
10175        let mut deletion_ranges = Vec::new();
10176        let mut last_outdent = None;
10177        {
10178            let buffer = self.buffer.read(cx);
10179            let snapshot = buffer.snapshot(cx);
10180            for selection in &selections {
10181                let settings = buffer.language_settings_at(selection.start, cx);
10182                let tab_size = settings.tab_size.get();
10183                let mut rows = selection.spanned_rows(false, &display_map);
10184
10185                // Avoid re-outdenting a row that has already been outdented by a
10186                // previous selection.
10187                if let Some(last_row) = last_outdent
10188                    && last_row == rows.start
10189                {
10190                    rows.start = rows.start.next_row();
10191                }
10192                let has_multiple_rows = rows.len() > 1;
10193                for row in rows.iter_rows() {
10194                    let indent_size = snapshot.indent_size_for_line(row);
10195                    if indent_size.len > 0 {
10196                        let deletion_len = match indent_size.kind {
10197                            IndentKind::Space => {
10198                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10199                                if columns_to_prev_tab_stop == 0 {
10200                                    tab_size
10201                                } else {
10202                                    columns_to_prev_tab_stop
10203                                }
10204                            }
10205                            IndentKind::Tab => 1,
10206                        };
10207                        let start = if has_multiple_rows
10208                            || deletion_len > selection.start.column
10209                            || indent_size.len < selection.start.column
10210                        {
10211                            0
10212                        } else {
10213                            selection.start.column - deletion_len
10214                        };
10215                        deletion_ranges.push(
10216                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10217                        );
10218                        last_outdent = Some(row);
10219                    }
10220                }
10221            }
10222        }
10223
10224        self.transact(window, cx, |this, window, cx| {
10225            this.buffer.update(cx, |buffer, cx| {
10226                let empty_str: Arc<str> = Arc::default();
10227                buffer.edit(
10228                    deletion_ranges
10229                        .into_iter()
10230                        .map(|range| (range, empty_str.clone())),
10231                    None,
10232                    cx,
10233                );
10234            });
10235            let selections = this.selections.all::<usize>(cx);
10236            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10237        });
10238    }
10239
10240    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10241        if self.read_only(cx) {
10242            return;
10243        }
10244        if self.mode.is_single_line() {
10245            cx.propagate();
10246            return;
10247        }
10248
10249        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10250        let selections = self
10251            .selections
10252            .all::<usize>(cx)
10253            .into_iter()
10254            .map(|s| s.range());
10255
10256        self.transact(window, cx, |this, window, cx| {
10257            this.buffer.update(cx, |buffer, cx| {
10258                buffer.autoindent_ranges(selections, cx);
10259            });
10260            let selections = this.selections.all::<usize>(cx);
10261            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10262        });
10263    }
10264
10265    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10267        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10268        let selections = self.selections.all::<Point>(cx);
10269
10270        let mut new_cursors = Vec::new();
10271        let mut edit_ranges = Vec::new();
10272        let mut selections = selections.iter().peekable();
10273        while let Some(selection) = selections.next() {
10274            let mut rows = selection.spanned_rows(false, &display_map);
10275            let goal_display_column = selection.head().to_display_point(&display_map).column();
10276
10277            // Accumulate contiguous regions of rows that we want to delete.
10278            while let Some(next_selection) = selections.peek() {
10279                let next_rows = next_selection.spanned_rows(false, &display_map);
10280                if next_rows.start <= rows.end {
10281                    rows.end = next_rows.end;
10282                    selections.next().unwrap();
10283                } else {
10284                    break;
10285                }
10286            }
10287
10288            let buffer = &display_map.buffer_snapshot;
10289            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10290            let edit_end;
10291            let cursor_buffer_row;
10292            if buffer.max_point().row >= rows.end.0 {
10293                // If there's a line after the range, delete the \n from the end of the row range
10294                // and position the cursor on the next line.
10295                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10296                cursor_buffer_row = rows.end;
10297            } else {
10298                // If there isn't a line after the range, delete the \n from the line before the
10299                // start of the row range and position the cursor there.
10300                edit_start = edit_start.saturating_sub(1);
10301                edit_end = buffer.len();
10302                cursor_buffer_row = rows.start.previous_row();
10303            }
10304
10305            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10306            *cursor.column_mut() =
10307                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10308
10309            new_cursors.push((
10310                selection.id,
10311                buffer.anchor_after(cursor.to_point(&display_map)),
10312            ));
10313            edit_ranges.push(edit_start..edit_end);
10314        }
10315
10316        self.transact(window, cx, |this, window, cx| {
10317            let buffer = this.buffer.update(cx, |buffer, cx| {
10318                let empty_str: Arc<str> = Arc::default();
10319                buffer.edit(
10320                    edit_ranges
10321                        .into_iter()
10322                        .map(|range| (range, empty_str.clone())),
10323                    None,
10324                    cx,
10325                );
10326                buffer.snapshot(cx)
10327            });
10328            let new_selections = new_cursors
10329                .into_iter()
10330                .map(|(id, cursor)| {
10331                    let cursor = cursor.to_point(&buffer);
10332                    Selection {
10333                        id,
10334                        start: cursor,
10335                        end: cursor,
10336                        reversed: false,
10337                        goal: SelectionGoal::None,
10338                    }
10339                })
10340                .collect();
10341
10342            this.change_selections(Default::default(), window, cx, |s| {
10343                s.select(new_selections);
10344            });
10345        });
10346    }
10347
10348    pub fn join_lines_impl(
10349        &mut self,
10350        insert_whitespace: bool,
10351        window: &mut Window,
10352        cx: &mut Context<Self>,
10353    ) {
10354        if self.read_only(cx) {
10355            return;
10356        }
10357        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10358        for selection in self.selections.all::<Point>(cx) {
10359            let start = MultiBufferRow(selection.start.row);
10360            // Treat single line selections as if they include the next line. Otherwise this action
10361            // would do nothing for single line selections individual cursors.
10362            let end = if selection.start.row == selection.end.row {
10363                MultiBufferRow(selection.start.row + 1)
10364            } else {
10365                MultiBufferRow(selection.end.row)
10366            };
10367
10368            if let Some(last_row_range) = row_ranges.last_mut()
10369                && start <= last_row_range.end
10370            {
10371                last_row_range.end = end;
10372                continue;
10373            }
10374            row_ranges.push(start..end);
10375        }
10376
10377        let snapshot = self.buffer.read(cx).snapshot(cx);
10378        let mut cursor_positions = Vec::new();
10379        for row_range in &row_ranges {
10380            let anchor = snapshot.anchor_before(Point::new(
10381                row_range.end.previous_row().0,
10382                snapshot.line_len(row_range.end.previous_row()),
10383            ));
10384            cursor_positions.push(anchor..anchor);
10385        }
10386
10387        self.transact(window, cx, |this, window, cx| {
10388            for row_range in row_ranges.into_iter().rev() {
10389                for row in row_range.iter_rows().rev() {
10390                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10391                    let next_line_row = row.next_row();
10392                    let indent = snapshot.indent_size_for_line(next_line_row);
10393                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10394
10395                    let replace =
10396                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10397                            " "
10398                        } else {
10399                            ""
10400                        };
10401
10402                    this.buffer.update(cx, |buffer, cx| {
10403                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10404                    });
10405                }
10406            }
10407
10408            this.change_selections(Default::default(), window, cx, |s| {
10409                s.select_anchor_ranges(cursor_positions)
10410            });
10411        });
10412    }
10413
10414    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10415        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10416        self.join_lines_impl(true, window, cx);
10417    }
10418
10419    pub fn sort_lines_case_sensitive(
10420        &mut self,
10421        _: &SortLinesCaseSensitive,
10422        window: &mut Window,
10423        cx: &mut Context<Self>,
10424    ) {
10425        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10426    }
10427
10428    pub fn sort_lines_by_length(
10429        &mut self,
10430        _: &SortLinesByLength,
10431        window: &mut Window,
10432        cx: &mut Context<Self>,
10433    ) {
10434        self.manipulate_immutable_lines(window, cx, |lines| {
10435            lines.sort_by_key(|&line| line.chars().count())
10436        })
10437    }
10438
10439    pub fn sort_lines_case_insensitive(
10440        &mut self,
10441        _: &SortLinesCaseInsensitive,
10442        window: &mut Window,
10443        cx: &mut Context<Self>,
10444    ) {
10445        self.manipulate_immutable_lines(window, cx, |lines| {
10446            lines.sort_by_key(|line| line.to_lowercase())
10447        })
10448    }
10449
10450    pub fn unique_lines_case_insensitive(
10451        &mut self,
10452        _: &UniqueLinesCaseInsensitive,
10453        window: &mut Window,
10454        cx: &mut Context<Self>,
10455    ) {
10456        self.manipulate_immutable_lines(window, cx, |lines| {
10457            let mut seen = HashSet::default();
10458            lines.retain(|line| seen.insert(line.to_lowercase()));
10459        })
10460    }
10461
10462    pub fn unique_lines_case_sensitive(
10463        &mut self,
10464        _: &UniqueLinesCaseSensitive,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_immutable_lines(window, cx, |lines| {
10469            let mut seen = HashSet::default();
10470            lines.retain(|line| seen.insert(*line));
10471        })
10472    }
10473
10474    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10475        let Some(project) = self.project.clone() else {
10476            return;
10477        };
10478        self.reload(project, window, cx)
10479            .detach_and_notify_err(window, cx);
10480    }
10481
10482    pub fn restore_file(
10483        &mut self,
10484        _: &::git::RestoreFile,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10489        let mut buffer_ids = HashSet::default();
10490        let snapshot = self.buffer().read(cx).snapshot(cx);
10491        for selection in self.selections.all::<usize>(cx) {
10492            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10493        }
10494
10495        let buffer = self.buffer().read(cx);
10496        let ranges = buffer_ids
10497            .into_iter()
10498            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10499            .collect::<Vec<_>>();
10500
10501        self.restore_hunks_in_ranges(ranges, window, cx);
10502    }
10503
10504    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10505        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10506        let selections = self
10507            .selections
10508            .all(cx)
10509            .into_iter()
10510            .map(|s| s.range())
10511            .collect();
10512        self.restore_hunks_in_ranges(selections, window, cx);
10513    }
10514
10515    pub fn restore_hunks_in_ranges(
10516        &mut self,
10517        ranges: Vec<Range<Point>>,
10518        window: &mut Window,
10519        cx: &mut Context<Editor>,
10520    ) {
10521        let mut revert_changes = HashMap::default();
10522        let chunk_by = self
10523            .snapshot(window, cx)
10524            .hunks_for_ranges(ranges)
10525            .into_iter()
10526            .chunk_by(|hunk| hunk.buffer_id);
10527        for (buffer_id, hunks) in &chunk_by {
10528            let hunks = hunks.collect::<Vec<_>>();
10529            for hunk in &hunks {
10530                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10531            }
10532            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10533        }
10534        drop(chunk_by);
10535        if !revert_changes.is_empty() {
10536            self.transact(window, cx, |editor, window, cx| {
10537                editor.restore(revert_changes, window, cx);
10538            });
10539        }
10540    }
10541
10542    pub fn open_active_item_in_terminal(
10543        &mut self,
10544        _: &OpenInTerminal,
10545        window: &mut Window,
10546        cx: &mut Context<Self>,
10547    ) {
10548        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10549            let project_path = buffer.read(cx).project_path(cx)?;
10550            let project = self.project()?.read(cx);
10551            let entry = project.entry_for_path(&project_path, cx)?;
10552            let parent = match &entry.canonical_path {
10553                Some(canonical_path) => canonical_path.to_path_buf(),
10554                None => project.absolute_path(&project_path, cx)?,
10555            }
10556            .parent()?
10557            .to_path_buf();
10558            Some(parent)
10559        }) {
10560            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10561        }
10562    }
10563
10564    fn set_breakpoint_context_menu(
10565        &mut self,
10566        display_row: DisplayRow,
10567        position: Option<Anchor>,
10568        clicked_point: gpui::Point<Pixels>,
10569        window: &mut Window,
10570        cx: &mut Context<Self>,
10571    ) {
10572        let source = self
10573            .buffer
10574            .read(cx)
10575            .snapshot(cx)
10576            .anchor_before(Point::new(display_row.0, 0u32));
10577
10578        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10579
10580        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10581            self,
10582            source,
10583            clicked_point,
10584            context_menu,
10585            window,
10586            cx,
10587        );
10588    }
10589
10590    fn add_edit_breakpoint_block(
10591        &mut self,
10592        anchor: Anchor,
10593        breakpoint: &Breakpoint,
10594        edit_action: BreakpointPromptEditAction,
10595        window: &mut Window,
10596        cx: &mut Context<Self>,
10597    ) {
10598        let weak_editor = cx.weak_entity();
10599        let bp_prompt = cx.new(|cx| {
10600            BreakpointPromptEditor::new(
10601                weak_editor,
10602                anchor,
10603                breakpoint.clone(),
10604                edit_action,
10605                window,
10606                cx,
10607            )
10608        });
10609
10610        let height = bp_prompt.update(cx, |this, cx| {
10611            this.prompt
10612                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10613        });
10614        let cloned_prompt = bp_prompt.clone();
10615        let blocks = vec![BlockProperties {
10616            style: BlockStyle::Sticky,
10617            placement: BlockPlacement::Above(anchor),
10618            height: Some(height),
10619            render: Arc::new(move |cx| {
10620                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10621                cloned_prompt.clone().into_any_element()
10622            }),
10623            priority: 0,
10624        }];
10625
10626        let focus_handle = bp_prompt.focus_handle(cx);
10627        window.focus(&focus_handle);
10628
10629        let block_ids = self.insert_blocks(blocks, None, cx);
10630        bp_prompt.update(cx, |prompt, _| {
10631            prompt.add_block_ids(block_ids);
10632        });
10633    }
10634
10635    pub(crate) fn breakpoint_at_row(
10636        &self,
10637        row: u32,
10638        window: &mut Window,
10639        cx: &mut Context<Self>,
10640    ) -> Option<(Anchor, Breakpoint)> {
10641        let snapshot = self.snapshot(window, cx);
10642        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10643
10644        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10645    }
10646
10647    pub(crate) fn breakpoint_at_anchor(
10648        &self,
10649        breakpoint_position: Anchor,
10650        snapshot: &EditorSnapshot,
10651        cx: &mut Context<Self>,
10652    ) -> Option<(Anchor, Breakpoint)> {
10653        let buffer = self
10654            .buffer
10655            .read(cx)
10656            .buffer_for_anchor(breakpoint_position, cx)?;
10657
10658        let enclosing_excerpt = breakpoint_position.excerpt_id;
10659        let buffer_snapshot = buffer.read(cx).snapshot();
10660
10661        let row = buffer_snapshot
10662            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10663            .row;
10664
10665        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10666        let anchor_end = snapshot
10667            .buffer_snapshot
10668            .anchor_after(Point::new(row, line_len));
10669
10670        self.breakpoint_store
10671            .as_ref()?
10672            .read_with(cx, |breakpoint_store, cx| {
10673                breakpoint_store
10674                    .breakpoints(
10675                        &buffer,
10676                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10677                        &buffer_snapshot,
10678                        cx,
10679                    )
10680                    .next()
10681                    .and_then(|(bp, _)| {
10682                        let breakpoint_row = buffer_snapshot
10683                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10684                            .row;
10685
10686                        if breakpoint_row == row {
10687                            snapshot
10688                                .buffer_snapshot
10689                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10690                                .map(|position| (position, bp.bp.clone()))
10691                        } else {
10692                            None
10693                        }
10694                    })
10695            })
10696    }
10697
10698    pub fn edit_log_breakpoint(
10699        &mut self,
10700        _: &EditLogBreakpoint,
10701        window: &mut Window,
10702        cx: &mut Context<Self>,
10703    ) {
10704        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10705            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10706                message: None,
10707                state: BreakpointState::Enabled,
10708                condition: None,
10709                hit_condition: None,
10710            });
10711
10712            self.add_edit_breakpoint_block(
10713                anchor,
10714                &breakpoint,
10715                BreakpointPromptEditAction::Log,
10716                window,
10717                cx,
10718            );
10719        }
10720    }
10721
10722    fn breakpoints_at_cursors(
10723        &self,
10724        window: &mut Window,
10725        cx: &mut Context<Self>,
10726    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10727        let snapshot = self.snapshot(window, cx);
10728        let cursors = self
10729            .selections
10730            .disjoint_anchors()
10731            .iter()
10732            .map(|selection| {
10733                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10734
10735                let breakpoint_position = self
10736                    .breakpoint_at_row(cursor_position.row, window, cx)
10737                    .map(|bp| bp.0)
10738                    .unwrap_or_else(|| {
10739                        snapshot
10740                            .display_snapshot
10741                            .buffer_snapshot
10742                            .anchor_after(Point::new(cursor_position.row, 0))
10743                    });
10744
10745                let breakpoint = self
10746                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10747                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10748
10749                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10750            })
10751            // 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.
10752            .collect::<HashMap<Anchor, _>>();
10753
10754        cursors.into_iter().collect()
10755    }
10756
10757    pub fn enable_breakpoint(
10758        &mut self,
10759        _: &crate::actions::EnableBreakpoint,
10760        window: &mut Window,
10761        cx: &mut Context<Self>,
10762    ) {
10763        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10764            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10765                continue;
10766            };
10767            self.edit_breakpoint_at_anchor(
10768                anchor,
10769                breakpoint,
10770                BreakpointEditAction::InvertState,
10771                cx,
10772            );
10773        }
10774    }
10775
10776    pub fn disable_breakpoint(
10777        &mut self,
10778        _: &crate::actions::DisableBreakpoint,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) {
10782        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10783            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10784                continue;
10785            };
10786            self.edit_breakpoint_at_anchor(
10787                anchor,
10788                breakpoint,
10789                BreakpointEditAction::InvertState,
10790                cx,
10791            );
10792        }
10793    }
10794
10795    pub fn toggle_breakpoint(
10796        &mut self,
10797        _: &crate::actions::ToggleBreakpoint,
10798        window: &mut Window,
10799        cx: &mut Context<Self>,
10800    ) {
10801        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10802            if let Some(breakpoint) = breakpoint {
10803                self.edit_breakpoint_at_anchor(
10804                    anchor,
10805                    breakpoint,
10806                    BreakpointEditAction::Toggle,
10807                    cx,
10808                );
10809            } else {
10810                self.edit_breakpoint_at_anchor(
10811                    anchor,
10812                    Breakpoint::new_standard(),
10813                    BreakpointEditAction::Toggle,
10814                    cx,
10815                );
10816            }
10817        }
10818    }
10819
10820    pub fn edit_breakpoint_at_anchor(
10821        &mut self,
10822        breakpoint_position: Anchor,
10823        breakpoint: Breakpoint,
10824        edit_action: BreakpointEditAction,
10825        cx: &mut Context<Self>,
10826    ) {
10827        let Some(breakpoint_store) = &self.breakpoint_store else {
10828            return;
10829        };
10830
10831        let Some(buffer) = self
10832            .buffer
10833            .read(cx)
10834            .buffer_for_anchor(breakpoint_position, cx)
10835        else {
10836            return;
10837        };
10838
10839        breakpoint_store.update(cx, |breakpoint_store, cx| {
10840            breakpoint_store.toggle_breakpoint(
10841                buffer,
10842                BreakpointWithPosition {
10843                    position: breakpoint_position.text_anchor,
10844                    bp: breakpoint,
10845                },
10846                edit_action,
10847                cx,
10848            );
10849        });
10850
10851        cx.notify();
10852    }
10853
10854    #[cfg(any(test, feature = "test-support"))]
10855    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10856        self.breakpoint_store.clone()
10857    }
10858
10859    pub fn prepare_restore_change(
10860        &self,
10861        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10862        hunk: &MultiBufferDiffHunk,
10863        cx: &mut App,
10864    ) -> Option<()> {
10865        if hunk.is_created_file() {
10866            return None;
10867        }
10868        let buffer = self.buffer.read(cx);
10869        let diff = buffer.diff_for(hunk.buffer_id)?;
10870        let buffer = buffer.buffer(hunk.buffer_id)?;
10871        let buffer = buffer.read(cx);
10872        let original_text = diff
10873            .read(cx)
10874            .base_text()
10875            .as_rope()
10876            .slice(hunk.diff_base_byte_range.clone());
10877        let buffer_snapshot = buffer.snapshot();
10878        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10879        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10880            probe
10881                .0
10882                .start
10883                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10884                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10885        }) {
10886            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10887            Some(())
10888        } else {
10889            None
10890        }
10891    }
10892
10893    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10894        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10895    }
10896
10897    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10898        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10899    }
10900
10901    fn manipulate_lines<M>(
10902        &mut self,
10903        window: &mut Window,
10904        cx: &mut Context<Self>,
10905        mut manipulate: M,
10906    ) where
10907        M: FnMut(&str) -> LineManipulationResult,
10908    {
10909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10910
10911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10912        let buffer = self.buffer.read(cx).snapshot(cx);
10913
10914        let mut edits = Vec::new();
10915
10916        let selections = self.selections.all::<Point>(cx);
10917        let mut selections = selections.iter().peekable();
10918        let mut contiguous_row_selections = Vec::new();
10919        let mut new_selections = Vec::new();
10920        let mut added_lines = 0;
10921        let mut removed_lines = 0;
10922
10923        while let Some(selection) = selections.next() {
10924            let (start_row, end_row) = consume_contiguous_rows(
10925                &mut contiguous_row_selections,
10926                selection,
10927                &display_map,
10928                &mut selections,
10929            );
10930
10931            let start_point = Point::new(start_row.0, 0);
10932            let end_point = Point::new(
10933                end_row.previous_row().0,
10934                buffer.line_len(end_row.previous_row()),
10935            );
10936            let text = buffer
10937                .text_for_range(start_point..end_point)
10938                .collect::<String>();
10939
10940            let LineManipulationResult {
10941                new_text,
10942                line_count_before,
10943                line_count_after,
10944            } = manipulate(&text);
10945
10946            edits.push((start_point..end_point, new_text));
10947
10948            // Selections must change based on added and removed line count
10949            let start_row =
10950                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10951            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10952            new_selections.push(Selection {
10953                id: selection.id,
10954                start: start_row,
10955                end: end_row,
10956                goal: SelectionGoal::None,
10957                reversed: selection.reversed,
10958            });
10959
10960            if line_count_after > line_count_before {
10961                added_lines += line_count_after - line_count_before;
10962            } else if line_count_before > line_count_after {
10963                removed_lines += line_count_before - line_count_after;
10964            }
10965        }
10966
10967        self.transact(window, cx, |this, window, cx| {
10968            let buffer = this.buffer.update(cx, |buffer, cx| {
10969                buffer.edit(edits, None, cx);
10970                buffer.snapshot(cx)
10971            });
10972
10973            // Recalculate offsets on newly edited buffer
10974            let new_selections = new_selections
10975                .iter()
10976                .map(|s| {
10977                    let start_point = Point::new(s.start.0, 0);
10978                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10979                    Selection {
10980                        id: s.id,
10981                        start: buffer.point_to_offset(start_point),
10982                        end: buffer.point_to_offset(end_point),
10983                        goal: s.goal,
10984                        reversed: s.reversed,
10985                    }
10986                })
10987                .collect();
10988
10989            this.change_selections(Default::default(), window, cx, |s| {
10990                s.select(new_selections);
10991            });
10992
10993            this.request_autoscroll(Autoscroll::fit(), cx);
10994        });
10995    }
10996
10997    fn manipulate_immutable_lines<Fn>(
10998        &mut self,
10999        window: &mut Window,
11000        cx: &mut Context<Self>,
11001        mut callback: Fn,
11002    ) where
11003        Fn: FnMut(&mut Vec<&str>),
11004    {
11005        self.manipulate_lines(window, cx, |text| {
11006            let mut lines: Vec<&str> = text.split('\n').collect();
11007            let line_count_before = lines.len();
11008
11009            callback(&mut lines);
11010
11011            LineManipulationResult {
11012                new_text: lines.join("\n"),
11013                line_count_before,
11014                line_count_after: lines.len(),
11015            }
11016        });
11017    }
11018
11019    fn manipulate_mutable_lines<Fn>(
11020        &mut self,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023        mut callback: Fn,
11024    ) where
11025        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11026    {
11027        self.manipulate_lines(window, cx, |text| {
11028            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11029            let line_count_before = lines.len();
11030
11031            callback(&mut lines);
11032
11033            LineManipulationResult {
11034                new_text: lines.join("\n"),
11035                line_count_before,
11036                line_count_after: lines.len(),
11037            }
11038        });
11039    }
11040
11041    pub fn convert_indentation_to_spaces(
11042        &mut self,
11043        _: &ConvertIndentationToSpaces,
11044        window: &mut Window,
11045        cx: &mut Context<Self>,
11046    ) {
11047        let settings = self.buffer.read(cx).language_settings(cx);
11048        let tab_size = settings.tab_size.get() as usize;
11049
11050        self.manipulate_mutable_lines(window, cx, |lines| {
11051            // Allocates a reasonably sized scratch buffer once for the whole loop
11052            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11053            // Avoids recomputing spaces that could be inserted many times
11054            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11055                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11056                .collect();
11057
11058            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11059                let mut chars = line.as_ref().chars();
11060                let mut col = 0;
11061                let mut changed = false;
11062
11063                for ch in chars.by_ref() {
11064                    match ch {
11065                        ' ' => {
11066                            reindented_line.push(' ');
11067                            col += 1;
11068                        }
11069                        '\t' => {
11070                            // \t are converted to spaces depending on the current column
11071                            let spaces_len = tab_size - (col % tab_size);
11072                            reindented_line.extend(&space_cache[spaces_len - 1]);
11073                            col += spaces_len;
11074                            changed = true;
11075                        }
11076                        _ => {
11077                            // If we dont append before break, the character is consumed
11078                            reindented_line.push(ch);
11079                            break;
11080                        }
11081                    }
11082                }
11083
11084                if !changed {
11085                    reindented_line.clear();
11086                    continue;
11087                }
11088                // Append the rest of the line and replace old reference with new one
11089                reindented_line.extend(chars);
11090                *line = Cow::Owned(reindented_line.clone());
11091                reindented_line.clear();
11092            }
11093        });
11094    }
11095
11096    pub fn convert_indentation_to_tabs(
11097        &mut self,
11098        _: &ConvertIndentationToTabs,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        let settings = self.buffer.read(cx).language_settings(cx);
11103        let tab_size = settings.tab_size.get() as usize;
11104
11105        self.manipulate_mutable_lines(window, cx, |lines| {
11106            // Allocates a reasonably sized buffer once for the whole loop
11107            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11108            // Avoids recomputing spaces that could be inserted many times
11109            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11110                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11111                .collect();
11112
11113            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11114                let mut chars = line.chars();
11115                let mut spaces_count = 0;
11116                let mut first_non_indent_char = None;
11117                let mut changed = false;
11118
11119                for ch in chars.by_ref() {
11120                    match ch {
11121                        ' ' => {
11122                            // Keep track of spaces. Append \t when we reach tab_size
11123                            spaces_count += 1;
11124                            changed = true;
11125                            if spaces_count == tab_size {
11126                                reindented_line.push('\t');
11127                                spaces_count = 0;
11128                            }
11129                        }
11130                        '\t' => {
11131                            reindented_line.push('\t');
11132                            spaces_count = 0;
11133                        }
11134                        _ => {
11135                            // Dont append it yet, we might have remaining spaces
11136                            first_non_indent_char = Some(ch);
11137                            break;
11138                        }
11139                    }
11140                }
11141
11142                if !changed {
11143                    reindented_line.clear();
11144                    continue;
11145                }
11146                // Remaining spaces that didn't make a full tab stop
11147                if spaces_count > 0 {
11148                    reindented_line.extend(&space_cache[spaces_count - 1]);
11149                }
11150                // If we consume an extra character that was not indentation, add it back
11151                if let Some(extra_char) = first_non_indent_char {
11152                    reindented_line.push(extra_char);
11153                }
11154                // Append the rest of the line and replace old reference with new one
11155                reindented_line.extend(chars);
11156                *line = Cow::Owned(reindented_line.clone());
11157                reindented_line.clear();
11158            }
11159        });
11160    }
11161
11162    pub fn convert_to_upper_case(
11163        &mut self,
11164        _: &ConvertToUpperCase,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        self.manipulate_text(window, cx, |text| text.to_uppercase())
11169    }
11170
11171    pub fn convert_to_lower_case(
11172        &mut self,
11173        _: &ConvertToLowerCase,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176    ) {
11177        self.manipulate_text(window, cx, |text| text.to_lowercase())
11178    }
11179
11180    pub fn convert_to_title_case(
11181        &mut self,
11182        _: &ConvertToTitleCase,
11183        window: &mut Window,
11184        cx: &mut Context<Self>,
11185    ) {
11186        self.manipulate_text(window, cx, |text| {
11187            text.split('\n')
11188                .map(|line| line.to_case(Case::Title))
11189                .join("\n")
11190        })
11191    }
11192
11193    pub fn convert_to_snake_case(
11194        &mut self,
11195        _: &ConvertToSnakeCase,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198    ) {
11199        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11200    }
11201
11202    pub fn convert_to_kebab_case(
11203        &mut self,
11204        _: &ConvertToKebabCase,
11205        window: &mut Window,
11206        cx: &mut Context<Self>,
11207    ) {
11208        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11209    }
11210
11211    pub fn convert_to_upper_camel_case(
11212        &mut self,
11213        _: &ConvertToUpperCamelCase,
11214        window: &mut Window,
11215        cx: &mut Context<Self>,
11216    ) {
11217        self.manipulate_text(window, cx, |text| {
11218            text.split('\n')
11219                .map(|line| line.to_case(Case::UpperCamel))
11220                .join("\n")
11221        })
11222    }
11223
11224    pub fn convert_to_lower_camel_case(
11225        &mut self,
11226        _: &ConvertToLowerCamelCase,
11227        window: &mut Window,
11228        cx: &mut Context<Self>,
11229    ) {
11230        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11231    }
11232
11233    pub fn convert_to_opposite_case(
11234        &mut self,
11235        _: &ConvertToOppositeCase,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        self.manipulate_text(window, cx, |text| {
11240            text.chars()
11241                .fold(String::with_capacity(text.len()), |mut t, c| {
11242                    if c.is_uppercase() {
11243                        t.extend(c.to_lowercase());
11244                    } else {
11245                        t.extend(c.to_uppercase());
11246                    }
11247                    t
11248                })
11249        })
11250    }
11251
11252    pub fn convert_to_sentence_case(
11253        &mut self,
11254        _: &ConvertToSentenceCase,
11255        window: &mut Window,
11256        cx: &mut Context<Self>,
11257    ) {
11258        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11259    }
11260
11261    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11262        self.manipulate_text(window, cx, |text| {
11263            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11264            if has_upper_case_characters {
11265                text.to_lowercase()
11266            } else {
11267                text.to_uppercase()
11268            }
11269        })
11270    }
11271
11272    pub fn convert_to_rot13(
11273        &mut self,
11274        _: &ConvertToRot13,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277    ) {
11278        self.manipulate_text(window, cx, |text| {
11279            text.chars()
11280                .map(|c| match c {
11281                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11282                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11283                    _ => c,
11284                })
11285                .collect()
11286        })
11287    }
11288
11289    pub fn convert_to_rot47(
11290        &mut self,
11291        _: &ConvertToRot47,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.manipulate_text(window, cx, |text| {
11296            text.chars()
11297                .map(|c| {
11298                    let code_point = c as u32;
11299                    if code_point >= 33 && code_point <= 126 {
11300                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11301                    }
11302                    c
11303                })
11304                .collect()
11305        })
11306    }
11307
11308    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11309    where
11310        Fn: FnMut(&str) -> String,
11311    {
11312        let buffer = self.buffer.read(cx).snapshot(cx);
11313
11314        let mut new_selections = Vec::new();
11315        let mut edits = Vec::new();
11316        let mut selection_adjustment = 0i32;
11317
11318        for selection in self.selections.all::<usize>(cx) {
11319            let selection_is_empty = selection.is_empty();
11320
11321            let (start, end) = if selection_is_empty {
11322                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11323                (word_range.start, word_range.end)
11324            } else {
11325                (selection.start, selection.end)
11326            };
11327
11328            let text = buffer.text_for_range(start..end).collect::<String>();
11329            let old_length = text.len() as i32;
11330            let text = callback(&text);
11331
11332            new_selections.push(Selection {
11333                start: (start as i32 - selection_adjustment) as usize,
11334                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11335                goal: SelectionGoal::None,
11336                ..selection
11337            });
11338
11339            selection_adjustment += old_length - text.len() as i32;
11340
11341            edits.push((start..end, text));
11342        }
11343
11344        self.transact(window, cx, |this, window, cx| {
11345            this.buffer.update(cx, |buffer, cx| {
11346                buffer.edit(edits, None, cx);
11347            });
11348
11349            this.change_selections(Default::default(), window, cx, |s| {
11350                s.select(new_selections);
11351            });
11352
11353            this.request_autoscroll(Autoscroll::fit(), cx);
11354        });
11355    }
11356
11357    pub fn move_selection_on_drop(
11358        &mut self,
11359        selection: &Selection<Anchor>,
11360        target: DisplayPoint,
11361        is_cut: bool,
11362        window: &mut Window,
11363        cx: &mut Context<Self>,
11364    ) {
11365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11366        let buffer = &display_map.buffer_snapshot;
11367        let mut edits = Vec::new();
11368        let insert_point = display_map
11369            .clip_point(target, Bias::Left)
11370            .to_point(&display_map);
11371        let text = buffer
11372            .text_for_range(selection.start..selection.end)
11373            .collect::<String>();
11374        if is_cut {
11375            edits.push(((selection.start..selection.end), String::new()));
11376        }
11377        let insert_anchor = buffer.anchor_before(insert_point);
11378        edits.push(((insert_anchor..insert_anchor), text));
11379        let last_edit_start = insert_anchor.bias_left(buffer);
11380        let last_edit_end = insert_anchor.bias_right(buffer);
11381        self.transact(window, cx, |this, window, cx| {
11382            this.buffer.update(cx, |buffer, cx| {
11383                buffer.edit(edits, None, cx);
11384            });
11385            this.change_selections(Default::default(), window, cx, |s| {
11386                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11387            });
11388        });
11389    }
11390
11391    pub fn clear_selection_drag_state(&mut self) {
11392        self.selection_drag_state = SelectionDragState::None;
11393    }
11394
11395    pub fn duplicate(
11396        &mut self,
11397        upwards: bool,
11398        whole_lines: bool,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11403
11404        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11405        let buffer = &display_map.buffer_snapshot;
11406        let selections = self.selections.all::<Point>(cx);
11407
11408        let mut edits = Vec::new();
11409        let mut selections_iter = selections.iter().peekable();
11410        while let Some(selection) = selections_iter.next() {
11411            let mut rows = selection.spanned_rows(false, &display_map);
11412            // duplicate line-wise
11413            if whole_lines || selection.start == selection.end {
11414                // Avoid duplicating the same lines twice.
11415                while let Some(next_selection) = selections_iter.peek() {
11416                    let next_rows = next_selection.spanned_rows(false, &display_map);
11417                    if next_rows.start < rows.end {
11418                        rows.end = next_rows.end;
11419                        selections_iter.next().unwrap();
11420                    } else {
11421                        break;
11422                    }
11423                }
11424
11425                // Copy the text from the selected row region and splice it either at the start
11426                // or end of the region.
11427                let start = Point::new(rows.start.0, 0);
11428                let end = Point::new(
11429                    rows.end.previous_row().0,
11430                    buffer.line_len(rows.end.previous_row()),
11431                );
11432                let text = buffer
11433                    .text_for_range(start..end)
11434                    .chain(Some("\n"))
11435                    .collect::<String>();
11436                let insert_location = if upwards {
11437                    Point::new(rows.end.0, 0)
11438                } else {
11439                    start
11440                };
11441                edits.push((insert_location..insert_location, text));
11442            } else {
11443                // duplicate character-wise
11444                let start = selection.start;
11445                let end = selection.end;
11446                let text = buffer.text_for_range(start..end).collect::<String>();
11447                edits.push((selection.end..selection.end, text));
11448            }
11449        }
11450
11451        self.transact(window, cx, |this, _, cx| {
11452            this.buffer.update(cx, |buffer, cx| {
11453                buffer.edit(edits, None, cx);
11454            });
11455
11456            this.request_autoscroll(Autoscroll::fit(), cx);
11457        });
11458    }
11459
11460    pub fn duplicate_line_up(
11461        &mut self,
11462        _: &DuplicateLineUp,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        self.duplicate(true, true, window, cx);
11467    }
11468
11469    pub fn duplicate_line_down(
11470        &mut self,
11471        _: &DuplicateLineDown,
11472        window: &mut Window,
11473        cx: &mut Context<Self>,
11474    ) {
11475        self.duplicate(false, true, window, cx);
11476    }
11477
11478    pub fn duplicate_selection(
11479        &mut self,
11480        _: &DuplicateSelection,
11481        window: &mut Window,
11482        cx: &mut Context<Self>,
11483    ) {
11484        self.duplicate(false, false, window, cx);
11485    }
11486
11487    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11489        if self.mode.is_single_line() {
11490            cx.propagate();
11491            return;
11492        }
11493
11494        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11495        let buffer = self.buffer.read(cx).snapshot(cx);
11496
11497        let mut edits = Vec::new();
11498        let mut unfold_ranges = Vec::new();
11499        let mut refold_creases = Vec::new();
11500
11501        let selections = self.selections.all::<Point>(cx);
11502        let mut selections = selections.iter().peekable();
11503        let mut contiguous_row_selections = Vec::new();
11504        let mut new_selections = Vec::new();
11505
11506        while let Some(selection) = selections.next() {
11507            // Find all the selections that span a contiguous row range
11508            let (start_row, end_row) = consume_contiguous_rows(
11509                &mut contiguous_row_selections,
11510                selection,
11511                &display_map,
11512                &mut selections,
11513            );
11514
11515            // Move the text spanned by the row range to be before the line preceding the row range
11516            if start_row.0 > 0 {
11517                let range_to_move = Point::new(
11518                    start_row.previous_row().0,
11519                    buffer.line_len(start_row.previous_row()),
11520                )
11521                    ..Point::new(
11522                        end_row.previous_row().0,
11523                        buffer.line_len(end_row.previous_row()),
11524                    );
11525                let insertion_point = display_map
11526                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11527                    .0;
11528
11529                // Don't move lines across excerpts
11530                if buffer
11531                    .excerpt_containing(insertion_point..range_to_move.end)
11532                    .is_some()
11533                {
11534                    let text = buffer
11535                        .text_for_range(range_to_move.clone())
11536                        .flat_map(|s| s.chars())
11537                        .skip(1)
11538                        .chain(['\n'])
11539                        .collect::<String>();
11540
11541                    edits.push((
11542                        buffer.anchor_after(range_to_move.start)
11543                            ..buffer.anchor_before(range_to_move.end),
11544                        String::new(),
11545                    ));
11546                    let insertion_anchor = buffer.anchor_after(insertion_point);
11547                    edits.push((insertion_anchor..insertion_anchor, text));
11548
11549                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11550
11551                    // Move selections up
11552                    new_selections.extend(contiguous_row_selections.drain(..).map(
11553                        |mut selection| {
11554                            selection.start.row -= row_delta;
11555                            selection.end.row -= row_delta;
11556                            selection
11557                        },
11558                    ));
11559
11560                    // Move folds up
11561                    unfold_ranges.push(range_to_move.clone());
11562                    for fold in display_map.folds_in_range(
11563                        buffer.anchor_before(range_to_move.start)
11564                            ..buffer.anchor_after(range_to_move.end),
11565                    ) {
11566                        let mut start = fold.range.start.to_point(&buffer);
11567                        let mut end = fold.range.end.to_point(&buffer);
11568                        start.row -= row_delta;
11569                        end.row -= row_delta;
11570                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11571                    }
11572                }
11573            }
11574
11575            // If we didn't move line(s), preserve the existing selections
11576            new_selections.append(&mut contiguous_row_selections);
11577        }
11578
11579        self.transact(window, cx, |this, window, cx| {
11580            this.unfold_ranges(&unfold_ranges, true, true, cx);
11581            this.buffer.update(cx, |buffer, cx| {
11582                for (range, text) in edits {
11583                    buffer.edit([(range, text)], None, cx);
11584                }
11585            });
11586            this.fold_creases(refold_creases, true, window, cx);
11587            this.change_selections(Default::default(), window, cx, |s| {
11588                s.select(new_selections);
11589            })
11590        });
11591    }
11592
11593    pub fn move_line_down(
11594        &mut self,
11595        _: &MoveLineDown,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11600        if self.mode.is_single_line() {
11601            cx.propagate();
11602            return;
11603        }
11604
11605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11606        let buffer = self.buffer.read(cx).snapshot(cx);
11607
11608        let mut edits = Vec::new();
11609        let mut unfold_ranges = Vec::new();
11610        let mut refold_creases = Vec::new();
11611
11612        let selections = self.selections.all::<Point>(cx);
11613        let mut selections = selections.iter().peekable();
11614        let mut contiguous_row_selections = Vec::new();
11615        let mut new_selections = Vec::new();
11616
11617        while let Some(selection) = selections.next() {
11618            // Find all the selections that span a contiguous row range
11619            let (start_row, end_row) = consume_contiguous_rows(
11620                &mut contiguous_row_selections,
11621                selection,
11622                &display_map,
11623                &mut selections,
11624            );
11625
11626            // Move the text spanned by the row range to be after the last line of the row range
11627            if end_row.0 <= buffer.max_point().row {
11628                let range_to_move =
11629                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11630                let insertion_point = display_map
11631                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11632                    .0;
11633
11634                // Don't move lines across excerpt boundaries
11635                if buffer
11636                    .excerpt_containing(range_to_move.start..insertion_point)
11637                    .is_some()
11638                {
11639                    let mut text = String::from("\n");
11640                    text.extend(buffer.text_for_range(range_to_move.clone()));
11641                    text.pop(); // Drop trailing newline
11642                    edits.push((
11643                        buffer.anchor_after(range_to_move.start)
11644                            ..buffer.anchor_before(range_to_move.end),
11645                        String::new(),
11646                    ));
11647                    let insertion_anchor = buffer.anchor_after(insertion_point);
11648                    edits.push((insertion_anchor..insertion_anchor, text));
11649
11650                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11651
11652                    // Move selections down
11653                    new_selections.extend(contiguous_row_selections.drain(..).map(
11654                        |mut selection| {
11655                            selection.start.row += row_delta;
11656                            selection.end.row += row_delta;
11657                            selection
11658                        },
11659                    ));
11660
11661                    // Move folds down
11662                    unfold_ranges.push(range_to_move.clone());
11663                    for fold in display_map.folds_in_range(
11664                        buffer.anchor_before(range_to_move.start)
11665                            ..buffer.anchor_after(range_to_move.end),
11666                    ) {
11667                        let mut start = fold.range.start.to_point(&buffer);
11668                        let mut end = fold.range.end.to_point(&buffer);
11669                        start.row += row_delta;
11670                        end.row += row_delta;
11671                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11672                    }
11673                }
11674            }
11675
11676            // If we didn't move line(s), preserve the existing selections
11677            new_selections.append(&mut contiguous_row_selections);
11678        }
11679
11680        self.transact(window, cx, |this, window, cx| {
11681            this.unfold_ranges(&unfold_ranges, true, true, cx);
11682            this.buffer.update(cx, |buffer, cx| {
11683                for (range, text) in edits {
11684                    buffer.edit([(range, text)], None, cx);
11685                }
11686            });
11687            this.fold_creases(refold_creases, true, window, cx);
11688            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11689        });
11690    }
11691
11692    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11693        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11694        let text_layout_details = &self.text_layout_details(window);
11695        self.transact(window, cx, |this, window, cx| {
11696            let edits = this.change_selections(Default::default(), window, cx, |s| {
11697                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11698                s.move_with(|display_map, selection| {
11699                    if !selection.is_empty() {
11700                        return;
11701                    }
11702
11703                    let mut head = selection.head();
11704                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11705                    if head.column() == display_map.line_len(head.row()) {
11706                        transpose_offset = display_map
11707                            .buffer_snapshot
11708                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11709                    }
11710
11711                    if transpose_offset == 0 {
11712                        return;
11713                    }
11714
11715                    *head.column_mut() += 1;
11716                    head = display_map.clip_point(head, Bias::Right);
11717                    let goal = SelectionGoal::HorizontalPosition(
11718                        display_map
11719                            .x_for_display_point(head, text_layout_details)
11720                            .into(),
11721                    );
11722                    selection.collapse_to(head, goal);
11723
11724                    let transpose_start = display_map
11725                        .buffer_snapshot
11726                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11727                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11728                        let transpose_end = display_map
11729                            .buffer_snapshot
11730                            .clip_offset(transpose_offset + 1, Bias::Right);
11731                        if let Some(ch) =
11732                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11733                        {
11734                            edits.push((transpose_start..transpose_offset, String::new()));
11735                            edits.push((transpose_end..transpose_end, ch.to_string()));
11736                        }
11737                    }
11738                });
11739                edits
11740            });
11741            this.buffer
11742                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11743            let selections = this.selections.all::<usize>(cx);
11744            this.change_selections(Default::default(), window, cx, |s| {
11745                s.select(selections);
11746            });
11747        });
11748    }
11749
11750    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11752        if self.mode.is_single_line() {
11753            cx.propagate();
11754            return;
11755        }
11756
11757        self.rewrap_impl(RewrapOptions::default(), cx)
11758    }
11759
11760    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11761        let buffer = self.buffer.read(cx).snapshot(cx);
11762        let selections = self.selections.all::<Point>(cx);
11763
11764        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11765        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11766            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11767                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11768                .peekable();
11769
11770            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11771                row
11772            } else {
11773                return Vec::new();
11774            };
11775
11776            let language_settings = buffer.language_settings_at(selection.head(), cx);
11777            let language_scope = buffer.language_scope_at(selection.head());
11778
11779            let indent_and_prefix_for_row =
11780                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11781                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11782                    let (comment_prefix, rewrap_prefix) =
11783                        if let Some(language_scope) = &language_scope {
11784                            let indent_end = Point::new(row, indent.len);
11785                            let comment_prefix = language_scope
11786                                .line_comment_prefixes()
11787                                .iter()
11788                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11789                                .map(|prefix| prefix.to_string());
11790                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11791                            let line_text_after_indent = buffer
11792                                .text_for_range(indent_end..line_end)
11793                                .collect::<String>();
11794                            let rewrap_prefix = language_scope
11795                                .rewrap_prefixes()
11796                                .iter()
11797                                .find_map(|prefix_regex| {
11798                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11799                                        if mat.start() == 0 {
11800                                            Some(mat.as_str().to_string())
11801                                        } else {
11802                                            None
11803                                        }
11804                                    })
11805                                })
11806                                .flatten();
11807                            (comment_prefix, rewrap_prefix)
11808                        } else {
11809                            (None, None)
11810                        };
11811                    (indent, comment_prefix, rewrap_prefix)
11812                };
11813
11814            let mut ranges = Vec::new();
11815            let from_empty_selection = selection.is_empty();
11816
11817            let mut current_range_start = first_row;
11818            let mut prev_row = first_row;
11819            let (
11820                mut current_range_indent,
11821                mut current_range_comment_prefix,
11822                mut current_range_rewrap_prefix,
11823            ) = indent_and_prefix_for_row(first_row);
11824
11825            for row in non_blank_rows_iter.skip(1) {
11826                let has_paragraph_break = row > prev_row + 1;
11827
11828                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11829                    indent_and_prefix_for_row(row);
11830
11831                let has_indent_change = row_indent != current_range_indent;
11832                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11833
11834                let has_boundary_change = has_comment_change
11835                    || row_rewrap_prefix.is_some()
11836                    || (has_indent_change && current_range_comment_prefix.is_some());
11837
11838                if has_paragraph_break || has_boundary_change {
11839                    ranges.push((
11840                        language_settings.clone(),
11841                        Point::new(current_range_start, 0)
11842                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11843                        current_range_indent,
11844                        current_range_comment_prefix.clone(),
11845                        current_range_rewrap_prefix.clone(),
11846                        from_empty_selection,
11847                    ));
11848                    current_range_start = row;
11849                    current_range_indent = row_indent;
11850                    current_range_comment_prefix = row_comment_prefix;
11851                    current_range_rewrap_prefix = row_rewrap_prefix;
11852                }
11853                prev_row = row;
11854            }
11855
11856            ranges.push((
11857                language_settings.clone(),
11858                Point::new(current_range_start, 0)
11859                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11860                current_range_indent,
11861                current_range_comment_prefix,
11862                current_range_rewrap_prefix,
11863                from_empty_selection,
11864            ));
11865
11866            ranges
11867        });
11868
11869        let mut edits = Vec::new();
11870        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11871
11872        for (
11873            language_settings,
11874            wrap_range,
11875            indent_size,
11876            comment_prefix,
11877            rewrap_prefix,
11878            from_empty_selection,
11879        ) in wrap_ranges
11880        {
11881            let mut start_row = wrap_range.start.row;
11882            let mut end_row = wrap_range.end.row;
11883
11884            // Skip selections that overlap with a range that has already been rewrapped.
11885            let selection_range = start_row..end_row;
11886            if rewrapped_row_ranges
11887                .iter()
11888                .any(|range| range.overlaps(&selection_range))
11889            {
11890                continue;
11891            }
11892
11893            let tab_size = language_settings.tab_size;
11894
11895            let indent_prefix = indent_size.chars().collect::<String>();
11896            let mut line_prefix = indent_prefix.clone();
11897            let mut inside_comment = false;
11898            if let Some(prefix) = &comment_prefix {
11899                line_prefix.push_str(prefix);
11900                inside_comment = true;
11901            }
11902            if let Some(prefix) = &rewrap_prefix {
11903                line_prefix.push_str(prefix);
11904            }
11905
11906            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11907                RewrapBehavior::InComments => inside_comment,
11908                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11909                RewrapBehavior::Anywhere => true,
11910            };
11911
11912            let should_rewrap = options.override_language_settings
11913                || allow_rewrap_based_on_language
11914                || self.hard_wrap.is_some();
11915            if !should_rewrap {
11916                continue;
11917            }
11918
11919            if from_empty_selection {
11920                'expand_upwards: while start_row > 0 {
11921                    let prev_row = start_row - 1;
11922                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11923                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11924                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11925                    {
11926                        start_row = prev_row;
11927                    } else {
11928                        break 'expand_upwards;
11929                    }
11930                }
11931
11932                'expand_downwards: while end_row < buffer.max_point().row {
11933                    let next_row = end_row + 1;
11934                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11935                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11936                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11937                    {
11938                        end_row = next_row;
11939                    } else {
11940                        break 'expand_downwards;
11941                    }
11942                }
11943            }
11944
11945            let start = Point::new(start_row, 0);
11946            let start_offset = start.to_offset(&buffer);
11947            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11948            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11949            let Some(lines_without_prefixes) = selection_text
11950                .lines()
11951                .enumerate()
11952                .map(|(ix, line)| {
11953                    let line_trimmed = line.trim_start();
11954                    if rewrap_prefix.is_some() && ix > 0 {
11955                        Ok(line_trimmed)
11956                    } else {
11957                        line_trimmed
11958                            .strip_prefix(&line_prefix.trim_start())
11959                            .with_context(|| {
11960                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11961                            })
11962                    }
11963                })
11964                .collect::<Result<Vec<_>, _>>()
11965                .log_err()
11966            else {
11967                continue;
11968            };
11969
11970            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11971                buffer
11972                    .language_settings_at(Point::new(start_row, 0), cx)
11973                    .preferred_line_length as usize
11974            });
11975
11976            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11977                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11978            } else {
11979                line_prefix.clone()
11980            };
11981
11982            let wrapped_text = wrap_with_prefix(
11983                line_prefix,
11984                subsequent_lines_prefix,
11985                lines_without_prefixes.join("\n"),
11986                wrap_column,
11987                tab_size,
11988                options.preserve_existing_whitespace,
11989            );
11990
11991            // TODO: should always use char-based diff while still supporting cursor behavior that
11992            // matches vim.
11993            let mut diff_options = DiffOptions::default();
11994            if options.override_language_settings {
11995                diff_options.max_word_diff_len = 0;
11996                diff_options.max_word_diff_line_count = 0;
11997            } else {
11998                diff_options.max_word_diff_len = usize::MAX;
11999                diff_options.max_word_diff_line_count = usize::MAX;
12000            }
12001
12002            for (old_range, new_text) in
12003                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12004            {
12005                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12006                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12007                edits.push((edit_start..edit_end, new_text));
12008            }
12009
12010            rewrapped_row_ranges.push(start_row..=end_row);
12011        }
12012
12013        self.buffer
12014            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12015    }
12016
12017    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12018        let mut text = String::new();
12019        let buffer = self.buffer.read(cx).snapshot(cx);
12020        let mut selections = self.selections.all::<Point>(cx);
12021        let mut clipboard_selections = Vec::with_capacity(selections.len());
12022        {
12023            let max_point = buffer.max_point();
12024            let mut is_first = true;
12025            for selection in &mut selections {
12026                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12027                if is_entire_line {
12028                    selection.start = Point::new(selection.start.row, 0);
12029                    if !selection.is_empty() && selection.end.column == 0 {
12030                        selection.end = cmp::min(max_point, selection.end);
12031                    } else {
12032                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12033                    }
12034                    selection.goal = SelectionGoal::None;
12035                }
12036                if is_first {
12037                    is_first = false;
12038                } else {
12039                    text += "\n";
12040                }
12041                let mut len = 0;
12042                for chunk in buffer.text_for_range(selection.start..selection.end) {
12043                    text.push_str(chunk);
12044                    len += chunk.len();
12045                }
12046                clipboard_selections.push(ClipboardSelection {
12047                    len,
12048                    is_entire_line,
12049                    first_line_indent: buffer
12050                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12051                        .len,
12052                });
12053            }
12054        }
12055
12056        self.transact(window, cx, |this, window, cx| {
12057            this.change_selections(Default::default(), window, cx, |s| {
12058                s.select(selections);
12059            });
12060            this.insert("", window, cx);
12061        });
12062        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12063    }
12064
12065    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12067        let item = self.cut_common(window, cx);
12068        cx.write_to_clipboard(item);
12069    }
12070
12071    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12072        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12073        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12074            s.move_with(|snapshot, sel| {
12075                if sel.is_empty() {
12076                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12077                }
12078            });
12079        });
12080        let item = self.cut_common(window, cx);
12081        cx.set_global(KillRing(item))
12082    }
12083
12084    pub fn kill_ring_yank(
12085        &mut self,
12086        _: &KillRingYank,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12091        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12092            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12093                (kill_ring.text().to_string(), kill_ring.metadata_json())
12094            } else {
12095                return;
12096            }
12097        } else {
12098            return;
12099        };
12100        self.do_paste(&text, metadata, false, window, cx);
12101    }
12102
12103    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12104        self.do_copy(true, cx);
12105    }
12106
12107    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12108        self.do_copy(false, cx);
12109    }
12110
12111    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12112        let selections = self.selections.all::<Point>(cx);
12113        let buffer = self.buffer.read(cx).read(cx);
12114        let mut text = String::new();
12115
12116        let mut clipboard_selections = Vec::with_capacity(selections.len());
12117        {
12118            let max_point = buffer.max_point();
12119            let mut is_first = true;
12120            for selection in &selections {
12121                let mut start = selection.start;
12122                let mut end = selection.end;
12123                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12124                if is_entire_line {
12125                    start = Point::new(start.row, 0);
12126                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12127                }
12128
12129                let mut trimmed_selections = Vec::new();
12130                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12131                    let row = MultiBufferRow(start.row);
12132                    let first_indent = buffer.indent_size_for_line(row);
12133                    if first_indent.len == 0 || start.column > first_indent.len {
12134                        trimmed_selections.push(start..end);
12135                    } else {
12136                        trimmed_selections.push(
12137                            Point::new(row.0, first_indent.len)
12138                                ..Point::new(row.0, buffer.line_len(row)),
12139                        );
12140                        for row in start.row + 1..=end.row {
12141                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12142                            if row == end.row {
12143                                line_len = end.column;
12144                            }
12145                            if line_len == 0 {
12146                                trimmed_selections
12147                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12148                                continue;
12149                            }
12150                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12151                            if row_indent_size.len >= first_indent.len {
12152                                trimmed_selections.push(
12153                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12154                                );
12155                            } else {
12156                                trimmed_selections.clear();
12157                                trimmed_selections.push(start..end);
12158                                break;
12159                            }
12160                        }
12161                    }
12162                } else {
12163                    trimmed_selections.push(start..end);
12164                }
12165
12166                for trimmed_range in trimmed_selections {
12167                    if is_first {
12168                        is_first = false;
12169                    } else {
12170                        text += "\n";
12171                    }
12172                    let mut len = 0;
12173                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12174                        text.push_str(chunk);
12175                        len += chunk.len();
12176                    }
12177                    clipboard_selections.push(ClipboardSelection {
12178                        len,
12179                        is_entire_line,
12180                        first_line_indent: buffer
12181                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12182                            .len,
12183                    });
12184                }
12185            }
12186        }
12187
12188        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12189            text,
12190            clipboard_selections,
12191        ));
12192    }
12193
12194    pub fn do_paste(
12195        &mut self,
12196        text: &String,
12197        clipboard_selections: Option<Vec<ClipboardSelection>>,
12198        handle_entire_lines: bool,
12199        window: &mut Window,
12200        cx: &mut Context<Self>,
12201    ) {
12202        if self.read_only(cx) {
12203            return;
12204        }
12205
12206        let clipboard_text = Cow::Borrowed(text);
12207
12208        self.transact(window, cx, |this, window, cx| {
12209            let had_active_edit_prediction = this.has_active_edit_prediction();
12210
12211            if let Some(mut clipboard_selections) = clipboard_selections {
12212                let old_selections = this.selections.all::<usize>(cx);
12213                let all_selections_were_entire_line =
12214                    clipboard_selections.iter().all(|s| s.is_entire_line);
12215                let first_selection_indent_column =
12216                    clipboard_selections.first().map(|s| s.first_line_indent);
12217                if clipboard_selections.len() != old_selections.len() {
12218                    clipboard_selections.drain(..);
12219                }
12220                let cursor_offset = this.selections.last::<usize>(cx).head();
12221                let mut auto_indent_on_paste = true;
12222
12223                this.buffer.update(cx, |buffer, cx| {
12224                    let snapshot = buffer.read(cx);
12225                    auto_indent_on_paste = snapshot
12226                        .language_settings_at(cursor_offset, cx)
12227                        .auto_indent_on_paste;
12228
12229                    let mut start_offset = 0;
12230                    let mut edits = Vec::new();
12231                    let mut original_indent_columns = Vec::new();
12232                    for (ix, selection) in old_selections.iter().enumerate() {
12233                        let to_insert;
12234                        let entire_line;
12235                        let original_indent_column;
12236                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12237                            let end_offset = start_offset + clipboard_selection.len;
12238                            to_insert = &clipboard_text[start_offset..end_offset];
12239                            entire_line = clipboard_selection.is_entire_line;
12240                            start_offset = end_offset + 1;
12241                            original_indent_column = Some(clipboard_selection.first_line_indent);
12242                        } else {
12243                            to_insert = clipboard_text.as_str();
12244                            entire_line = all_selections_were_entire_line;
12245                            original_indent_column = first_selection_indent_column
12246                        }
12247
12248                        // If the corresponding selection was empty when this slice of the
12249                        // clipboard text was written, then the entire line containing the
12250                        // selection was copied. If this selection is also currently empty,
12251                        // then paste the line before the current line of the buffer.
12252                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12253                            let column = selection.start.to_point(&snapshot).column as usize;
12254                            let line_start = selection.start - column;
12255                            line_start..line_start
12256                        } else {
12257                            selection.range()
12258                        };
12259
12260                        edits.push((range, to_insert));
12261                        original_indent_columns.push(original_indent_column);
12262                    }
12263                    drop(snapshot);
12264
12265                    buffer.edit(
12266                        edits,
12267                        if auto_indent_on_paste {
12268                            Some(AutoindentMode::Block {
12269                                original_indent_columns,
12270                            })
12271                        } else {
12272                            None
12273                        },
12274                        cx,
12275                    );
12276                });
12277
12278                let selections = this.selections.all::<usize>(cx);
12279                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12280            } else {
12281                this.insert(&clipboard_text, window, cx);
12282            }
12283
12284            let trigger_in_words =
12285                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12286
12287            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12288        });
12289    }
12290
12291    pub fn diff_clipboard_with_selection(
12292        &mut self,
12293        _: &DiffClipboardWithSelection,
12294        window: &mut Window,
12295        cx: &mut Context<Self>,
12296    ) {
12297        let selections = self.selections.all::<usize>(cx);
12298
12299        if selections.is_empty() {
12300            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12301            return;
12302        };
12303
12304        let clipboard_text = match cx.read_from_clipboard() {
12305            Some(item) => match item.entries().first() {
12306                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12307                _ => None,
12308            },
12309            None => None,
12310        };
12311
12312        let Some(clipboard_text) = clipboard_text else {
12313            log::warn!("Clipboard doesn't contain text.");
12314            return;
12315        };
12316
12317        window.dispatch_action(
12318            Box::new(DiffClipboardWithSelectionData {
12319                clipboard_text,
12320                editor: cx.entity(),
12321            }),
12322            cx,
12323        );
12324    }
12325
12326    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12328        if let Some(item) = cx.read_from_clipboard() {
12329            let entries = item.entries();
12330
12331            match entries.first() {
12332                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12333                // of all the pasted entries.
12334                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12335                    .do_paste(
12336                        clipboard_string.text(),
12337                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12338                        true,
12339                        window,
12340                        cx,
12341                    ),
12342                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12343            }
12344        }
12345    }
12346
12347    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12348        if self.read_only(cx) {
12349            return;
12350        }
12351
12352        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12353
12354        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12355            if let Some((selections, _)) =
12356                self.selection_history.transaction(transaction_id).cloned()
12357            {
12358                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12359                    s.select_anchors(selections.to_vec());
12360                });
12361            } else {
12362                log::error!(
12363                    "No entry in selection_history found for undo. \
12364                     This may correspond to a bug where undo does not update the selection. \
12365                     If this is occurring, please add details to \
12366                     https://github.com/zed-industries/zed/issues/22692"
12367                );
12368            }
12369            self.request_autoscroll(Autoscroll::fit(), cx);
12370            self.unmark_text(window, cx);
12371            self.refresh_edit_prediction(true, false, window, cx);
12372            cx.emit(EditorEvent::Edited { transaction_id });
12373            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12374        }
12375    }
12376
12377    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12378        if self.read_only(cx) {
12379            return;
12380        }
12381
12382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12383
12384        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12385            if let Some((_, Some(selections))) =
12386                self.selection_history.transaction(transaction_id).cloned()
12387            {
12388                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12389                    s.select_anchors(selections.to_vec());
12390                });
12391            } else {
12392                log::error!(
12393                    "No entry in selection_history found for redo. \
12394                     This may correspond to a bug where undo does not update the selection. \
12395                     If this is occurring, please add details to \
12396                     https://github.com/zed-industries/zed/issues/22692"
12397                );
12398            }
12399            self.request_autoscroll(Autoscroll::fit(), cx);
12400            self.unmark_text(window, cx);
12401            self.refresh_edit_prediction(true, false, window, cx);
12402            cx.emit(EditorEvent::Edited { transaction_id });
12403        }
12404    }
12405
12406    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12407        self.buffer
12408            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12409    }
12410
12411    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12412        self.buffer
12413            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12414    }
12415
12416    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12418        self.change_selections(Default::default(), window, cx, |s| {
12419            s.move_with(|map, selection| {
12420                let cursor = if selection.is_empty() {
12421                    movement::left(map, selection.start)
12422                } else {
12423                    selection.start
12424                };
12425                selection.collapse_to(cursor, SelectionGoal::None);
12426            });
12427        })
12428    }
12429
12430    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12432        self.change_selections(Default::default(), window, cx, |s| {
12433            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12434        })
12435    }
12436
12437    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12439        self.change_selections(Default::default(), window, cx, |s| {
12440            s.move_with(|map, selection| {
12441                let cursor = if selection.is_empty() {
12442                    movement::right(map, selection.end)
12443                } else {
12444                    selection.end
12445                };
12446                selection.collapse_to(cursor, SelectionGoal::None)
12447            });
12448        })
12449    }
12450
12451    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12453        self.change_selections(Default::default(), window, cx, |s| {
12454            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12455        })
12456    }
12457
12458    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12459        if self.take_rename(true, window, cx).is_some() {
12460            return;
12461        }
12462
12463        if self.mode.is_single_line() {
12464            cx.propagate();
12465            return;
12466        }
12467
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12469
12470        let text_layout_details = &self.text_layout_details(window);
12471        let selection_count = self.selections.count();
12472        let first_selection = self.selections.first_anchor();
12473
12474        self.change_selections(Default::default(), window, cx, |s| {
12475            s.move_with(|map, selection| {
12476                if !selection.is_empty() {
12477                    selection.goal = SelectionGoal::None;
12478                }
12479                let (cursor, goal) = movement::up(
12480                    map,
12481                    selection.start,
12482                    selection.goal,
12483                    false,
12484                    text_layout_details,
12485                );
12486                selection.collapse_to(cursor, goal);
12487            });
12488        });
12489
12490        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12491        {
12492            cx.propagate();
12493        }
12494    }
12495
12496    pub fn move_up_by_lines(
12497        &mut self,
12498        action: &MoveUpByLines,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        if self.take_rename(true, window, cx).is_some() {
12503            return;
12504        }
12505
12506        if self.mode.is_single_line() {
12507            cx.propagate();
12508            return;
12509        }
12510
12511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12512
12513        let text_layout_details = &self.text_layout_details(window);
12514
12515        self.change_selections(Default::default(), window, cx, |s| {
12516            s.move_with(|map, selection| {
12517                if !selection.is_empty() {
12518                    selection.goal = SelectionGoal::None;
12519                }
12520                let (cursor, goal) = movement::up_by_rows(
12521                    map,
12522                    selection.start,
12523                    action.lines,
12524                    selection.goal,
12525                    false,
12526                    text_layout_details,
12527                );
12528                selection.collapse_to(cursor, goal);
12529            });
12530        })
12531    }
12532
12533    pub fn move_down_by_lines(
12534        &mut self,
12535        action: &MoveDownByLines,
12536        window: &mut Window,
12537        cx: &mut Context<Self>,
12538    ) {
12539        if self.take_rename(true, window, cx).is_some() {
12540            return;
12541        }
12542
12543        if self.mode.is_single_line() {
12544            cx.propagate();
12545            return;
12546        }
12547
12548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12549
12550        let text_layout_details = &self.text_layout_details(window);
12551
12552        self.change_selections(Default::default(), window, cx, |s| {
12553            s.move_with(|map, selection| {
12554                if !selection.is_empty() {
12555                    selection.goal = SelectionGoal::None;
12556                }
12557                let (cursor, goal) = movement::down_by_rows(
12558                    map,
12559                    selection.start,
12560                    action.lines,
12561                    selection.goal,
12562                    false,
12563                    text_layout_details,
12564                );
12565                selection.collapse_to(cursor, goal);
12566            });
12567        })
12568    }
12569
12570    pub fn select_down_by_lines(
12571        &mut self,
12572        action: &SelectDownByLines,
12573        window: &mut Window,
12574        cx: &mut Context<Self>,
12575    ) {
12576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12577        let text_layout_details = &self.text_layout_details(window);
12578        self.change_selections(Default::default(), window, cx, |s| {
12579            s.move_heads_with(|map, head, goal| {
12580                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12581            })
12582        })
12583    }
12584
12585    pub fn select_up_by_lines(
12586        &mut self,
12587        action: &SelectUpByLines,
12588        window: &mut Window,
12589        cx: &mut Context<Self>,
12590    ) {
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12592        let text_layout_details = &self.text_layout_details(window);
12593        self.change_selections(Default::default(), window, cx, |s| {
12594            s.move_heads_with(|map, head, goal| {
12595                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12596            })
12597        })
12598    }
12599
12600    pub fn select_page_up(
12601        &mut self,
12602        _: &SelectPageUp,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let Some(row_count) = self.visible_row_count() else {
12607            return;
12608        };
12609
12610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12611
12612        let text_layout_details = &self.text_layout_details(window);
12613
12614        self.change_selections(Default::default(), window, cx, |s| {
12615            s.move_heads_with(|map, head, goal| {
12616                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12617            })
12618        })
12619    }
12620
12621    pub fn move_page_up(
12622        &mut self,
12623        action: &MovePageUp,
12624        window: &mut Window,
12625        cx: &mut Context<Self>,
12626    ) {
12627        if self.take_rename(true, window, cx).is_some() {
12628            return;
12629        }
12630
12631        if self
12632            .context_menu
12633            .borrow_mut()
12634            .as_mut()
12635            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12636            .unwrap_or(false)
12637        {
12638            return;
12639        }
12640
12641        if matches!(self.mode, EditorMode::SingleLine) {
12642            cx.propagate();
12643            return;
12644        }
12645
12646        let Some(row_count) = self.visible_row_count() else {
12647            return;
12648        };
12649
12650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12651
12652        let effects = if action.center_cursor {
12653            SelectionEffects::scroll(Autoscroll::center())
12654        } else {
12655            SelectionEffects::default()
12656        };
12657
12658        let text_layout_details = &self.text_layout_details(window);
12659
12660        self.change_selections(effects, window, cx, |s| {
12661            s.move_with(|map, selection| {
12662                if !selection.is_empty() {
12663                    selection.goal = SelectionGoal::None;
12664                }
12665                let (cursor, goal) = movement::up_by_rows(
12666                    map,
12667                    selection.end,
12668                    row_count,
12669                    selection.goal,
12670                    false,
12671                    text_layout_details,
12672                );
12673                selection.collapse_to(cursor, goal);
12674            });
12675        });
12676    }
12677
12678    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680        let text_layout_details = &self.text_layout_details(window);
12681        self.change_selections(Default::default(), window, cx, |s| {
12682            s.move_heads_with(|map, head, goal| {
12683                movement::up(map, head, goal, false, text_layout_details)
12684            })
12685        })
12686    }
12687
12688    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12689        self.take_rename(true, window, cx);
12690
12691        if self.mode.is_single_line() {
12692            cx.propagate();
12693            return;
12694        }
12695
12696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12697
12698        let text_layout_details = &self.text_layout_details(window);
12699        let selection_count = self.selections.count();
12700        let first_selection = self.selections.first_anchor();
12701
12702        self.change_selections(Default::default(), window, cx, |s| {
12703            s.move_with(|map, selection| {
12704                if !selection.is_empty() {
12705                    selection.goal = SelectionGoal::None;
12706                }
12707                let (cursor, goal) = movement::down(
12708                    map,
12709                    selection.end,
12710                    selection.goal,
12711                    false,
12712                    text_layout_details,
12713                );
12714                selection.collapse_to(cursor, goal);
12715            });
12716        });
12717
12718        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12719        {
12720            cx.propagate();
12721        }
12722    }
12723
12724    pub fn select_page_down(
12725        &mut self,
12726        _: &SelectPageDown,
12727        window: &mut Window,
12728        cx: &mut Context<Self>,
12729    ) {
12730        let Some(row_count) = self.visible_row_count() else {
12731            return;
12732        };
12733
12734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12735
12736        let text_layout_details = &self.text_layout_details(window);
12737
12738        self.change_selections(Default::default(), window, cx, |s| {
12739            s.move_heads_with(|map, head, goal| {
12740                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12741            })
12742        })
12743    }
12744
12745    pub fn move_page_down(
12746        &mut self,
12747        action: &MovePageDown,
12748        window: &mut Window,
12749        cx: &mut Context<Self>,
12750    ) {
12751        if self.take_rename(true, window, cx).is_some() {
12752            return;
12753        }
12754
12755        if self
12756            .context_menu
12757            .borrow_mut()
12758            .as_mut()
12759            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12760            .unwrap_or(false)
12761        {
12762            return;
12763        }
12764
12765        if matches!(self.mode, EditorMode::SingleLine) {
12766            cx.propagate();
12767            return;
12768        }
12769
12770        let Some(row_count) = self.visible_row_count() else {
12771            return;
12772        };
12773
12774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12775
12776        let effects = if action.center_cursor {
12777            SelectionEffects::scroll(Autoscroll::center())
12778        } else {
12779            SelectionEffects::default()
12780        };
12781
12782        let text_layout_details = &self.text_layout_details(window);
12783        self.change_selections(effects, window, cx, |s| {
12784            s.move_with(|map, selection| {
12785                if !selection.is_empty() {
12786                    selection.goal = SelectionGoal::None;
12787                }
12788                let (cursor, goal) = movement::down_by_rows(
12789                    map,
12790                    selection.end,
12791                    row_count,
12792                    selection.goal,
12793                    false,
12794                    text_layout_details,
12795                );
12796                selection.collapse_to(cursor, goal);
12797            });
12798        });
12799    }
12800
12801    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12803        let text_layout_details = &self.text_layout_details(window);
12804        self.change_selections(Default::default(), window, cx, |s| {
12805            s.move_heads_with(|map, head, goal| {
12806                movement::down(map, head, goal, false, text_layout_details)
12807            })
12808        });
12809    }
12810
12811    pub fn context_menu_first(
12812        &mut self,
12813        _: &ContextMenuFirst,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12818            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12819        }
12820    }
12821
12822    pub fn context_menu_prev(
12823        &mut self,
12824        _: &ContextMenuPrevious,
12825        window: &mut Window,
12826        cx: &mut Context<Self>,
12827    ) {
12828        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12829            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12830        }
12831    }
12832
12833    pub fn context_menu_next(
12834        &mut self,
12835        _: &ContextMenuNext,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12840            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12841        }
12842    }
12843
12844    pub fn context_menu_last(
12845        &mut self,
12846        _: &ContextMenuLast,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12851            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12852        }
12853    }
12854
12855    pub fn signature_help_prev(
12856        &mut self,
12857        _: &SignatureHelpPrevious,
12858        _: &mut Window,
12859        cx: &mut Context<Self>,
12860    ) {
12861        if let Some(popover) = self.signature_help_state.popover_mut() {
12862            if popover.current_signature == 0 {
12863                popover.current_signature = popover.signatures.len() - 1;
12864            } else {
12865                popover.current_signature -= 1;
12866            }
12867            cx.notify();
12868        }
12869    }
12870
12871    pub fn signature_help_next(
12872        &mut self,
12873        _: &SignatureHelpNext,
12874        _: &mut Window,
12875        cx: &mut Context<Self>,
12876    ) {
12877        if let Some(popover) = self.signature_help_state.popover_mut() {
12878            if popover.current_signature + 1 == popover.signatures.len() {
12879                popover.current_signature = 0;
12880            } else {
12881                popover.current_signature += 1;
12882            }
12883            cx.notify();
12884        }
12885    }
12886
12887    pub fn move_to_previous_word_start(
12888        &mut self,
12889        _: &MoveToPreviousWordStart,
12890        window: &mut Window,
12891        cx: &mut Context<Self>,
12892    ) {
12893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12894        self.change_selections(Default::default(), window, cx, |s| {
12895            s.move_cursors_with(|map, head, _| {
12896                (
12897                    movement::previous_word_start(map, head),
12898                    SelectionGoal::None,
12899                )
12900            });
12901        })
12902    }
12903
12904    pub fn move_to_previous_subword_start(
12905        &mut self,
12906        _: &MoveToPreviousSubwordStart,
12907        window: &mut Window,
12908        cx: &mut Context<Self>,
12909    ) {
12910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12911        self.change_selections(Default::default(), window, cx, |s| {
12912            s.move_cursors_with(|map, head, _| {
12913                (
12914                    movement::previous_subword_start(map, head),
12915                    SelectionGoal::None,
12916                )
12917            });
12918        })
12919    }
12920
12921    pub fn select_to_previous_word_start(
12922        &mut self,
12923        _: &SelectToPreviousWordStart,
12924        window: &mut Window,
12925        cx: &mut Context<Self>,
12926    ) {
12927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12928        self.change_selections(Default::default(), window, cx, |s| {
12929            s.move_heads_with(|map, head, _| {
12930                (
12931                    movement::previous_word_start(map, head),
12932                    SelectionGoal::None,
12933                )
12934            });
12935        })
12936    }
12937
12938    pub fn select_to_previous_subword_start(
12939        &mut self,
12940        _: &SelectToPreviousSubwordStart,
12941        window: &mut Window,
12942        cx: &mut Context<Self>,
12943    ) {
12944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12945        self.change_selections(Default::default(), window, cx, |s| {
12946            s.move_heads_with(|map, head, _| {
12947                (
12948                    movement::previous_subword_start(map, head),
12949                    SelectionGoal::None,
12950                )
12951            });
12952        })
12953    }
12954
12955    pub fn delete_to_previous_word_start(
12956        &mut self,
12957        action: &DeleteToPreviousWordStart,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12962        self.transact(window, cx, |this, window, cx| {
12963            this.select_autoclose_pair(window, cx);
12964            this.change_selections(Default::default(), window, cx, |s| {
12965                s.move_with(|map, selection| {
12966                    if selection.is_empty() {
12967                        let cursor = if action.ignore_newlines {
12968                            movement::previous_word_start(map, selection.head())
12969                        } else {
12970                            movement::previous_word_start_or_newline(map, selection.head())
12971                        };
12972                        selection.set_head(cursor, SelectionGoal::None);
12973                    }
12974                });
12975            });
12976            this.insert("", window, cx);
12977        });
12978    }
12979
12980    pub fn delete_to_previous_subword_start(
12981        &mut self,
12982        _: &DeleteToPreviousSubwordStart,
12983        window: &mut Window,
12984        cx: &mut Context<Self>,
12985    ) {
12986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12987        self.transact(window, cx, |this, window, cx| {
12988            this.select_autoclose_pair(window, cx);
12989            this.change_selections(Default::default(), window, cx, |s| {
12990                s.move_with(|map, selection| {
12991                    if selection.is_empty() {
12992                        let cursor = movement::previous_subword_start(map, selection.head());
12993                        selection.set_head(cursor, SelectionGoal::None);
12994                    }
12995                });
12996            });
12997            this.insert("", window, cx);
12998        });
12999    }
13000
13001    pub fn move_to_next_word_end(
13002        &mut self,
13003        _: &MoveToNextWordEnd,
13004        window: &mut Window,
13005        cx: &mut Context<Self>,
13006    ) {
13007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13008        self.change_selections(Default::default(), window, cx, |s| {
13009            s.move_cursors_with(|map, head, _| {
13010                (movement::next_word_end(map, head), SelectionGoal::None)
13011            });
13012        })
13013    }
13014
13015    pub fn move_to_next_subword_end(
13016        &mut self,
13017        _: &MoveToNextSubwordEnd,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_cursors_with(|map, head, _| {
13024                (movement::next_subword_end(map, head), SelectionGoal::None)
13025            });
13026        })
13027    }
13028
13029    pub fn select_to_next_word_end(
13030        &mut self,
13031        _: &SelectToNextWordEnd,
13032        window: &mut Window,
13033        cx: &mut Context<Self>,
13034    ) {
13035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13036        self.change_selections(Default::default(), window, cx, |s| {
13037            s.move_heads_with(|map, head, _| {
13038                (movement::next_word_end(map, head), SelectionGoal::None)
13039            });
13040        })
13041    }
13042
13043    pub fn select_to_next_subword_end(
13044        &mut self,
13045        _: &SelectToNextSubwordEnd,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13050        self.change_selections(Default::default(), window, cx, |s| {
13051            s.move_heads_with(|map, head, _| {
13052                (movement::next_subword_end(map, head), SelectionGoal::None)
13053            });
13054        })
13055    }
13056
13057    pub fn delete_to_next_word_end(
13058        &mut self,
13059        action: &DeleteToNextWordEnd,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13064        self.transact(window, cx, |this, window, cx| {
13065            this.change_selections(Default::default(), window, cx, |s| {
13066                s.move_with(|map, selection| {
13067                    if selection.is_empty() {
13068                        let cursor = if action.ignore_newlines {
13069                            movement::next_word_end(map, selection.head())
13070                        } else {
13071                            movement::next_word_end_or_newline(map, selection.head())
13072                        };
13073                        selection.set_head(cursor, SelectionGoal::None);
13074                    }
13075                });
13076            });
13077            this.insert("", window, cx);
13078        });
13079    }
13080
13081    pub fn delete_to_next_subword_end(
13082        &mut self,
13083        _: &DeleteToNextSubwordEnd,
13084        window: &mut Window,
13085        cx: &mut Context<Self>,
13086    ) {
13087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13088        self.transact(window, cx, |this, window, cx| {
13089            this.change_selections(Default::default(), window, cx, |s| {
13090                s.move_with(|map, selection| {
13091                    if selection.is_empty() {
13092                        let cursor = movement::next_subword_end(map, selection.head());
13093                        selection.set_head(cursor, SelectionGoal::None);
13094                    }
13095                });
13096            });
13097            this.insert("", window, cx);
13098        });
13099    }
13100
13101    pub fn move_to_beginning_of_line(
13102        &mut self,
13103        action: &MoveToBeginningOfLine,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13108        self.change_selections(Default::default(), window, cx, |s| {
13109            s.move_cursors_with(|map, head, _| {
13110                (
13111                    movement::indented_line_beginning(
13112                        map,
13113                        head,
13114                        action.stop_at_soft_wraps,
13115                        action.stop_at_indent,
13116                    ),
13117                    SelectionGoal::None,
13118                )
13119            });
13120        })
13121    }
13122
13123    pub fn select_to_beginning_of_line(
13124        &mut self,
13125        action: &SelectToBeginningOfLine,
13126        window: &mut Window,
13127        cx: &mut Context<Self>,
13128    ) {
13129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13130        self.change_selections(Default::default(), window, cx, |s| {
13131            s.move_heads_with(|map, head, _| {
13132                (
13133                    movement::indented_line_beginning(
13134                        map,
13135                        head,
13136                        action.stop_at_soft_wraps,
13137                        action.stop_at_indent,
13138                    ),
13139                    SelectionGoal::None,
13140                )
13141            });
13142        });
13143    }
13144
13145    pub fn delete_to_beginning_of_line(
13146        &mut self,
13147        action: &DeleteToBeginningOfLine,
13148        window: &mut Window,
13149        cx: &mut Context<Self>,
13150    ) {
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13152        self.transact(window, cx, |this, window, cx| {
13153            this.change_selections(Default::default(), window, cx, |s| {
13154                s.move_with(|_, selection| {
13155                    selection.reversed = true;
13156                });
13157            });
13158
13159            this.select_to_beginning_of_line(
13160                &SelectToBeginningOfLine {
13161                    stop_at_soft_wraps: false,
13162                    stop_at_indent: action.stop_at_indent,
13163                },
13164                window,
13165                cx,
13166            );
13167            this.backspace(&Backspace, window, cx);
13168        });
13169    }
13170
13171    pub fn move_to_end_of_line(
13172        &mut self,
13173        action: &MoveToEndOfLine,
13174        window: &mut Window,
13175        cx: &mut Context<Self>,
13176    ) {
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178        self.change_selections(Default::default(), window, cx, |s| {
13179            s.move_cursors_with(|map, head, _| {
13180                (
13181                    movement::line_end(map, head, action.stop_at_soft_wraps),
13182                    SelectionGoal::None,
13183                )
13184            });
13185        })
13186    }
13187
13188    pub fn select_to_end_of_line(
13189        &mut self,
13190        action: &SelectToEndOfLine,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13195        self.change_selections(Default::default(), window, cx, |s| {
13196            s.move_heads_with(|map, head, _| {
13197                (
13198                    movement::line_end(map, head, action.stop_at_soft_wraps),
13199                    SelectionGoal::None,
13200                )
13201            });
13202        })
13203    }
13204
13205    pub fn delete_to_end_of_line(
13206        &mut self,
13207        _: &DeleteToEndOfLine,
13208        window: &mut Window,
13209        cx: &mut Context<Self>,
13210    ) {
13211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13212        self.transact(window, cx, |this, window, cx| {
13213            this.select_to_end_of_line(
13214                &SelectToEndOfLine {
13215                    stop_at_soft_wraps: false,
13216                },
13217                window,
13218                cx,
13219            );
13220            this.delete(&Delete, window, cx);
13221        });
13222    }
13223
13224    pub fn cut_to_end_of_line(
13225        &mut self,
13226        _: &CutToEndOfLine,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13231        self.transact(window, cx, |this, window, cx| {
13232            this.select_to_end_of_line(
13233                &SelectToEndOfLine {
13234                    stop_at_soft_wraps: false,
13235                },
13236                window,
13237                cx,
13238            );
13239            this.cut(&Cut, window, cx);
13240        });
13241    }
13242
13243    pub fn move_to_start_of_paragraph(
13244        &mut self,
13245        _: &MoveToStartOfParagraph,
13246        window: &mut Window,
13247        cx: &mut Context<Self>,
13248    ) {
13249        if matches!(self.mode, EditorMode::SingleLine) {
13250            cx.propagate();
13251            return;
13252        }
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_with(|map, selection| {
13256                selection.collapse_to(
13257                    movement::start_of_paragraph(map, selection.head(), 1),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn move_to_end_of_paragraph(
13265        &mut self,
13266        _: &MoveToEndOfParagraph,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        if matches!(self.mode, EditorMode::SingleLine) {
13271            cx.propagate();
13272            return;
13273        }
13274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13275        self.change_selections(Default::default(), window, cx, |s| {
13276            s.move_with(|map, selection| {
13277                selection.collapse_to(
13278                    movement::end_of_paragraph(map, selection.head(), 1),
13279                    SelectionGoal::None,
13280                )
13281            });
13282        })
13283    }
13284
13285    pub fn select_to_start_of_paragraph(
13286        &mut self,
13287        _: &SelectToStartOfParagraph,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        if matches!(self.mode, EditorMode::SingleLine) {
13292            cx.propagate();
13293            return;
13294        }
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296        self.change_selections(Default::default(), window, cx, |s| {
13297            s.move_heads_with(|map, head, _| {
13298                (
13299                    movement::start_of_paragraph(map, head, 1),
13300                    SelectionGoal::None,
13301                )
13302            });
13303        })
13304    }
13305
13306    pub fn select_to_end_of_paragraph(
13307        &mut self,
13308        _: &SelectToEndOfParagraph,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        if matches!(self.mode, EditorMode::SingleLine) {
13313            cx.propagate();
13314            return;
13315        }
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317        self.change_selections(Default::default(), window, cx, |s| {
13318            s.move_heads_with(|map, head, _| {
13319                (
13320                    movement::end_of_paragraph(map, head, 1),
13321                    SelectionGoal::None,
13322                )
13323            });
13324        })
13325    }
13326
13327    pub fn move_to_start_of_excerpt(
13328        &mut self,
13329        _: &MoveToStartOfExcerpt,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        if matches!(self.mode, EditorMode::SingleLine) {
13334            cx.propagate();
13335            return;
13336        }
13337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13338        self.change_selections(Default::default(), window, cx, |s| {
13339            s.move_with(|map, selection| {
13340                selection.collapse_to(
13341                    movement::start_of_excerpt(
13342                        map,
13343                        selection.head(),
13344                        workspace::searchable::Direction::Prev,
13345                    ),
13346                    SelectionGoal::None,
13347                )
13348            });
13349        })
13350    }
13351
13352    pub fn move_to_start_of_next_excerpt(
13353        &mut self,
13354        _: &MoveToStartOfNextExcerpt,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        if matches!(self.mode, EditorMode::SingleLine) {
13359            cx.propagate();
13360            return;
13361        }
13362
13363        self.change_selections(Default::default(), window, cx, |s| {
13364            s.move_with(|map, selection| {
13365                selection.collapse_to(
13366                    movement::start_of_excerpt(
13367                        map,
13368                        selection.head(),
13369                        workspace::searchable::Direction::Next,
13370                    ),
13371                    SelectionGoal::None,
13372                )
13373            });
13374        })
13375    }
13376
13377    pub fn move_to_end_of_excerpt(
13378        &mut self,
13379        _: &MoveToEndOfExcerpt,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        if matches!(self.mode, EditorMode::SingleLine) {
13384            cx.propagate();
13385            return;
13386        }
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13388        self.change_selections(Default::default(), window, cx, |s| {
13389            s.move_with(|map, selection| {
13390                selection.collapse_to(
13391                    movement::end_of_excerpt(
13392                        map,
13393                        selection.head(),
13394                        workspace::searchable::Direction::Next,
13395                    ),
13396                    SelectionGoal::None,
13397                )
13398            });
13399        })
13400    }
13401
13402    pub fn move_to_end_of_previous_excerpt(
13403        &mut self,
13404        _: &MoveToEndOfPreviousExcerpt,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        if matches!(self.mode, EditorMode::SingleLine) {
13409            cx.propagate();
13410            return;
13411        }
13412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13413        self.change_selections(Default::default(), window, cx, |s| {
13414            s.move_with(|map, selection| {
13415                selection.collapse_to(
13416                    movement::end_of_excerpt(
13417                        map,
13418                        selection.head(),
13419                        workspace::searchable::Direction::Prev,
13420                    ),
13421                    SelectionGoal::None,
13422                )
13423            });
13424        })
13425    }
13426
13427    pub fn select_to_start_of_excerpt(
13428        &mut self,
13429        _: &SelectToStartOfExcerpt,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        if matches!(self.mode, EditorMode::SingleLine) {
13434            cx.propagate();
13435            return;
13436        }
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        self.change_selections(Default::default(), window, cx, |s| {
13439            s.move_heads_with(|map, head, _| {
13440                (
13441                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_start_of_next_excerpt(
13449        &mut self,
13450        _: &SelectToStartOfNextExcerpt,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        if matches!(self.mode, EditorMode::SingleLine) {
13455            cx.propagate();
13456            return;
13457        }
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_heads_with(|map, head, _| {
13461                (
13462                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13463                    SelectionGoal::None,
13464                )
13465            });
13466        })
13467    }
13468
13469    pub fn select_to_end_of_excerpt(
13470        &mut self,
13471        _: &SelectToEndOfExcerpt,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) {
13475        if matches!(self.mode, EditorMode::SingleLine) {
13476            cx.propagate();
13477            return;
13478        }
13479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13480        self.change_selections(Default::default(), window, cx, |s| {
13481            s.move_heads_with(|map, head, _| {
13482                (
13483                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13484                    SelectionGoal::None,
13485                )
13486            });
13487        })
13488    }
13489
13490    pub fn select_to_end_of_previous_excerpt(
13491        &mut self,
13492        _: &SelectToEndOfPreviousExcerpt,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        if matches!(self.mode, EditorMode::SingleLine) {
13497            cx.propagate();
13498            return;
13499        }
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13501        self.change_selections(Default::default(), window, cx, |s| {
13502            s.move_heads_with(|map, head, _| {
13503                (
13504                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13505                    SelectionGoal::None,
13506                )
13507            });
13508        })
13509    }
13510
13511    pub fn move_to_beginning(
13512        &mut self,
13513        _: &MoveToBeginning,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        if matches!(self.mode, EditorMode::SingleLine) {
13518            cx.propagate();
13519            return;
13520        }
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.select_ranges(vec![0..0]);
13524        });
13525    }
13526
13527    pub fn select_to_beginning(
13528        &mut self,
13529        _: &SelectToBeginning,
13530        window: &mut Window,
13531        cx: &mut Context<Self>,
13532    ) {
13533        let mut selection = self.selections.last::<Point>(cx);
13534        selection.set_head(Point::zero(), SelectionGoal::None);
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.select(vec![selection]);
13538        });
13539    }
13540
13541    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13542        if matches!(self.mode, EditorMode::SingleLine) {
13543            cx.propagate();
13544            return;
13545        }
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547        let cursor = self.buffer.read(cx).read(cx).len();
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.select_ranges(vec![cursor..cursor])
13550        });
13551    }
13552
13553    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13554        self.nav_history = nav_history;
13555    }
13556
13557    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13558        self.nav_history.as_ref()
13559    }
13560
13561    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13562        self.push_to_nav_history(
13563            self.selections.newest_anchor().head(),
13564            None,
13565            false,
13566            true,
13567            cx,
13568        );
13569    }
13570
13571    fn push_to_nav_history(
13572        &mut self,
13573        cursor_anchor: Anchor,
13574        new_position: Option<Point>,
13575        is_deactivate: bool,
13576        always: bool,
13577        cx: &mut Context<Self>,
13578    ) {
13579        if let Some(nav_history) = self.nav_history.as_mut() {
13580            let buffer = self.buffer.read(cx).read(cx);
13581            let cursor_position = cursor_anchor.to_point(&buffer);
13582            let scroll_state = self.scroll_manager.anchor();
13583            let scroll_top_row = scroll_state.top_row(&buffer);
13584            drop(buffer);
13585
13586            if let Some(new_position) = new_position {
13587                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13588                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13589                    return;
13590                }
13591            }
13592
13593            nav_history.push(
13594                Some(NavigationData {
13595                    cursor_anchor,
13596                    cursor_position,
13597                    scroll_anchor: scroll_state,
13598                    scroll_top_row,
13599                }),
13600                cx,
13601            );
13602            cx.emit(EditorEvent::PushedToNavHistory {
13603                anchor: cursor_anchor,
13604                is_deactivate,
13605            })
13606        }
13607    }
13608
13609    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        let buffer = self.buffer.read(cx).snapshot(cx);
13612        let mut selection = self.selections.first::<usize>(cx);
13613        selection.set_head(buffer.len(), SelectionGoal::None);
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.select(vec![selection]);
13616        });
13617    }
13618
13619    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        let end = self.buffer.read(cx).read(cx).len();
13622        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13623            s.select_ranges(vec![0..end]);
13624        });
13625    }
13626
13627    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13630        let mut selections = self.selections.all::<Point>(cx);
13631        let max_point = display_map.buffer_snapshot.max_point();
13632        for selection in &mut selections {
13633            let rows = selection.spanned_rows(true, &display_map);
13634            selection.start = Point::new(rows.start.0, 0);
13635            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13636            selection.reversed = false;
13637        }
13638        self.change_selections(Default::default(), window, cx, |s| {
13639            s.select(selections);
13640        });
13641    }
13642
13643    pub fn split_selection_into_lines(
13644        &mut self,
13645        action: &SplitSelectionIntoLines,
13646        window: &mut Window,
13647        cx: &mut Context<Self>,
13648    ) {
13649        let selections = self
13650            .selections
13651            .all::<Point>(cx)
13652            .into_iter()
13653            .map(|selection| selection.start..selection.end)
13654            .collect::<Vec<_>>();
13655        self.unfold_ranges(&selections, true, true, cx);
13656
13657        let mut new_selection_ranges = Vec::new();
13658        {
13659            let buffer = self.buffer.read(cx).read(cx);
13660            for selection in selections {
13661                for row in selection.start.row..selection.end.row {
13662                    let line_start = Point::new(row, 0);
13663                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13664
13665                    if action.keep_selections {
13666                        // Keep the selection range for each line
13667                        let selection_start = if row == selection.start.row {
13668                            selection.start
13669                        } else {
13670                            line_start
13671                        };
13672                        new_selection_ranges.push(selection_start..line_end);
13673                    } else {
13674                        // Collapse to cursor at end of line
13675                        new_selection_ranges.push(line_end..line_end);
13676                    }
13677                }
13678
13679                let is_multiline_selection = selection.start.row != selection.end.row;
13680                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13681                // so this action feels more ergonomic when paired with other selection operations
13682                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13683                if !should_skip_last {
13684                    if action.keep_selections {
13685                        if is_multiline_selection {
13686                            let line_start = Point::new(selection.end.row, 0);
13687                            new_selection_ranges.push(line_start..selection.end);
13688                        } else {
13689                            new_selection_ranges.push(selection.start..selection.end);
13690                        }
13691                    } else {
13692                        new_selection_ranges.push(selection.end..selection.end);
13693                    }
13694                }
13695            }
13696        }
13697        self.change_selections(Default::default(), window, cx, |s| {
13698            s.select_ranges(new_selection_ranges);
13699        });
13700    }
13701
13702    pub fn add_selection_above(
13703        &mut self,
13704        _: &AddSelectionAbove,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.add_selection(true, window, cx);
13709    }
13710
13711    pub fn add_selection_below(
13712        &mut self,
13713        _: &AddSelectionBelow,
13714        window: &mut Window,
13715        cx: &mut Context<Self>,
13716    ) {
13717        self.add_selection(false, window, cx);
13718    }
13719
13720    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13722
13723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13724        let all_selections = self.selections.all::<Point>(cx);
13725        let text_layout_details = self.text_layout_details(window);
13726
13727        let (mut columnar_selections, new_selections_to_columnarize) = {
13728            if let Some(state) = self.add_selections_state.as_ref() {
13729                let columnar_selection_ids: HashSet<_> = state
13730                    .groups
13731                    .iter()
13732                    .flat_map(|group| group.stack.iter())
13733                    .copied()
13734                    .collect();
13735
13736                all_selections
13737                    .into_iter()
13738                    .partition(|s| columnar_selection_ids.contains(&s.id))
13739            } else {
13740                (Vec::new(), all_selections)
13741            }
13742        };
13743
13744        let mut state = self
13745            .add_selections_state
13746            .take()
13747            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13748
13749        for selection in new_selections_to_columnarize {
13750            let range = selection.display_range(&display_map).sorted();
13751            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13752            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13753            let positions = start_x.min(end_x)..start_x.max(end_x);
13754            let mut stack = Vec::new();
13755            for row in range.start.row().0..=range.end.row().0 {
13756                if let Some(selection) = self.selections.build_columnar_selection(
13757                    &display_map,
13758                    DisplayRow(row),
13759                    &positions,
13760                    selection.reversed,
13761                    &text_layout_details,
13762                ) {
13763                    stack.push(selection.id);
13764                    columnar_selections.push(selection);
13765                }
13766            }
13767            if !stack.is_empty() {
13768                if above {
13769                    stack.reverse();
13770                }
13771                state.groups.push(AddSelectionsGroup { above, stack });
13772            }
13773        }
13774
13775        let mut final_selections = Vec::new();
13776        let end_row = if above {
13777            DisplayRow(0)
13778        } else {
13779            display_map.max_point().row()
13780        };
13781
13782        let mut last_added_item_per_group = HashMap::default();
13783        for group in state.groups.iter_mut() {
13784            if let Some(last_id) = group.stack.last() {
13785                last_added_item_per_group.insert(*last_id, group);
13786            }
13787        }
13788
13789        for selection in columnar_selections {
13790            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13791                if above == group.above {
13792                    let range = selection.display_range(&display_map).sorted();
13793                    debug_assert_eq!(range.start.row(), range.end.row());
13794                    let mut row = range.start.row();
13795                    let positions =
13796                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13797                            px(start)..px(end)
13798                        } else {
13799                            let start_x =
13800                                display_map.x_for_display_point(range.start, &text_layout_details);
13801                            let end_x =
13802                                display_map.x_for_display_point(range.end, &text_layout_details);
13803                            start_x.min(end_x)..start_x.max(end_x)
13804                        };
13805
13806                    let mut maybe_new_selection = None;
13807                    while row != end_row {
13808                        if above {
13809                            row.0 -= 1;
13810                        } else {
13811                            row.0 += 1;
13812                        }
13813                        if let Some(new_selection) = self.selections.build_columnar_selection(
13814                            &display_map,
13815                            row,
13816                            &positions,
13817                            selection.reversed,
13818                            &text_layout_details,
13819                        ) {
13820                            maybe_new_selection = Some(new_selection);
13821                            break;
13822                        }
13823                    }
13824
13825                    if let Some(new_selection) = maybe_new_selection {
13826                        group.stack.push(new_selection.id);
13827                        if above {
13828                            final_selections.push(new_selection);
13829                            final_selections.push(selection);
13830                        } else {
13831                            final_selections.push(selection);
13832                            final_selections.push(new_selection);
13833                        }
13834                    } else {
13835                        final_selections.push(selection);
13836                    }
13837                } else {
13838                    group.stack.pop();
13839                }
13840            } else {
13841                final_selections.push(selection);
13842            }
13843        }
13844
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.select(final_selections);
13847        });
13848
13849        let final_selection_ids: HashSet<_> = self
13850            .selections
13851            .all::<Point>(cx)
13852            .iter()
13853            .map(|s| s.id)
13854            .collect();
13855        state.groups.retain_mut(|group| {
13856            // selections might get merged above so we remove invalid items from stacks
13857            group.stack.retain(|id| final_selection_ids.contains(id));
13858
13859            // single selection in stack can be treated as initial state
13860            group.stack.len() > 1
13861        });
13862
13863        if !state.groups.is_empty() {
13864            self.add_selections_state = Some(state);
13865        }
13866    }
13867
13868    fn select_match_ranges(
13869        &mut self,
13870        range: Range<usize>,
13871        reversed: bool,
13872        replace_newest: bool,
13873        auto_scroll: Option<Autoscroll>,
13874        window: &mut Window,
13875        cx: &mut Context<Editor>,
13876    ) {
13877        self.unfold_ranges(
13878            std::slice::from_ref(&range),
13879            false,
13880            auto_scroll.is_some(),
13881            cx,
13882        );
13883        let effects = if let Some(scroll) = auto_scroll {
13884            SelectionEffects::scroll(scroll)
13885        } else {
13886            SelectionEffects::no_scroll()
13887        };
13888        self.change_selections(effects, window, cx, |s| {
13889            if replace_newest {
13890                s.delete(s.newest_anchor().id);
13891            }
13892            if reversed {
13893                s.insert_range(range.end..range.start);
13894            } else {
13895                s.insert_range(range);
13896            }
13897        });
13898    }
13899
13900    pub fn select_next_match_internal(
13901        &mut self,
13902        display_map: &DisplaySnapshot,
13903        replace_newest: bool,
13904        autoscroll: Option<Autoscroll>,
13905        window: &mut Window,
13906        cx: &mut Context<Self>,
13907    ) -> Result<()> {
13908        let buffer = &display_map.buffer_snapshot;
13909        let mut selections = self.selections.all::<usize>(cx);
13910        if let Some(mut select_next_state) = self.select_next_state.take() {
13911            let query = &select_next_state.query;
13912            if !select_next_state.done {
13913                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13914                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13915                let mut next_selected_range = None;
13916
13917                let bytes_after_last_selection =
13918                    buffer.bytes_in_range(last_selection.end..buffer.len());
13919                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13920                let query_matches = query
13921                    .stream_find_iter(bytes_after_last_selection)
13922                    .map(|result| (last_selection.end, result))
13923                    .chain(
13924                        query
13925                            .stream_find_iter(bytes_before_first_selection)
13926                            .map(|result| (0, result)),
13927                    );
13928
13929                for (start_offset, query_match) in query_matches {
13930                    let query_match = query_match.unwrap(); // can only fail due to I/O
13931                    let offset_range =
13932                        start_offset + query_match.start()..start_offset + query_match.end();
13933
13934                    if !select_next_state.wordwise
13935                        || (!buffer.is_inside_word(offset_range.start, false)
13936                            && !buffer.is_inside_word(offset_range.end, false))
13937                    {
13938                        // TODO: This is n^2, because we might check all the selections
13939                        if !selections
13940                            .iter()
13941                            .any(|selection| selection.range().overlaps(&offset_range))
13942                        {
13943                            next_selected_range = Some(offset_range);
13944                            break;
13945                        }
13946                    }
13947                }
13948
13949                if let Some(next_selected_range) = next_selected_range {
13950                    self.select_match_ranges(
13951                        next_selected_range,
13952                        last_selection.reversed,
13953                        replace_newest,
13954                        autoscroll,
13955                        window,
13956                        cx,
13957                    );
13958                } else {
13959                    select_next_state.done = true;
13960                }
13961            }
13962
13963            self.select_next_state = Some(select_next_state);
13964        } else {
13965            let mut only_carets = true;
13966            let mut same_text_selected = true;
13967            let mut selected_text = None;
13968
13969            let mut selections_iter = selections.iter().peekable();
13970            while let Some(selection) = selections_iter.next() {
13971                if selection.start != selection.end {
13972                    only_carets = false;
13973                }
13974
13975                if same_text_selected {
13976                    if selected_text.is_none() {
13977                        selected_text =
13978                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13979                    }
13980
13981                    if let Some(next_selection) = selections_iter.peek() {
13982                        if next_selection.range().len() == selection.range().len() {
13983                            let next_selected_text = buffer
13984                                .text_for_range(next_selection.range())
13985                                .collect::<String>();
13986                            if Some(next_selected_text) != selected_text {
13987                                same_text_selected = false;
13988                                selected_text = None;
13989                            }
13990                        } else {
13991                            same_text_selected = false;
13992                            selected_text = None;
13993                        }
13994                    }
13995                }
13996            }
13997
13998            if only_carets {
13999                for selection in &mut selections {
14000                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14001                    selection.start = word_range.start;
14002                    selection.end = word_range.end;
14003                    selection.goal = SelectionGoal::None;
14004                    selection.reversed = false;
14005                    self.select_match_ranges(
14006                        selection.start..selection.end,
14007                        selection.reversed,
14008                        replace_newest,
14009                        autoscroll,
14010                        window,
14011                        cx,
14012                    );
14013                }
14014
14015                if selections.len() == 1 {
14016                    let selection = selections
14017                        .last()
14018                        .expect("ensured that there's only one selection");
14019                    let query = buffer
14020                        .text_for_range(selection.start..selection.end)
14021                        .collect::<String>();
14022                    let is_empty = query.is_empty();
14023                    let select_state = SelectNextState {
14024                        query: AhoCorasick::new(&[query])?,
14025                        wordwise: true,
14026                        done: is_empty,
14027                    };
14028                    self.select_next_state = Some(select_state);
14029                } else {
14030                    self.select_next_state = None;
14031                }
14032            } else if let Some(selected_text) = selected_text {
14033                self.select_next_state = Some(SelectNextState {
14034                    query: AhoCorasick::new(&[selected_text])?,
14035                    wordwise: false,
14036                    done: false,
14037                });
14038                self.select_next_match_internal(
14039                    display_map,
14040                    replace_newest,
14041                    autoscroll,
14042                    window,
14043                    cx,
14044                )?;
14045            }
14046        }
14047        Ok(())
14048    }
14049
14050    pub fn select_all_matches(
14051        &mut self,
14052        _action: &SelectAllMatches,
14053        window: &mut Window,
14054        cx: &mut Context<Self>,
14055    ) -> Result<()> {
14056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14057
14058        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14059
14060        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14061        let Some(select_next_state) = self.select_next_state.as_mut() else {
14062            return Ok(());
14063        };
14064        if select_next_state.done {
14065            return Ok(());
14066        }
14067
14068        let mut new_selections = Vec::new();
14069
14070        let reversed = self.selections.oldest::<usize>(cx).reversed;
14071        let buffer = &display_map.buffer_snapshot;
14072        let query_matches = select_next_state
14073            .query
14074            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14075
14076        for query_match in query_matches.into_iter() {
14077            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14078            let offset_range = if reversed {
14079                query_match.end()..query_match.start()
14080            } else {
14081                query_match.start()..query_match.end()
14082            };
14083
14084            if !select_next_state.wordwise
14085                || (!buffer.is_inside_word(offset_range.start, false)
14086                    && !buffer.is_inside_word(offset_range.end, false))
14087            {
14088                new_selections.push(offset_range.start..offset_range.end);
14089            }
14090        }
14091
14092        select_next_state.done = true;
14093
14094        if new_selections.is_empty() {
14095            log::error!("bug: new_selections is empty in select_all_matches");
14096            return Ok(());
14097        }
14098
14099        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14100        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14101            selections.select_ranges(new_selections)
14102        });
14103
14104        Ok(())
14105    }
14106
14107    pub fn select_next(
14108        &mut self,
14109        action: &SelectNext,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) -> Result<()> {
14113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14114        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14115        self.select_next_match_internal(
14116            &display_map,
14117            action.replace_newest,
14118            Some(Autoscroll::newest()),
14119            window,
14120            cx,
14121        )?;
14122        Ok(())
14123    }
14124
14125    pub fn select_previous(
14126        &mut self,
14127        action: &SelectPrevious,
14128        window: &mut Window,
14129        cx: &mut Context<Self>,
14130    ) -> Result<()> {
14131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14132        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14133        let buffer = &display_map.buffer_snapshot;
14134        let mut selections = self.selections.all::<usize>(cx);
14135        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14136            let query = &select_prev_state.query;
14137            if !select_prev_state.done {
14138                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14139                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14140                let mut next_selected_range = None;
14141                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14142                let bytes_before_last_selection =
14143                    buffer.reversed_bytes_in_range(0..last_selection.start);
14144                let bytes_after_first_selection =
14145                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14146                let query_matches = query
14147                    .stream_find_iter(bytes_before_last_selection)
14148                    .map(|result| (last_selection.start, result))
14149                    .chain(
14150                        query
14151                            .stream_find_iter(bytes_after_first_selection)
14152                            .map(|result| (buffer.len(), result)),
14153                    );
14154                for (end_offset, query_match) in query_matches {
14155                    let query_match = query_match.unwrap(); // can only fail due to I/O
14156                    let offset_range =
14157                        end_offset - query_match.end()..end_offset - query_match.start();
14158
14159                    if !select_prev_state.wordwise
14160                        || (!buffer.is_inside_word(offset_range.start, false)
14161                            && !buffer.is_inside_word(offset_range.end, false))
14162                    {
14163                        next_selected_range = Some(offset_range);
14164                        break;
14165                    }
14166                }
14167
14168                if let Some(next_selected_range) = next_selected_range {
14169                    self.select_match_ranges(
14170                        next_selected_range,
14171                        last_selection.reversed,
14172                        action.replace_newest,
14173                        Some(Autoscroll::newest()),
14174                        window,
14175                        cx,
14176                    );
14177                } else {
14178                    select_prev_state.done = true;
14179                }
14180            }
14181
14182            self.select_prev_state = Some(select_prev_state);
14183        } else {
14184            let mut only_carets = true;
14185            let mut same_text_selected = true;
14186            let mut selected_text = None;
14187
14188            let mut selections_iter = selections.iter().peekable();
14189            while let Some(selection) = selections_iter.next() {
14190                if selection.start != selection.end {
14191                    only_carets = false;
14192                }
14193
14194                if same_text_selected {
14195                    if selected_text.is_none() {
14196                        selected_text =
14197                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14198                    }
14199
14200                    if let Some(next_selection) = selections_iter.peek() {
14201                        if next_selection.range().len() == selection.range().len() {
14202                            let next_selected_text = buffer
14203                                .text_for_range(next_selection.range())
14204                                .collect::<String>();
14205                            if Some(next_selected_text) != selected_text {
14206                                same_text_selected = false;
14207                                selected_text = None;
14208                            }
14209                        } else {
14210                            same_text_selected = false;
14211                            selected_text = None;
14212                        }
14213                    }
14214                }
14215            }
14216
14217            if only_carets {
14218                for selection in &mut selections {
14219                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14220                    selection.start = word_range.start;
14221                    selection.end = word_range.end;
14222                    selection.goal = SelectionGoal::None;
14223                    selection.reversed = false;
14224                    self.select_match_ranges(
14225                        selection.start..selection.end,
14226                        selection.reversed,
14227                        action.replace_newest,
14228                        Some(Autoscroll::newest()),
14229                        window,
14230                        cx,
14231                    );
14232                }
14233                if selections.len() == 1 {
14234                    let selection = selections
14235                        .last()
14236                        .expect("ensured that there's only one selection");
14237                    let query = buffer
14238                        .text_for_range(selection.start..selection.end)
14239                        .collect::<String>();
14240                    let is_empty = query.is_empty();
14241                    let select_state = SelectNextState {
14242                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14243                        wordwise: true,
14244                        done: is_empty,
14245                    };
14246                    self.select_prev_state = Some(select_state);
14247                } else {
14248                    self.select_prev_state = None;
14249                }
14250            } else if let Some(selected_text) = selected_text {
14251                self.select_prev_state = Some(SelectNextState {
14252                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14253                    wordwise: false,
14254                    done: false,
14255                });
14256                self.select_previous(action, window, cx)?;
14257            }
14258        }
14259        Ok(())
14260    }
14261
14262    pub fn find_next_match(
14263        &mut self,
14264        _: &FindNextMatch,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) -> Result<()> {
14268        let selections = self.selections.disjoint_anchors();
14269        match selections.first() {
14270            Some(first) if selections.len() >= 2 => {
14271                self.change_selections(Default::default(), window, cx, |s| {
14272                    s.select_ranges([first.range()]);
14273                });
14274            }
14275            _ => self.select_next(
14276                &SelectNext {
14277                    replace_newest: true,
14278                },
14279                window,
14280                cx,
14281            )?,
14282        }
14283        Ok(())
14284    }
14285
14286    pub fn find_previous_match(
14287        &mut self,
14288        _: &FindPreviousMatch,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) -> Result<()> {
14292        let selections = self.selections.disjoint_anchors();
14293        match selections.last() {
14294            Some(last) if selections.len() >= 2 => {
14295                self.change_selections(Default::default(), window, cx, |s| {
14296                    s.select_ranges([last.range()]);
14297                });
14298            }
14299            _ => self.select_previous(
14300                &SelectPrevious {
14301                    replace_newest: true,
14302                },
14303                window,
14304                cx,
14305            )?,
14306        }
14307        Ok(())
14308    }
14309
14310    pub fn toggle_comments(
14311        &mut self,
14312        action: &ToggleComments,
14313        window: &mut Window,
14314        cx: &mut Context<Self>,
14315    ) {
14316        if self.read_only(cx) {
14317            return;
14318        }
14319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14320        let text_layout_details = &self.text_layout_details(window);
14321        self.transact(window, cx, |this, window, cx| {
14322            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14323            let mut edits = Vec::new();
14324            let mut selection_edit_ranges = Vec::new();
14325            let mut last_toggled_row = None;
14326            let snapshot = this.buffer.read(cx).read(cx);
14327            let empty_str: Arc<str> = Arc::default();
14328            let mut suffixes_inserted = Vec::new();
14329            let ignore_indent = action.ignore_indent;
14330
14331            fn comment_prefix_range(
14332                snapshot: &MultiBufferSnapshot,
14333                row: MultiBufferRow,
14334                comment_prefix: &str,
14335                comment_prefix_whitespace: &str,
14336                ignore_indent: bool,
14337            ) -> Range<Point> {
14338                let indent_size = if ignore_indent {
14339                    0
14340                } else {
14341                    snapshot.indent_size_for_line(row).len
14342                };
14343
14344                let start = Point::new(row.0, indent_size);
14345
14346                let mut line_bytes = snapshot
14347                    .bytes_in_range(start..snapshot.max_point())
14348                    .flatten()
14349                    .copied();
14350
14351                // If this line currently begins with the line comment prefix, then record
14352                // the range containing the prefix.
14353                if line_bytes
14354                    .by_ref()
14355                    .take(comment_prefix.len())
14356                    .eq(comment_prefix.bytes())
14357                {
14358                    // Include any whitespace that matches the comment prefix.
14359                    let matching_whitespace_len = line_bytes
14360                        .zip(comment_prefix_whitespace.bytes())
14361                        .take_while(|(a, b)| a == b)
14362                        .count() as u32;
14363                    let end = Point::new(
14364                        start.row,
14365                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14366                    );
14367                    start..end
14368                } else {
14369                    start..start
14370                }
14371            }
14372
14373            fn comment_suffix_range(
14374                snapshot: &MultiBufferSnapshot,
14375                row: MultiBufferRow,
14376                comment_suffix: &str,
14377                comment_suffix_has_leading_space: bool,
14378            ) -> Range<Point> {
14379                let end = Point::new(row.0, snapshot.line_len(row));
14380                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14381
14382                let mut line_end_bytes = snapshot
14383                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14384                    .flatten()
14385                    .copied();
14386
14387                let leading_space_len = if suffix_start_column > 0
14388                    && line_end_bytes.next() == Some(b' ')
14389                    && comment_suffix_has_leading_space
14390                {
14391                    1
14392                } else {
14393                    0
14394                };
14395
14396                // If this line currently begins with the line comment prefix, then record
14397                // the range containing the prefix.
14398                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14399                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14400                    start..end
14401                } else {
14402                    end..end
14403                }
14404            }
14405
14406            // TODO: Handle selections that cross excerpts
14407            for selection in &mut selections {
14408                let start_column = snapshot
14409                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14410                    .len;
14411                let language = if let Some(language) =
14412                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14413                {
14414                    language
14415                } else {
14416                    continue;
14417                };
14418
14419                selection_edit_ranges.clear();
14420
14421                // If multiple selections contain a given row, avoid processing that
14422                // row more than once.
14423                let mut start_row = MultiBufferRow(selection.start.row);
14424                if last_toggled_row == Some(start_row) {
14425                    start_row = start_row.next_row();
14426                }
14427                let end_row =
14428                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14429                        MultiBufferRow(selection.end.row - 1)
14430                    } else {
14431                        MultiBufferRow(selection.end.row)
14432                    };
14433                last_toggled_row = Some(end_row);
14434
14435                if start_row > end_row {
14436                    continue;
14437                }
14438
14439                // If the language has line comments, toggle those.
14440                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14441
14442                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14443                if ignore_indent {
14444                    full_comment_prefixes = full_comment_prefixes
14445                        .into_iter()
14446                        .map(|s| Arc::from(s.trim_end()))
14447                        .collect();
14448                }
14449
14450                if !full_comment_prefixes.is_empty() {
14451                    let first_prefix = full_comment_prefixes
14452                        .first()
14453                        .expect("prefixes is non-empty");
14454                    let prefix_trimmed_lengths = full_comment_prefixes
14455                        .iter()
14456                        .map(|p| p.trim_end_matches(' ').len())
14457                        .collect::<SmallVec<[usize; 4]>>();
14458
14459                    let mut all_selection_lines_are_comments = true;
14460
14461                    for row in start_row.0..=end_row.0 {
14462                        let row = MultiBufferRow(row);
14463                        if start_row < end_row && snapshot.is_line_blank(row) {
14464                            continue;
14465                        }
14466
14467                        let prefix_range = full_comment_prefixes
14468                            .iter()
14469                            .zip(prefix_trimmed_lengths.iter().copied())
14470                            .map(|(prefix, trimmed_prefix_len)| {
14471                                comment_prefix_range(
14472                                    snapshot.deref(),
14473                                    row,
14474                                    &prefix[..trimmed_prefix_len],
14475                                    &prefix[trimmed_prefix_len..],
14476                                    ignore_indent,
14477                                )
14478                            })
14479                            .max_by_key(|range| range.end.column - range.start.column)
14480                            .expect("prefixes is non-empty");
14481
14482                        if prefix_range.is_empty() {
14483                            all_selection_lines_are_comments = false;
14484                        }
14485
14486                        selection_edit_ranges.push(prefix_range);
14487                    }
14488
14489                    if all_selection_lines_are_comments {
14490                        edits.extend(
14491                            selection_edit_ranges
14492                                .iter()
14493                                .cloned()
14494                                .map(|range| (range, empty_str.clone())),
14495                        );
14496                    } else {
14497                        let min_column = selection_edit_ranges
14498                            .iter()
14499                            .map(|range| range.start.column)
14500                            .min()
14501                            .unwrap_or(0);
14502                        edits.extend(selection_edit_ranges.iter().map(|range| {
14503                            let position = Point::new(range.start.row, min_column);
14504                            (position..position, first_prefix.clone())
14505                        }));
14506                    }
14507                } else if let Some(BlockCommentConfig {
14508                    start: full_comment_prefix,
14509                    end: comment_suffix,
14510                    ..
14511                }) = language.block_comment()
14512                {
14513                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14514                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14515                    let prefix_range = comment_prefix_range(
14516                        snapshot.deref(),
14517                        start_row,
14518                        comment_prefix,
14519                        comment_prefix_whitespace,
14520                        ignore_indent,
14521                    );
14522                    let suffix_range = comment_suffix_range(
14523                        snapshot.deref(),
14524                        end_row,
14525                        comment_suffix.trim_start_matches(' '),
14526                        comment_suffix.starts_with(' '),
14527                    );
14528
14529                    if prefix_range.is_empty() || suffix_range.is_empty() {
14530                        edits.push((
14531                            prefix_range.start..prefix_range.start,
14532                            full_comment_prefix.clone(),
14533                        ));
14534                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14535                        suffixes_inserted.push((end_row, comment_suffix.len()));
14536                    } else {
14537                        edits.push((prefix_range, empty_str.clone()));
14538                        edits.push((suffix_range, empty_str.clone()));
14539                    }
14540                } else {
14541                    continue;
14542                }
14543            }
14544
14545            drop(snapshot);
14546            this.buffer.update(cx, |buffer, cx| {
14547                buffer.edit(edits, None, cx);
14548            });
14549
14550            // Adjust selections so that they end before any comment suffixes that
14551            // were inserted.
14552            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14553            let mut selections = this.selections.all::<Point>(cx);
14554            let snapshot = this.buffer.read(cx).read(cx);
14555            for selection in &mut selections {
14556                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14557                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14558                        Ordering::Less => {
14559                            suffixes_inserted.next();
14560                            continue;
14561                        }
14562                        Ordering::Greater => break,
14563                        Ordering::Equal => {
14564                            if selection.end.column == snapshot.line_len(row) {
14565                                if selection.is_empty() {
14566                                    selection.start.column -= suffix_len as u32;
14567                                }
14568                                selection.end.column -= suffix_len as u32;
14569                            }
14570                            break;
14571                        }
14572                    }
14573                }
14574            }
14575
14576            drop(snapshot);
14577            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14578
14579            let selections = this.selections.all::<Point>(cx);
14580            let selections_on_single_row = selections.windows(2).all(|selections| {
14581                selections[0].start.row == selections[1].start.row
14582                    && selections[0].end.row == selections[1].end.row
14583                    && selections[0].start.row == selections[0].end.row
14584            });
14585            let selections_selecting = selections
14586                .iter()
14587                .any(|selection| selection.start != selection.end);
14588            let advance_downwards = action.advance_downwards
14589                && selections_on_single_row
14590                && !selections_selecting
14591                && !matches!(this.mode, EditorMode::SingleLine);
14592
14593            if advance_downwards {
14594                let snapshot = this.buffer.read(cx).snapshot(cx);
14595
14596                this.change_selections(Default::default(), window, cx, |s| {
14597                    s.move_cursors_with(|display_snapshot, display_point, _| {
14598                        let mut point = display_point.to_point(display_snapshot);
14599                        point.row += 1;
14600                        point = snapshot.clip_point(point, Bias::Left);
14601                        let display_point = point.to_display_point(display_snapshot);
14602                        let goal = SelectionGoal::HorizontalPosition(
14603                            display_snapshot
14604                                .x_for_display_point(display_point, text_layout_details)
14605                                .into(),
14606                        );
14607                        (display_point, goal)
14608                    })
14609                });
14610            }
14611        });
14612    }
14613
14614    pub fn select_enclosing_symbol(
14615        &mut self,
14616        _: &SelectEnclosingSymbol,
14617        window: &mut Window,
14618        cx: &mut Context<Self>,
14619    ) {
14620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14621
14622        let buffer = self.buffer.read(cx).snapshot(cx);
14623        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14624
14625        fn update_selection(
14626            selection: &Selection<usize>,
14627            buffer_snap: &MultiBufferSnapshot,
14628        ) -> Option<Selection<usize>> {
14629            let cursor = selection.head();
14630            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14631            for symbol in symbols.iter().rev() {
14632                let start = symbol.range.start.to_offset(buffer_snap);
14633                let end = symbol.range.end.to_offset(buffer_snap);
14634                let new_range = start..end;
14635                if start < selection.start || end > selection.end {
14636                    return Some(Selection {
14637                        id: selection.id,
14638                        start: new_range.start,
14639                        end: new_range.end,
14640                        goal: SelectionGoal::None,
14641                        reversed: selection.reversed,
14642                    });
14643                }
14644            }
14645            None
14646        }
14647
14648        let mut selected_larger_symbol = false;
14649        let new_selections = old_selections
14650            .iter()
14651            .map(|selection| match update_selection(selection, &buffer) {
14652                Some(new_selection) => {
14653                    if new_selection.range() != selection.range() {
14654                        selected_larger_symbol = true;
14655                    }
14656                    new_selection
14657                }
14658                None => selection.clone(),
14659            })
14660            .collect::<Vec<_>>();
14661
14662        if selected_larger_symbol {
14663            self.change_selections(Default::default(), window, cx, |s| {
14664                s.select(new_selections);
14665            });
14666        }
14667    }
14668
14669    pub fn select_larger_syntax_node(
14670        &mut self,
14671        _: &SelectLargerSyntaxNode,
14672        window: &mut Window,
14673        cx: &mut Context<Self>,
14674    ) {
14675        let Some(visible_row_count) = self.visible_row_count() else {
14676            return;
14677        };
14678        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14679        if old_selections.is_empty() {
14680            return;
14681        }
14682
14683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14684
14685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14686        let buffer = self.buffer.read(cx).snapshot(cx);
14687
14688        let mut selected_larger_node = false;
14689        let mut new_selections = old_selections
14690            .iter()
14691            .map(|selection| {
14692                let old_range = selection.start..selection.end;
14693
14694                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14695                    // manually select word at selection
14696                    if ["string_content", "inline"].contains(&node.kind()) {
14697                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14698                        // ignore if word is already selected
14699                        if !word_range.is_empty() && old_range != word_range {
14700                            let (last_word_range, _) =
14701                                buffer.surrounding_word(old_range.end, false);
14702                            // only select word if start and end point belongs to same word
14703                            if word_range == last_word_range {
14704                                selected_larger_node = true;
14705                                return Selection {
14706                                    id: selection.id,
14707                                    start: word_range.start,
14708                                    end: word_range.end,
14709                                    goal: SelectionGoal::None,
14710                                    reversed: selection.reversed,
14711                                };
14712                            }
14713                        }
14714                    }
14715                }
14716
14717                let mut new_range = old_range.clone();
14718                while let Some((_node, containing_range)) =
14719                    buffer.syntax_ancestor(new_range.clone())
14720                {
14721                    new_range = match containing_range {
14722                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14723                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14724                    };
14725                    if !display_map.intersects_fold(new_range.start)
14726                        && !display_map.intersects_fold(new_range.end)
14727                    {
14728                        break;
14729                    }
14730                }
14731
14732                selected_larger_node |= new_range != old_range;
14733                Selection {
14734                    id: selection.id,
14735                    start: new_range.start,
14736                    end: new_range.end,
14737                    goal: SelectionGoal::None,
14738                    reversed: selection.reversed,
14739                }
14740            })
14741            .collect::<Vec<_>>();
14742
14743        if !selected_larger_node {
14744            return; // don't put this call in the history
14745        }
14746
14747        // scroll based on transformation done to the last selection created by the user
14748        let (last_old, last_new) = old_selections
14749            .last()
14750            .zip(new_selections.last().cloned())
14751            .expect("old_selections isn't empty");
14752
14753        // revert selection
14754        let is_selection_reversed = {
14755            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14756            new_selections.last_mut().expect("checked above").reversed =
14757                should_newest_selection_be_reversed;
14758            should_newest_selection_be_reversed
14759        };
14760
14761        if selected_larger_node {
14762            self.select_syntax_node_history.disable_clearing = true;
14763            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14764                s.select(new_selections.clone());
14765            });
14766            self.select_syntax_node_history.disable_clearing = false;
14767        }
14768
14769        let start_row = last_new.start.to_display_point(&display_map).row().0;
14770        let end_row = last_new.end.to_display_point(&display_map).row().0;
14771        let selection_height = end_row - start_row + 1;
14772        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14773
14774        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14775        let scroll_behavior = if fits_on_the_screen {
14776            self.request_autoscroll(Autoscroll::fit(), cx);
14777            SelectSyntaxNodeScrollBehavior::FitSelection
14778        } else if is_selection_reversed {
14779            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14780            SelectSyntaxNodeScrollBehavior::CursorTop
14781        } else {
14782            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14783            SelectSyntaxNodeScrollBehavior::CursorBottom
14784        };
14785
14786        self.select_syntax_node_history.push((
14787            old_selections,
14788            scroll_behavior,
14789            is_selection_reversed,
14790        ));
14791    }
14792
14793    pub fn select_smaller_syntax_node(
14794        &mut self,
14795        _: &SelectSmallerSyntaxNode,
14796        window: &mut Window,
14797        cx: &mut Context<Self>,
14798    ) {
14799        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14800
14801        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14802            self.select_syntax_node_history.pop()
14803        {
14804            if let Some(selection) = selections.last_mut() {
14805                selection.reversed = is_selection_reversed;
14806            }
14807
14808            self.select_syntax_node_history.disable_clearing = true;
14809            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14810                s.select(selections.to_vec());
14811            });
14812            self.select_syntax_node_history.disable_clearing = false;
14813
14814            match scroll_behavior {
14815                SelectSyntaxNodeScrollBehavior::CursorTop => {
14816                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14817                }
14818                SelectSyntaxNodeScrollBehavior::FitSelection => {
14819                    self.request_autoscroll(Autoscroll::fit(), cx);
14820                }
14821                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14822                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14823                }
14824            }
14825        }
14826    }
14827
14828    pub fn unwrap_syntax_node(
14829        &mut self,
14830        _: &UnwrapSyntaxNode,
14831        window: &mut Window,
14832        cx: &mut Context<Self>,
14833    ) {
14834        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14835
14836        let buffer = self.buffer.read(cx).snapshot(cx);
14837        let selections = self
14838            .selections
14839            .all::<usize>(cx)
14840            .into_iter()
14841            // subtracting the offset requires sorting
14842            .sorted_by_key(|i| i.start);
14843
14844        let full_edits = selections
14845            .into_iter()
14846            .filter_map(|selection| {
14847                // Only requires two branches once if-let-chains stabilize (#53667)
14848                let child = if !selection.is_empty() {
14849                    selection.range()
14850                } else if let Some((_, ancestor_range)) =
14851                    buffer.syntax_ancestor(selection.start..selection.end)
14852                {
14853                    match ancestor_range {
14854                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14855                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14856                    }
14857                } else {
14858                    selection.range()
14859                };
14860
14861                let mut parent = child.clone();
14862                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14863                    parent = match ancestor_range {
14864                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14865                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14866                    };
14867                    if parent.start < child.start || parent.end > child.end {
14868                        break;
14869                    }
14870                }
14871
14872                if parent == child {
14873                    return None;
14874                }
14875                let text = buffer.text_for_range(child).collect::<String>();
14876                Some((selection.id, parent, text))
14877            })
14878            .collect::<Vec<_>>();
14879
14880        self.transact(window, cx, |this, window, cx| {
14881            this.buffer.update(cx, |buffer, cx| {
14882                buffer.edit(
14883                    full_edits
14884                        .iter()
14885                        .map(|(_, p, t)| (p.clone(), t.clone()))
14886                        .collect::<Vec<_>>(),
14887                    None,
14888                    cx,
14889                );
14890            });
14891            this.change_selections(Default::default(), window, cx, |s| {
14892                let mut offset = 0;
14893                let mut selections = vec![];
14894                for (id, parent, text) in full_edits {
14895                    let start = parent.start - offset;
14896                    offset += parent.len() - text.len();
14897                    selections.push(Selection {
14898                        id,
14899                        start,
14900                        end: start + text.len(),
14901                        reversed: false,
14902                        goal: Default::default(),
14903                    });
14904                }
14905                s.select(selections);
14906            });
14907        });
14908    }
14909
14910    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14911        if !EditorSettings::get_global(cx).gutter.runnables {
14912            self.clear_tasks();
14913            return Task::ready(());
14914        }
14915        let project = self.project().map(Entity::downgrade);
14916        let task_sources = self.lsp_task_sources(cx);
14917        let multi_buffer = self.buffer.downgrade();
14918        cx.spawn_in(window, async move |editor, cx| {
14919            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14920            let Some(project) = project.and_then(|p| p.upgrade()) else {
14921                return;
14922            };
14923            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14924                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14925            }) else {
14926                return;
14927            };
14928
14929            let hide_runnables = project
14930                .update(cx, |project, _| project.is_via_collab())
14931                .unwrap_or(true);
14932            if hide_runnables {
14933                return;
14934            }
14935            let new_rows =
14936                cx.background_spawn({
14937                    let snapshot = display_snapshot.clone();
14938                    async move {
14939                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14940                    }
14941                })
14942                    .await;
14943            let Ok(lsp_tasks) =
14944                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14945            else {
14946                return;
14947            };
14948            let lsp_tasks = lsp_tasks.await;
14949
14950            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14951                lsp_tasks
14952                    .into_iter()
14953                    .flat_map(|(kind, tasks)| {
14954                        tasks.into_iter().filter_map(move |(location, task)| {
14955                            Some((kind.clone(), location?, task))
14956                        })
14957                    })
14958                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14959                        let buffer = location.target.buffer;
14960                        let buffer_snapshot = buffer.read(cx).snapshot();
14961                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14962                            |(excerpt_id, snapshot, _)| {
14963                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14964                                    display_snapshot
14965                                        .buffer_snapshot
14966                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14967                                } else {
14968                                    None
14969                                }
14970                            },
14971                        );
14972                        if let Some(offset) = offset {
14973                            let task_buffer_range =
14974                                location.target.range.to_point(&buffer_snapshot);
14975                            let context_buffer_range =
14976                                task_buffer_range.to_offset(&buffer_snapshot);
14977                            let context_range = BufferOffset(context_buffer_range.start)
14978                                ..BufferOffset(context_buffer_range.end);
14979
14980                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14981                                .or_insert_with(|| RunnableTasks {
14982                                    templates: Vec::new(),
14983                                    offset,
14984                                    column: task_buffer_range.start.column,
14985                                    extra_variables: HashMap::default(),
14986                                    context_range,
14987                                })
14988                                .templates
14989                                .push((kind, task.original_task().clone()));
14990                        }
14991
14992                        acc
14993                    })
14994            }) else {
14995                return;
14996            };
14997
14998            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14999                buffer.language_settings(cx).tasks.prefer_lsp
15000            }) else {
15001                return;
15002            };
15003
15004            let rows = Self::runnable_rows(
15005                project,
15006                display_snapshot,
15007                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15008                new_rows,
15009                cx.clone(),
15010            )
15011            .await;
15012            editor
15013                .update(cx, |editor, _| {
15014                    editor.clear_tasks();
15015                    for (key, mut value) in rows {
15016                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15017                            value.templates.extend(lsp_tasks.templates);
15018                        }
15019
15020                        editor.insert_tasks(key, value);
15021                    }
15022                    for (key, value) in lsp_tasks_by_rows {
15023                        editor.insert_tasks(key, value);
15024                    }
15025                })
15026                .ok();
15027        })
15028    }
15029    fn fetch_runnable_ranges(
15030        snapshot: &DisplaySnapshot,
15031        range: Range<Anchor>,
15032    ) -> Vec<language::RunnableRange> {
15033        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15034    }
15035
15036    fn runnable_rows(
15037        project: Entity<Project>,
15038        snapshot: DisplaySnapshot,
15039        prefer_lsp: bool,
15040        runnable_ranges: Vec<RunnableRange>,
15041        cx: AsyncWindowContext,
15042    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15043        cx.spawn(async move |cx| {
15044            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15045            for mut runnable in runnable_ranges {
15046                let Some(tasks) = cx
15047                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15048                    .ok()
15049                else {
15050                    continue;
15051                };
15052                let mut tasks = tasks.await;
15053
15054                if prefer_lsp {
15055                    tasks.retain(|(task_kind, _)| {
15056                        !matches!(task_kind, TaskSourceKind::Language { .. })
15057                    });
15058                }
15059                if tasks.is_empty() {
15060                    continue;
15061                }
15062
15063                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15064                let Some(row) = snapshot
15065                    .buffer_snapshot
15066                    .buffer_line_for_row(MultiBufferRow(point.row))
15067                    .map(|(_, range)| range.start.row)
15068                else {
15069                    continue;
15070                };
15071
15072                let context_range =
15073                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15074                runnable_rows.push((
15075                    (runnable.buffer_id, row),
15076                    RunnableTasks {
15077                        templates: tasks,
15078                        offset: snapshot
15079                            .buffer_snapshot
15080                            .anchor_before(runnable.run_range.start),
15081                        context_range,
15082                        column: point.column,
15083                        extra_variables: runnable.extra_captures,
15084                    },
15085                ));
15086            }
15087            runnable_rows
15088        })
15089    }
15090
15091    fn templates_with_tags(
15092        project: &Entity<Project>,
15093        runnable: &mut Runnable,
15094        cx: &mut App,
15095    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15096        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15097            let (worktree_id, file) = project
15098                .buffer_for_id(runnable.buffer, cx)
15099                .and_then(|buffer| buffer.read(cx).file())
15100                .map(|file| (file.worktree_id(cx), file.clone()))
15101                .unzip();
15102
15103            (
15104                project.task_store().read(cx).task_inventory().cloned(),
15105                worktree_id,
15106                file,
15107            )
15108        });
15109
15110        let tags = mem::take(&mut runnable.tags);
15111        let language = runnable.language.clone();
15112        cx.spawn(async move |cx| {
15113            let mut templates_with_tags = Vec::new();
15114            if let Some(inventory) = inventory {
15115                for RunnableTag(tag) in tags {
15116                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15117                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15118                    }) else {
15119                        return templates_with_tags;
15120                    };
15121                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15122                        move |(_, template)| {
15123                            template.tags.iter().any(|source_tag| source_tag == &tag)
15124                        },
15125                    ));
15126                }
15127            }
15128            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15129
15130            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15131                // Strongest source wins; if we have worktree tag binding, prefer that to
15132                // global and language bindings;
15133                // if we have a global binding, prefer that to language binding.
15134                let first_mismatch = templates_with_tags
15135                    .iter()
15136                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15137                if let Some(index) = first_mismatch {
15138                    templates_with_tags.truncate(index);
15139                }
15140            }
15141
15142            templates_with_tags
15143        })
15144    }
15145
15146    pub fn move_to_enclosing_bracket(
15147        &mut self,
15148        _: &MoveToEnclosingBracket,
15149        window: &mut Window,
15150        cx: &mut Context<Self>,
15151    ) {
15152        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15153        self.change_selections(Default::default(), window, cx, |s| {
15154            s.move_offsets_with(|snapshot, selection| {
15155                let Some(enclosing_bracket_ranges) =
15156                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15157                else {
15158                    return;
15159                };
15160
15161                let mut best_length = usize::MAX;
15162                let mut best_inside = false;
15163                let mut best_in_bracket_range = false;
15164                let mut best_destination = None;
15165                for (open, close) in enclosing_bracket_ranges {
15166                    let close = close.to_inclusive();
15167                    let length = close.end() - open.start;
15168                    let inside = selection.start >= open.end && selection.end <= *close.start();
15169                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15170                        || close.contains(&selection.head());
15171
15172                    // If best is next to a bracket and current isn't, skip
15173                    if !in_bracket_range && best_in_bracket_range {
15174                        continue;
15175                    }
15176
15177                    // Prefer smaller lengths unless best is inside and current isn't
15178                    if length > best_length && (best_inside || !inside) {
15179                        continue;
15180                    }
15181
15182                    best_length = length;
15183                    best_inside = inside;
15184                    best_in_bracket_range = in_bracket_range;
15185                    best_destination = Some(
15186                        if close.contains(&selection.start) && close.contains(&selection.end) {
15187                            if inside { open.end } else { open.start }
15188                        } else if inside {
15189                            *close.start()
15190                        } else {
15191                            *close.end()
15192                        },
15193                    );
15194                }
15195
15196                if let Some(destination) = best_destination {
15197                    selection.collapse_to(destination, SelectionGoal::None);
15198                }
15199            })
15200        });
15201    }
15202
15203    pub fn undo_selection(
15204        &mut self,
15205        _: &UndoSelection,
15206        window: &mut Window,
15207        cx: &mut Context<Self>,
15208    ) {
15209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15210        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15211            self.selection_history.mode = SelectionHistoryMode::Undoing;
15212            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15213                this.end_selection(window, cx);
15214                this.change_selections(
15215                    SelectionEffects::scroll(Autoscroll::newest()),
15216                    window,
15217                    cx,
15218                    |s| s.select_anchors(entry.selections.to_vec()),
15219                );
15220            });
15221            self.selection_history.mode = SelectionHistoryMode::Normal;
15222
15223            self.select_next_state = entry.select_next_state;
15224            self.select_prev_state = entry.select_prev_state;
15225            self.add_selections_state = entry.add_selections_state;
15226        }
15227    }
15228
15229    pub fn redo_selection(
15230        &mut self,
15231        _: &RedoSelection,
15232        window: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15236        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15237            self.selection_history.mode = SelectionHistoryMode::Redoing;
15238            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15239                this.end_selection(window, cx);
15240                this.change_selections(
15241                    SelectionEffects::scroll(Autoscroll::newest()),
15242                    window,
15243                    cx,
15244                    |s| s.select_anchors(entry.selections.to_vec()),
15245                );
15246            });
15247            self.selection_history.mode = SelectionHistoryMode::Normal;
15248
15249            self.select_next_state = entry.select_next_state;
15250            self.select_prev_state = entry.select_prev_state;
15251            self.add_selections_state = entry.add_selections_state;
15252        }
15253    }
15254
15255    pub fn expand_excerpts(
15256        &mut self,
15257        action: &ExpandExcerpts,
15258        _: &mut Window,
15259        cx: &mut Context<Self>,
15260    ) {
15261        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15262    }
15263
15264    pub fn expand_excerpts_down(
15265        &mut self,
15266        action: &ExpandExcerptsDown,
15267        _: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) {
15270        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15271    }
15272
15273    pub fn expand_excerpts_up(
15274        &mut self,
15275        action: &ExpandExcerptsUp,
15276        _: &mut Window,
15277        cx: &mut Context<Self>,
15278    ) {
15279        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15280    }
15281
15282    pub fn expand_excerpts_for_direction(
15283        &mut self,
15284        lines: u32,
15285        direction: ExpandExcerptDirection,
15286
15287        cx: &mut Context<Self>,
15288    ) {
15289        let selections = self.selections.disjoint_anchors();
15290
15291        let lines = if lines == 0 {
15292            EditorSettings::get_global(cx).expand_excerpt_lines
15293        } else {
15294            lines
15295        };
15296
15297        self.buffer.update(cx, |buffer, cx| {
15298            let snapshot = buffer.snapshot(cx);
15299            let mut excerpt_ids = selections
15300                .iter()
15301                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15302                .collect::<Vec<_>>();
15303            excerpt_ids.sort();
15304            excerpt_ids.dedup();
15305            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15306        })
15307    }
15308
15309    pub fn expand_excerpt(
15310        &mut self,
15311        excerpt: ExcerptId,
15312        direction: ExpandExcerptDirection,
15313        window: &mut Window,
15314        cx: &mut Context<Self>,
15315    ) {
15316        let current_scroll_position = self.scroll_position(cx);
15317        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15318        let mut should_scroll_up = false;
15319
15320        if direction == ExpandExcerptDirection::Down {
15321            let multi_buffer = self.buffer.read(cx);
15322            let snapshot = multi_buffer.snapshot(cx);
15323            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15324                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15325                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15326            {
15327                let buffer_snapshot = buffer.read(cx).snapshot();
15328                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15329                let last_row = buffer_snapshot.max_point().row;
15330                let lines_below = last_row.saturating_sub(excerpt_end_row);
15331                should_scroll_up = lines_below >= lines_to_expand;
15332            }
15333        }
15334
15335        self.buffer.update(cx, |buffer, cx| {
15336            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15337        });
15338
15339        if should_scroll_up {
15340            let new_scroll_position =
15341                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15342            self.set_scroll_position(new_scroll_position, window, cx);
15343        }
15344    }
15345
15346    pub fn go_to_singleton_buffer_point(
15347        &mut self,
15348        point: Point,
15349        window: &mut Window,
15350        cx: &mut Context<Self>,
15351    ) {
15352        self.go_to_singleton_buffer_range(point..point, window, cx);
15353    }
15354
15355    pub fn go_to_singleton_buffer_range(
15356        &mut self,
15357        range: Range<Point>,
15358        window: &mut Window,
15359        cx: &mut Context<Self>,
15360    ) {
15361        let multibuffer = self.buffer().read(cx);
15362        let Some(buffer) = multibuffer.as_singleton() else {
15363            return;
15364        };
15365        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15366            return;
15367        };
15368        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15369            return;
15370        };
15371        self.change_selections(
15372            SelectionEffects::default().nav_history(true),
15373            window,
15374            cx,
15375            |s| s.select_anchor_ranges([start..end]),
15376        );
15377    }
15378
15379    pub fn go_to_diagnostic(
15380        &mut self,
15381        action: &GoToDiagnostic,
15382        window: &mut Window,
15383        cx: &mut Context<Self>,
15384    ) {
15385        if !self.diagnostics_enabled() {
15386            return;
15387        }
15388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15389        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15390    }
15391
15392    pub fn go_to_prev_diagnostic(
15393        &mut self,
15394        action: &GoToPreviousDiagnostic,
15395        window: &mut Window,
15396        cx: &mut Context<Self>,
15397    ) {
15398        if !self.diagnostics_enabled() {
15399            return;
15400        }
15401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15402        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15403    }
15404
15405    pub fn go_to_diagnostic_impl(
15406        &mut self,
15407        direction: Direction,
15408        severity: GoToDiagnosticSeverityFilter,
15409        window: &mut Window,
15410        cx: &mut Context<Self>,
15411    ) {
15412        let buffer = self.buffer.read(cx).snapshot(cx);
15413        let selection = self.selections.newest::<usize>(cx);
15414
15415        let mut active_group_id = None;
15416        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15417            && active_group.active_range.start.to_offset(&buffer) == selection.start
15418        {
15419            active_group_id = Some(active_group.group_id);
15420        }
15421
15422        fn filtered(
15423            snapshot: EditorSnapshot,
15424            severity: GoToDiagnosticSeverityFilter,
15425            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15426        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15427            diagnostics
15428                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15429                .filter(|entry| entry.range.start != entry.range.end)
15430                .filter(|entry| !entry.diagnostic.is_unnecessary)
15431                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15432        }
15433
15434        let snapshot = self.snapshot(window, cx);
15435        let before = filtered(
15436            snapshot.clone(),
15437            severity,
15438            buffer
15439                .diagnostics_in_range(0..selection.start)
15440                .filter(|entry| entry.range.start <= selection.start),
15441        );
15442        let after = filtered(
15443            snapshot,
15444            severity,
15445            buffer
15446                .diagnostics_in_range(selection.start..buffer.len())
15447                .filter(|entry| entry.range.start >= selection.start),
15448        );
15449
15450        let mut found: Option<DiagnosticEntry<usize>> = None;
15451        if direction == Direction::Prev {
15452            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15453            {
15454                for diagnostic in prev_diagnostics.into_iter().rev() {
15455                    if diagnostic.range.start != selection.start
15456                        || active_group_id
15457                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15458                    {
15459                        found = Some(diagnostic);
15460                        break 'outer;
15461                    }
15462                }
15463            }
15464        } else {
15465            for diagnostic in after.chain(before) {
15466                if diagnostic.range.start != selection.start
15467                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15468                {
15469                    found = Some(diagnostic);
15470                    break;
15471                }
15472            }
15473        }
15474        let Some(next_diagnostic) = found else {
15475            return;
15476        };
15477
15478        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15479        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15480            return;
15481        };
15482        self.change_selections(Default::default(), window, cx, |s| {
15483            s.select_ranges(vec![
15484                next_diagnostic.range.start..next_diagnostic.range.start,
15485            ])
15486        });
15487        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15488        self.refresh_edit_prediction(false, true, window, cx);
15489    }
15490
15491    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15493        let snapshot = self.snapshot(window, cx);
15494        let selection = self.selections.newest::<Point>(cx);
15495        self.go_to_hunk_before_or_after_position(
15496            &snapshot,
15497            selection.head(),
15498            Direction::Next,
15499            window,
15500            cx,
15501        );
15502    }
15503
15504    pub fn go_to_hunk_before_or_after_position(
15505        &mut self,
15506        snapshot: &EditorSnapshot,
15507        position: Point,
15508        direction: Direction,
15509        window: &mut Window,
15510        cx: &mut Context<Editor>,
15511    ) {
15512        let row = if direction == Direction::Next {
15513            self.hunk_after_position(snapshot, position)
15514                .map(|hunk| hunk.row_range.start)
15515        } else {
15516            self.hunk_before_position(snapshot, position)
15517        };
15518
15519        if let Some(row) = row {
15520            let destination = Point::new(row.0, 0);
15521            let autoscroll = Autoscroll::center();
15522
15523            self.unfold_ranges(&[destination..destination], false, false, cx);
15524            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15525                s.select_ranges([destination..destination]);
15526            });
15527        }
15528    }
15529
15530    fn hunk_after_position(
15531        &mut self,
15532        snapshot: &EditorSnapshot,
15533        position: Point,
15534    ) -> Option<MultiBufferDiffHunk> {
15535        snapshot
15536            .buffer_snapshot
15537            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15538            .find(|hunk| hunk.row_range.start.0 > position.row)
15539            .or_else(|| {
15540                snapshot
15541                    .buffer_snapshot
15542                    .diff_hunks_in_range(Point::zero()..position)
15543                    .find(|hunk| hunk.row_range.end.0 < position.row)
15544            })
15545    }
15546
15547    fn go_to_prev_hunk(
15548        &mut self,
15549        _: &GoToPreviousHunk,
15550        window: &mut Window,
15551        cx: &mut Context<Self>,
15552    ) {
15553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15554        let snapshot = self.snapshot(window, cx);
15555        let selection = self.selections.newest::<Point>(cx);
15556        self.go_to_hunk_before_or_after_position(
15557            &snapshot,
15558            selection.head(),
15559            Direction::Prev,
15560            window,
15561            cx,
15562        );
15563    }
15564
15565    fn hunk_before_position(
15566        &mut self,
15567        snapshot: &EditorSnapshot,
15568        position: Point,
15569    ) -> Option<MultiBufferRow> {
15570        snapshot
15571            .buffer_snapshot
15572            .diff_hunk_before(position)
15573            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15574    }
15575
15576    fn go_to_next_change(
15577        &mut self,
15578        _: &GoToNextChange,
15579        window: &mut Window,
15580        cx: &mut Context<Self>,
15581    ) {
15582        if let Some(selections) = self
15583            .change_list
15584            .next_change(1, Direction::Next)
15585            .map(|s| s.to_vec())
15586        {
15587            self.change_selections(Default::default(), window, cx, |s| {
15588                let map = s.display_map();
15589                s.select_display_ranges(selections.iter().map(|a| {
15590                    let point = a.to_display_point(&map);
15591                    point..point
15592                }))
15593            })
15594        }
15595    }
15596
15597    fn go_to_previous_change(
15598        &mut self,
15599        _: &GoToPreviousChange,
15600        window: &mut Window,
15601        cx: &mut Context<Self>,
15602    ) {
15603        if let Some(selections) = self
15604            .change_list
15605            .next_change(1, Direction::Prev)
15606            .map(|s| s.to_vec())
15607        {
15608            self.change_selections(Default::default(), window, cx, |s| {
15609                let map = s.display_map();
15610                s.select_display_ranges(selections.iter().map(|a| {
15611                    let point = a.to_display_point(&map);
15612                    point..point
15613                }))
15614            })
15615        }
15616    }
15617
15618    fn go_to_line<T: 'static>(
15619        &mut self,
15620        position: Anchor,
15621        highlight_color: Option<Hsla>,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) {
15625        let snapshot = self.snapshot(window, cx).display_snapshot;
15626        let position = position.to_point(&snapshot.buffer_snapshot);
15627        let start = snapshot
15628            .buffer_snapshot
15629            .clip_point(Point::new(position.row, 0), Bias::Left);
15630        let end = start + Point::new(1, 0);
15631        let start = snapshot.buffer_snapshot.anchor_before(start);
15632        let end = snapshot.buffer_snapshot.anchor_before(end);
15633
15634        self.highlight_rows::<T>(
15635            start..end,
15636            highlight_color
15637                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15638            Default::default(),
15639            cx,
15640        );
15641
15642        if self.buffer.read(cx).is_singleton() {
15643            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15644        }
15645    }
15646
15647    pub fn go_to_definition(
15648        &mut self,
15649        _: &GoToDefinition,
15650        window: &mut Window,
15651        cx: &mut Context<Self>,
15652    ) -> Task<Result<Navigated>> {
15653        let definition =
15654            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15655        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15656        cx.spawn_in(window, async move |editor, cx| {
15657            if definition.await? == Navigated::Yes {
15658                return Ok(Navigated::Yes);
15659            }
15660            match fallback_strategy {
15661                GoToDefinitionFallback::None => Ok(Navigated::No),
15662                GoToDefinitionFallback::FindAllReferences => {
15663                    match editor.update_in(cx, |editor, window, cx| {
15664                        editor.find_all_references(&FindAllReferences, window, cx)
15665                    })? {
15666                        Some(references) => references.await,
15667                        None => Ok(Navigated::No),
15668                    }
15669                }
15670            }
15671        })
15672    }
15673
15674    pub fn go_to_declaration(
15675        &mut self,
15676        _: &GoToDeclaration,
15677        window: &mut Window,
15678        cx: &mut Context<Self>,
15679    ) -> Task<Result<Navigated>> {
15680        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15681    }
15682
15683    pub fn go_to_declaration_split(
15684        &mut self,
15685        _: &GoToDeclaration,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) -> Task<Result<Navigated>> {
15689        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15690    }
15691
15692    pub fn go_to_implementation(
15693        &mut self,
15694        _: &GoToImplementation,
15695        window: &mut Window,
15696        cx: &mut Context<Self>,
15697    ) -> Task<Result<Navigated>> {
15698        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15699    }
15700
15701    pub fn go_to_implementation_split(
15702        &mut self,
15703        _: &GoToImplementationSplit,
15704        window: &mut Window,
15705        cx: &mut Context<Self>,
15706    ) -> Task<Result<Navigated>> {
15707        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15708    }
15709
15710    pub fn go_to_type_definition(
15711        &mut self,
15712        _: &GoToTypeDefinition,
15713        window: &mut Window,
15714        cx: &mut Context<Self>,
15715    ) -> Task<Result<Navigated>> {
15716        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15717    }
15718
15719    pub fn go_to_definition_split(
15720        &mut self,
15721        _: &GoToDefinitionSplit,
15722        window: &mut Window,
15723        cx: &mut Context<Self>,
15724    ) -> Task<Result<Navigated>> {
15725        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15726    }
15727
15728    pub fn go_to_type_definition_split(
15729        &mut self,
15730        _: &GoToTypeDefinitionSplit,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) -> Task<Result<Navigated>> {
15734        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15735    }
15736
15737    fn go_to_definition_of_kind(
15738        &mut self,
15739        kind: GotoDefinitionKind,
15740        split: bool,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) -> Task<Result<Navigated>> {
15744        let Some(provider) = self.semantics_provider.clone() else {
15745            return Task::ready(Ok(Navigated::No));
15746        };
15747        let head = self.selections.newest::<usize>(cx).head();
15748        let buffer = self.buffer.read(cx);
15749        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15750            return Task::ready(Ok(Navigated::No));
15751        };
15752        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15753            return Task::ready(Ok(Navigated::No));
15754        };
15755
15756        cx.spawn_in(window, async move |editor, cx| {
15757            let Some(definitions) = definitions.await? else {
15758                return Ok(Navigated::No);
15759            };
15760            let navigated = editor
15761                .update_in(cx, |editor, window, cx| {
15762                    editor.navigate_to_hover_links(
15763                        Some(kind),
15764                        definitions
15765                            .into_iter()
15766                            .filter(|location| {
15767                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15768                            })
15769                            .map(HoverLink::Text)
15770                            .collect::<Vec<_>>(),
15771                        split,
15772                        window,
15773                        cx,
15774                    )
15775                })?
15776                .await?;
15777            anyhow::Ok(navigated)
15778        })
15779    }
15780
15781    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15782        let selection = self.selections.newest_anchor();
15783        let head = selection.head();
15784        let tail = selection.tail();
15785
15786        let Some((buffer, start_position)) =
15787            self.buffer.read(cx).text_anchor_for_position(head, cx)
15788        else {
15789            return;
15790        };
15791
15792        let end_position = if head != tail {
15793            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15794                return;
15795            };
15796            Some(pos)
15797        } else {
15798            None
15799        };
15800
15801        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15802            let url = if let Some(end_pos) = end_position {
15803                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15804            } else {
15805                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15806            };
15807
15808            if let Some(url) = url {
15809                editor.update(cx, |_, cx| {
15810                    cx.open_url(&url);
15811                })
15812            } else {
15813                Ok(())
15814            }
15815        });
15816
15817        url_finder.detach();
15818    }
15819
15820    pub fn open_selected_filename(
15821        &mut self,
15822        _: &OpenSelectedFilename,
15823        window: &mut Window,
15824        cx: &mut Context<Self>,
15825    ) {
15826        let Some(workspace) = self.workspace() else {
15827            return;
15828        };
15829
15830        let position = self.selections.newest_anchor().head();
15831
15832        let Some((buffer, buffer_position)) =
15833            self.buffer.read(cx).text_anchor_for_position(position, cx)
15834        else {
15835            return;
15836        };
15837
15838        let project = self.project.clone();
15839
15840        cx.spawn_in(window, async move |_, cx| {
15841            let result = find_file(&buffer, project, buffer_position, cx).await;
15842
15843            if let Some((_, path)) = result {
15844                workspace
15845                    .update_in(cx, |workspace, window, cx| {
15846                        workspace.open_resolved_path(path, window, cx)
15847                    })?
15848                    .await?;
15849            }
15850            anyhow::Ok(())
15851        })
15852        .detach();
15853    }
15854
15855    pub(crate) fn navigate_to_hover_links(
15856        &mut self,
15857        kind: Option<GotoDefinitionKind>,
15858        definitions: Vec<HoverLink>,
15859        split: bool,
15860        window: &mut Window,
15861        cx: &mut Context<Editor>,
15862    ) -> Task<Result<Navigated>> {
15863        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15864        let mut first_url_or_file = None;
15865        let definitions: Vec<_> = definitions
15866            .into_iter()
15867            .filter_map(|def| match def {
15868                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15869                HoverLink::InlayHint(lsp_location, server_id) => {
15870                    let computation =
15871                        self.compute_target_location(lsp_location, server_id, window, cx);
15872                    Some(cx.background_spawn(computation))
15873                }
15874                HoverLink::Url(url) => {
15875                    first_url_or_file = Some(Either::Left(url));
15876                    None
15877                }
15878                HoverLink::File(path) => {
15879                    first_url_or_file = Some(Either::Right(path));
15880                    None
15881                }
15882            })
15883            .collect();
15884
15885        let workspace = self.workspace();
15886
15887        cx.spawn_in(window, async move |editor, acx| {
15888            let mut locations: Vec<Location> = future::join_all(definitions)
15889                .await
15890                .into_iter()
15891                .filter_map(|location| location.transpose())
15892                .collect::<Result<_>>()
15893                .context("location tasks")?;
15894
15895            if locations.len() > 1 {
15896                let Some(workspace) = workspace else {
15897                    return Ok(Navigated::No);
15898                };
15899
15900                let tab_kind = match kind {
15901                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15902                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15903                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15904                    Some(GotoDefinitionKind::Type) => "Types",
15905                };
15906                let title = editor
15907                    .update_in(acx, |_, _, cx| {
15908                        let target = locations
15909                            .iter()
15910                            .map(|location| {
15911                                location
15912                                    .buffer
15913                                    .read(cx)
15914                                    .text_for_range(location.range.clone())
15915                                    .collect::<String>()
15916                            })
15917                            .filter(|text| !text.contains('\n'))
15918                            .unique()
15919                            .take(3)
15920                            .join(", ");
15921                        if target.is_empty() {
15922                            tab_kind.to_owned()
15923                        } else {
15924                            format!("{tab_kind} for {target}")
15925                        }
15926                    })
15927                    .context("buffer title")?;
15928
15929                let opened = workspace
15930                    .update_in(acx, |workspace, window, cx| {
15931                        Self::open_locations_in_multibuffer(
15932                            workspace,
15933                            locations,
15934                            title,
15935                            split,
15936                            MultibufferSelectionMode::First,
15937                            window,
15938                            cx,
15939                        )
15940                    })
15941                    .is_ok();
15942
15943                anyhow::Ok(Navigated::from_bool(opened))
15944            } else if locations.is_empty() {
15945                // If there is one definition, just open it directly
15946                match first_url_or_file {
15947                    Some(Either::Left(url)) => {
15948                        acx.update(|_, cx| cx.open_url(&url))?;
15949                        Ok(Navigated::Yes)
15950                    }
15951                    Some(Either::Right(path)) => {
15952                        let Some(workspace) = workspace else {
15953                            return Ok(Navigated::No);
15954                        };
15955
15956                        workspace
15957                            .update_in(acx, |workspace, window, cx| {
15958                                workspace.open_resolved_path(path, window, cx)
15959                            })?
15960                            .await?;
15961                        Ok(Navigated::Yes)
15962                    }
15963                    None => Ok(Navigated::No),
15964                }
15965            } else {
15966                let Some(workspace) = workspace else {
15967                    return Ok(Navigated::No);
15968                };
15969
15970                let target = locations.pop().unwrap();
15971                editor.update_in(acx, |editor, window, cx| {
15972                    let pane = workspace.read(cx).active_pane().clone();
15973
15974                    let range = target.range.to_point(target.buffer.read(cx));
15975                    let range = editor.range_for_match(&range);
15976                    let range = collapse_multiline_range(range);
15977
15978                    if !split
15979                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15980                    {
15981                        editor.go_to_singleton_buffer_range(range, window, cx);
15982                    } else {
15983                        window.defer(cx, move |window, cx| {
15984                            let target_editor: Entity<Self> =
15985                                workspace.update(cx, |workspace, cx| {
15986                                    let pane = if split {
15987                                        workspace.adjacent_pane(window, cx)
15988                                    } else {
15989                                        workspace.active_pane().clone()
15990                                    };
15991
15992                                    workspace.open_project_item(
15993                                        pane,
15994                                        target.buffer.clone(),
15995                                        true,
15996                                        true,
15997                                        window,
15998                                        cx,
15999                                    )
16000                                });
16001                            target_editor.update(cx, |target_editor, cx| {
16002                                // When selecting a definition in a different buffer, disable the nav history
16003                                // to avoid creating a history entry at the previous cursor location.
16004                                pane.update(cx, |pane, _| pane.disable_history());
16005                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16006                                pane.update(cx, |pane, _| pane.enable_history());
16007                            });
16008                        });
16009                    }
16010                    Navigated::Yes
16011                })
16012            }
16013        })
16014    }
16015
16016    fn compute_target_location(
16017        &self,
16018        lsp_location: lsp::Location,
16019        server_id: LanguageServerId,
16020        window: &mut Window,
16021        cx: &mut Context<Self>,
16022    ) -> Task<anyhow::Result<Option<Location>>> {
16023        let Some(project) = self.project.clone() else {
16024            return Task::ready(Ok(None));
16025        };
16026
16027        cx.spawn_in(window, async move |editor, cx| {
16028            let location_task = editor.update(cx, |_, cx| {
16029                project.update(cx, |project, cx| {
16030                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16031                })
16032            })?;
16033            let location = Some({
16034                let target_buffer_handle = location_task.await.context("open local buffer")?;
16035                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16036                    let target_start = target_buffer
16037                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16038                    let target_end = target_buffer
16039                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16040                    target_buffer.anchor_after(target_start)
16041                        ..target_buffer.anchor_before(target_end)
16042                })?;
16043                Location {
16044                    buffer: target_buffer_handle,
16045                    range,
16046                }
16047            });
16048            Ok(location)
16049        })
16050    }
16051
16052    pub fn find_all_references(
16053        &mut self,
16054        _: &FindAllReferences,
16055        window: &mut Window,
16056        cx: &mut Context<Self>,
16057    ) -> Option<Task<Result<Navigated>>> {
16058        let selection = self.selections.newest::<usize>(cx);
16059        let multi_buffer = self.buffer.read(cx);
16060        let head = selection.head();
16061
16062        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16063        let head_anchor = multi_buffer_snapshot.anchor_at(
16064            head,
16065            if head < selection.tail() {
16066                Bias::Right
16067            } else {
16068                Bias::Left
16069            },
16070        );
16071
16072        match self
16073            .find_all_references_task_sources
16074            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16075        {
16076            Ok(_) => {
16077                log::info!(
16078                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16079                );
16080                return None;
16081            }
16082            Err(i) => {
16083                self.find_all_references_task_sources.insert(i, head_anchor);
16084            }
16085        }
16086
16087        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16088        let workspace = self.workspace()?;
16089        let project = workspace.read(cx).project().clone();
16090        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16091        Some(cx.spawn_in(window, async move |editor, cx| {
16092            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16093                if let Ok(i) = editor
16094                    .find_all_references_task_sources
16095                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16096                {
16097                    editor.find_all_references_task_sources.remove(i);
16098                }
16099            });
16100
16101            let Some(locations) = references.await? else {
16102                return anyhow::Ok(Navigated::No);
16103            };
16104            if locations.is_empty() {
16105                return anyhow::Ok(Navigated::No);
16106            }
16107
16108            workspace.update_in(cx, |workspace, window, cx| {
16109                let target = locations
16110                    .iter()
16111                    .map(|location| {
16112                        location
16113                            .buffer
16114                            .read(cx)
16115                            .text_for_range(location.range.clone())
16116                            .collect::<String>()
16117                    })
16118                    .filter(|text| !text.contains('\n'))
16119                    .unique()
16120                    .take(3)
16121                    .join(", ");
16122                let title = if target.is_empty() {
16123                    "References".to_owned()
16124                } else {
16125                    format!("References to {target}")
16126                };
16127                Self::open_locations_in_multibuffer(
16128                    workspace,
16129                    locations,
16130                    title,
16131                    false,
16132                    MultibufferSelectionMode::First,
16133                    window,
16134                    cx,
16135                );
16136                Navigated::Yes
16137            })
16138        }))
16139    }
16140
16141    /// Opens a multibuffer with the given project locations in it
16142    pub fn open_locations_in_multibuffer(
16143        workspace: &mut Workspace,
16144        mut locations: Vec<Location>,
16145        title: String,
16146        split: bool,
16147        multibuffer_selection_mode: MultibufferSelectionMode,
16148        window: &mut Window,
16149        cx: &mut Context<Workspace>,
16150    ) {
16151        if locations.is_empty() {
16152            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16153            return;
16154        }
16155
16156        // If there are multiple definitions, open them in a multibuffer
16157        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16158        let mut locations = locations.into_iter().peekable();
16159        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16160        let capability = workspace.project().read(cx).capability();
16161
16162        let excerpt_buffer = cx.new(|cx| {
16163            let mut multibuffer = MultiBuffer::new(capability);
16164            while let Some(location) = locations.next() {
16165                let buffer = location.buffer.read(cx);
16166                let mut ranges_for_buffer = Vec::new();
16167                let range = location.range.to_point(buffer);
16168                ranges_for_buffer.push(range.clone());
16169
16170                while let Some(next_location) = locations.peek() {
16171                    if next_location.buffer == location.buffer {
16172                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16173                        locations.next();
16174                    } else {
16175                        break;
16176                    }
16177                }
16178
16179                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16180                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16181                    PathKey::for_buffer(&location.buffer, cx),
16182                    location.buffer.clone(),
16183                    ranges_for_buffer,
16184                    DEFAULT_MULTIBUFFER_CONTEXT,
16185                    cx,
16186                );
16187                ranges.extend(new_ranges)
16188            }
16189
16190            multibuffer.with_title(title)
16191        });
16192
16193        let editor = cx.new(|cx| {
16194            Editor::for_multibuffer(
16195                excerpt_buffer,
16196                Some(workspace.project().clone()),
16197                window,
16198                cx,
16199            )
16200        });
16201        editor.update(cx, |editor, cx| {
16202            match multibuffer_selection_mode {
16203                MultibufferSelectionMode::First => {
16204                    if let Some(first_range) = ranges.first() {
16205                        editor.change_selections(
16206                            SelectionEffects::no_scroll(),
16207                            window,
16208                            cx,
16209                            |selections| {
16210                                selections.clear_disjoint();
16211                                selections
16212                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16213                            },
16214                        );
16215                    }
16216                    editor.highlight_background::<Self>(
16217                        &ranges,
16218                        |theme| theme.colors().editor_highlighted_line_background,
16219                        cx,
16220                    );
16221                }
16222                MultibufferSelectionMode::All => {
16223                    editor.change_selections(
16224                        SelectionEffects::no_scroll(),
16225                        window,
16226                        cx,
16227                        |selections| {
16228                            selections.clear_disjoint();
16229                            selections.select_anchor_ranges(ranges);
16230                        },
16231                    );
16232                }
16233            }
16234            editor.register_buffers_with_language_servers(cx);
16235        });
16236
16237        let item = Box::new(editor);
16238        let item_id = item.item_id();
16239
16240        if split {
16241            workspace.split_item(SplitDirection::Right, item, window, cx);
16242        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16243            let (preview_item_id, preview_item_idx) =
16244                workspace.active_pane().read_with(cx, |pane, _| {
16245                    (pane.preview_item_id(), pane.preview_item_idx())
16246                });
16247
16248            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16249
16250            if let Some(preview_item_id) = preview_item_id {
16251                workspace.active_pane().update(cx, |pane, cx| {
16252                    pane.remove_item(preview_item_id, false, false, window, cx);
16253                });
16254            }
16255        } else {
16256            workspace.add_item_to_active_pane(item, None, true, window, cx);
16257        }
16258        workspace.active_pane().update(cx, |pane, cx| {
16259            pane.set_preview_item_id(Some(item_id), cx);
16260        });
16261    }
16262
16263    pub fn rename(
16264        &mut self,
16265        _: &Rename,
16266        window: &mut Window,
16267        cx: &mut Context<Self>,
16268    ) -> Option<Task<Result<()>>> {
16269        use language::ToOffset as _;
16270
16271        let provider = self.semantics_provider.clone()?;
16272        let selection = self.selections.newest_anchor().clone();
16273        let (cursor_buffer, cursor_buffer_position) = self
16274            .buffer
16275            .read(cx)
16276            .text_anchor_for_position(selection.head(), cx)?;
16277        let (tail_buffer, cursor_buffer_position_end) = self
16278            .buffer
16279            .read(cx)
16280            .text_anchor_for_position(selection.tail(), cx)?;
16281        if tail_buffer != cursor_buffer {
16282            return None;
16283        }
16284
16285        let snapshot = cursor_buffer.read(cx).snapshot();
16286        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16287        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16288        let prepare_rename = provider
16289            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16290            .unwrap_or_else(|| Task::ready(Ok(None)));
16291        drop(snapshot);
16292
16293        Some(cx.spawn_in(window, async move |this, cx| {
16294            let rename_range = if let Some(range) = prepare_rename.await? {
16295                Some(range)
16296            } else {
16297                this.update(cx, |this, cx| {
16298                    let buffer = this.buffer.read(cx).snapshot(cx);
16299                    let mut buffer_highlights = this
16300                        .document_highlights_for_position(selection.head(), &buffer)
16301                        .filter(|highlight| {
16302                            highlight.start.excerpt_id == selection.head().excerpt_id
16303                                && highlight.end.excerpt_id == selection.head().excerpt_id
16304                        });
16305                    buffer_highlights
16306                        .next()
16307                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16308                })?
16309            };
16310            if let Some(rename_range) = rename_range {
16311                this.update_in(cx, |this, window, cx| {
16312                    let snapshot = cursor_buffer.read(cx).snapshot();
16313                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16314                    let cursor_offset_in_rename_range =
16315                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16316                    let cursor_offset_in_rename_range_end =
16317                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16318
16319                    this.take_rename(false, window, cx);
16320                    let buffer = this.buffer.read(cx).read(cx);
16321                    let cursor_offset = selection.head().to_offset(&buffer);
16322                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16323                    let rename_end = rename_start + rename_buffer_range.len();
16324                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16325                    let mut old_highlight_id = None;
16326                    let old_name: Arc<str> = buffer
16327                        .chunks(rename_start..rename_end, true)
16328                        .map(|chunk| {
16329                            if old_highlight_id.is_none() {
16330                                old_highlight_id = chunk.syntax_highlight_id;
16331                            }
16332                            chunk.text
16333                        })
16334                        .collect::<String>()
16335                        .into();
16336
16337                    drop(buffer);
16338
16339                    // Position the selection in the rename editor so that it matches the current selection.
16340                    this.show_local_selections = false;
16341                    let rename_editor = cx.new(|cx| {
16342                        let mut editor = Editor::single_line(window, cx);
16343                        editor.buffer.update(cx, |buffer, cx| {
16344                            buffer.edit([(0..0, old_name.clone())], None, cx)
16345                        });
16346                        let rename_selection_range = match cursor_offset_in_rename_range
16347                            .cmp(&cursor_offset_in_rename_range_end)
16348                        {
16349                            Ordering::Equal => {
16350                                editor.select_all(&SelectAll, window, cx);
16351                                return editor;
16352                            }
16353                            Ordering::Less => {
16354                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16355                            }
16356                            Ordering::Greater => {
16357                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16358                            }
16359                        };
16360                        if rename_selection_range.end > old_name.len() {
16361                            editor.select_all(&SelectAll, window, cx);
16362                        } else {
16363                            editor.change_selections(Default::default(), window, cx, |s| {
16364                                s.select_ranges([rename_selection_range]);
16365                            });
16366                        }
16367                        editor
16368                    });
16369                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16370                        if e == &EditorEvent::Focused {
16371                            cx.emit(EditorEvent::FocusedIn)
16372                        }
16373                    })
16374                    .detach();
16375
16376                    let write_highlights =
16377                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16378                    let read_highlights =
16379                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16380                    let ranges = write_highlights
16381                        .iter()
16382                        .flat_map(|(_, ranges)| ranges.iter())
16383                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16384                        .cloned()
16385                        .collect();
16386
16387                    this.highlight_text::<Rename>(
16388                        ranges,
16389                        HighlightStyle {
16390                            fade_out: Some(0.6),
16391                            ..Default::default()
16392                        },
16393                        cx,
16394                    );
16395                    let rename_focus_handle = rename_editor.focus_handle(cx);
16396                    window.focus(&rename_focus_handle);
16397                    let block_id = this.insert_blocks(
16398                        [BlockProperties {
16399                            style: BlockStyle::Flex,
16400                            placement: BlockPlacement::Below(range.start),
16401                            height: Some(1),
16402                            render: Arc::new({
16403                                let rename_editor = rename_editor.clone();
16404                                move |cx: &mut BlockContext| {
16405                                    let mut text_style = cx.editor_style.text.clone();
16406                                    if let Some(highlight_style) = old_highlight_id
16407                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16408                                    {
16409                                        text_style = text_style.highlight(highlight_style);
16410                                    }
16411                                    div()
16412                                        .block_mouse_except_scroll()
16413                                        .pl(cx.anchor_x)
16414                                        .child(EditorElement::new(
16415                                            &rename_editor,
16416                                            EditorStyle {
16417                                                background: cx.theme().system().transparent,
16418                                                local_player: cx.editor_style.local_player,
16419                                                text: text_style,
16420                                                scrollbar_width: cx.editor_style.scrollbar_width,
16421                                                syntax: cx.editor_style.syntax.clone(),
16422                                                status: cx.editor_style.status.clone(),
16423                                                inlay_hints_style: HighlightStyle {
16424                                                    font_weight: Some(FontWeight::BOLD),
16425                                                    ..make_inlay_hints_style(cx.app)
16426                                                },
16427                                                edit_prediction_styles: make_suggestion_styles(
16428                                                    cx.app,
16429                                                ),
16430                                                ..EditorStyle::default()
16431                                            },
16432                                        ))
16433                                        .into_any_element()
16434                                }
16435                            }),
16436                            priority: 0,
16437                        }],
16438                        Some(Autoscroll::fit()),
16439                        cx,
16440                    )[0];
16441                    this.pending_rename = Some(RenameState {
16442                        range,
16443                        old_name,
16444                        editor: rename_editor,
16445                        block_id,
16446                    });
16447                })?;
16448            }
16449
16450            Ok(())
16451        }))
16452    }
16453
16454    pub fn confirm_rename(
16455        &mut self,
16456        _: &ConfirmRename,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) -> Option<Task<Result<()>>> {
16460        let rename = self.take_rename(false, window, cx)?;
16461        let workspace = self.workspace()?.downgrade();
16462        let (buffer, start) = self
16463            .buffer
16464            .read(cx)
16465            .text_anchor_for_position(rename.range.start, cx)?;
16466        let (end_buffer, _) = self
16467            .buffer
16468            .read(cx)
16469            .text_anchor_for_position(rename.range.end, cx)?;
16470        if buffer != end_buffer {
16471            return None;
16472        }
16473
16474        let old_name = rename.old_name;
16475        let new_name = rename.editor.read(cx).text(cx);
16476
16477        let rename = self.semantics_provider.as_ref()?.perform_rename(
16478            &buffer,
16479            start,
16480            new_name.clone(),
16481            cx,
16482        )?;
16483
16484        Some(cx.spawn_in(window, async move |editor, cx| {
16485            let project_transaction = rename.await?;
16486            Self::open_project_transaction(
16487                &editor,
16488                workspace,
16489                project_transaction,
16490                format!("Rename: {}{}", old_name, new_name),
16491                cx,
16492            )
16493            .await?;
16494
16495            editor.update(cx, |editor, cx| {
16496                editor.refresh_document_highlights(cx);
16497            })?;
16498            Ok(())
16499        }))
16500    }
16501
16502    fn take_rename(
16503        &mut self,
16504        moving_cursor: bool,
16505        window: &mut Window,
16506        cx: &mut Context<Self>,
16507    ) -> Option<RenameState> {
16508        let rename = self.pending_rename.take()?;
16509        if rename.editor.focus_handle(cx).is_focused(window) {
16510            window.focus(&self.focus_handle);
16511        }
16512
16513        self.remove_blocks(
16514            [rename.block_id].into_iter().collect(),
16515            Some(Autoscroll::fit()),
16516            cx,
16517        );
16518        self.clear_highlights::<Rename>(cx);
16519        self.show_local_selections = true;
16520
16521        if moving_cursor {
16522            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16523                editor.selections.newest::<usize>(cx).head()
16524            });
16525
16526            // Update the selection to match the position of the selection inside
16527            // the rename editor.
16528            let snapshot = self.buffer.read(cx).read(cx);
16529            let rename_range = rename.range.to_offset(&snapshot);
16530            let cursor_in_editor = snapshot
16531                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16532                .min(rename_range.end);
16533            drop(snapshot);
16534
16535            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16536                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16537            });
16538        } else {
16539            self.refresh_document_highlights(cx);
16540        }
16541
16542        Some(rename)
16543    }
16544
16545    pub fn pending_rename(&self) -> Option<&RenameState> {
16546        self.pending_rename.as_ref()
16547    }
16548
16549    fn format(
16550        &mut self,
16551        _: &Format,
16552        window: &mut Window,
16553        cx: &mut Context<Self>,
16554    ) -> Option<Task<Result<()>>> {
16555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16556
16557        let project = match &self.project {
16558            Some(project) => project.clone(),
16559            None => return None,
16560        };
16561
16562        Some(self.perform_format(
16563            project,
16564            FormatTrigger::Manual,
16565            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16566            window,
16567            cx,
16568        ))
16569    }
16570
16571    fn format_selections(
16572        &mut self,
16573        _: &FormatSelections,
16574        window: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) -> Option<Task<Result<()>>> {
16577        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16578
16579        let project = match &self.project {
16580            Some(project) => project.clone(),
16581            None => return None,
16582        };
16583
16584        let ranges = self
16585            .selections
16586            .all_adjusted(cx)
16587            .into_iter()
16588            .map(|selection| selection.range())
16589            .collect_vec();
16590
16591        Some(self.perform_format(
16592            project,
16593            FormatTrigger::Manual,
16594            FormatTarget::Ranges(ranges),
16595            window,
16596            cx,
16597        ))
16598    }
16599
16600    fn perform_format(
16601        &mut self,
16602        project: Entity<Project>,
16603        trigger: FormatTrigger,
16604        target: FormatTarget,
16605        window: &mut Window,
16606        cx: &mut Context<Self>,
16607    ) -> Task<Result<()>> {
16608        let buffer = self.buffer.clone();
16609        let (buffers, target) = match target {
16610            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16611            FormatTarget::Ranges(selection_ranges) => {
16612                let multi_buffer = buffer.read(cx);
16613                let snapshot = multi_buffer.read(cx);
16614                let mut buffers = HashSet::default();
16615                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16616                    BTreeMap::new();
16617                for selection_range in selection_ranges {
16618                    for (buffer, buffer_range, _) in
16619                        snapshot.range_to_buffer_ranges(selection_range)
16620                    {
16621                        let buffer_id = buffer.remote_id();
16622                        let start = buffer.anchor_before(buffer_range.start);
16623                        let end = buffer.anchor_after(buffer_range.end);
16624                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16625                        buffer_id_to_ranges
16626                            .entry(buffer_id)
16627                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16628                            .or_insert_with(|| vec![start..end]);
16629                    }
16630                }
16631                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16632            }
16633        };
16634
16635        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16636        let selections_prev = transaction_id_prev
16637            .and_then(|transaction_id_prev| {
16638                // default to selections as they were after the last edit, if we have them,
16639                // instead of how they are now.
16640                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16641                // will take you back to where you made the last edit, instead of staying where you scrolled
16642                self.selection_history
16643                    .transaction(transaction_id_prev)
16644                    .map(|t| t.0.clone())
16645            })
16646            .unwrap_or_else(|| self.selections.disjoint_anchors());
16647
16648        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16649        let format = project.update(cx, |project, cx| {
16650            project.format(buffers, target, true, trigger, cx)
16651        });
16652
16653        cx.spawn_in(window, async move |editor, cx| {
16654            let transaction = futures::select_biased! {
16655                transaction = format.log_err().fuse() => transaction,
16656                () = timeout => {
16657                    log::warn!("timed out waiting for formatting");
16658                    None
16659                }
16660            };
16661
16662            buffer
16663                .update(cx, |buffer, cx| {
16664                    if let Some(transaction) = transaction
16665                        && !buffer.is_singleton()
16666                    {
16667                        buffer.push_transaction(&transaction.0, cx);
16668                    }
16669                    cx.notify();
16670                })
16671                .ok();
16672
16673            if let Some(transaction_id_now) =
16674                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16675            {
16676                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16677                if has_new_transaction {
16678                    _ = editor.update(cx, |editor, _| {
16679                        editor
16680                            .selection_history
16681                            .insert_transaction(transaction_id_now, selections_prev);
16682                    });
16683                }
16684            }
16685
16686            Ok(())
16687        })
16688    }
16689
16690    fn organize_imports(
16691        &mut self,
16692        _: &OrganizeImports,
16693        window: &mut Window,
16694        cx: &mut Context<Self>,
16695    ) -> Option<Task<Result<()>>> {
16696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16697        let project = match &self.project {
16698            Some(project) => project.clone(),
16699            None => return None,
16700        };
16701        Some(self.perform_code_action_kind(
16702            project,
16703            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16704            window,
16705            cx,
16706        ))
16707    }
16708
16709    fn perform_code_action_kind(
16710        &mut self,
16711        project: Entity<Project>,
16712        kind: CodeActionKind,
16713        window: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) -> Task<Result<()>> {
16716        let buffer = self.buffer.clone();
16717        let buffers = buffer.read(cx).all_buffers();
16718        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16719        let apply_action = project.update(cx, |project, cx| {
16720            project.apply_code_action_kind(buffers, kind, true, cx)
16721        });
16722        cx.spawn_in(window, async move |_, cx| {
16723            let transaction = futures::select_biased! {
16724                () = timeout => {
16725                    log::warn!("timed out waiting for executing code action");
16726                    None
16727                }
16728                transaction = apply_action.log_err().fuse() => transaction,
16729            };
16730            buffer
16731                .update(cx, |buffer, cx| {
16732                    // check if we need this
16733                    if let Some(transaction) = transaction
16734                        && !buffer.is_singleton()
16735                    {
16736                        buffer.push_transaction(&transaction.0, cx);
16737                    }
16738                    cx.notify();
16739                })
16740                .ok();
16741            Ok(())
16742        })
16743    }
16744
16745    pub fn restart_language_server(
16746        &mut self,
16747        _: &RestartLanguageServer,
16748        _: &mut Window,
16749        cx: &mut Context<Self>,
16750    ) {
16751        if let Some(project) = self.project.clone() {
16752            self.buffer.update(cx, |multi_buffer, cx| {
16753                project.update(cx, |project, cx| {
16754                    project.restart_language_servers_for_buffers(
16755                        multi_buffer.all_buffers().into_iter().collect(),
16756                        HashSet::default(),
16757                        cx,
16758                    );
16759                });
16760            })
16761        }
16762    }
16763
16764    pub fn stop_language_server(
16765        &mut self,
16766        _: &StopLanguageServer,
16767        _: &mut Window,
16768        cx: &mut Context<Self>,
16769    ) {
16770        if let Some(project) = self.project.clone() {
16771            self.buffer.update(cx, |multi_buffer, cx| {
16772                project.update(cx, |project, cx| {
16773                    project.stop_language_servers_for_buffers(
16774                        multi_buffer.all_buffers().into_iter().collect(),
16775                        HashSet::default(),
16776                        cx,
16777                    );
16778                    cx.emit(project::Event::RefreshInlayHints);
16779                });
16780            });
16781        }
16782    }
16783
16784    fn cancel_language_server_work(
16785        workspace: &mut Workspace,
16786        _: &actions::CancelLanguageServerWork,
16787        _: &mut Window,
16788        cx: &mut Context<Workspace>,
16789    ) {
16790        let project = workspace.project();
16791        let buffers = workspace
16792            .active_item(cx)
16793            .and_then(|item| item.act_as::<Editor>(cx))
16794            .map_or(HashSet::default(), |editor| {
16795                editor.read(cx).buffer.read(cx).all_buffers()
16796            });
16797        project.update(cx, |project, cx| {
16798            project.cancel_language_server_work_for_buffers(buffers, cx);
16799        });
16800    }
16801
16802    fn show_character_palette(
16803        &mut self,
16804        _: &ShowCharacterPalette,
16805        window: &mut Window,
16806        _: &mut Context<Self>,
16807    ) {
16808        window.show_character_palette();
16809    }
16810
16811    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16812        if !self.diagnostics_enabled() {
16813            return;
16814        }
16815
16816        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16817            let buffer = self.buffer.read(cx).snapshot(cx);
16818            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16819            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16820            let is_valid = buffer
16821                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16822                .any(|entry| {
16823                    entry.diagnostic.is_primary
16824                        && !entry.range.is_empty()
16825                        && entry.range.start == primary_range_start
16826                        && entry.diagnostic.message == active_diagnostics.active_message
16827                });
16828
16829            if !is_valid {
16830                self.dismiss_diagnostics(cx);
16831            }
16832        }
16833    }
16834
16835    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16836        match &self.active_diagnostics {
16837            ActiveDiagnostic::Group(group) => Some(group),
16838            _ => None,
16839        }
16840    }
16841
16842    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16843        if !self.diagnostics_enabled() {
16844            return;
16845        }
16846        self.dismiss_diagnostics(cx);
16847        self.active_diagnostics = ActiveDiagnostic::All;
16848    }
16849
16850    fn activate_diagnostics(
16851        &mut self,
16852        buffer_id: BufferId,
16853        diagnostic: DiagnosticEntry<usize>,
16854        window: &mut Window,
16855        cx: &mut Context<Self>,
16856    ) {
16857        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16858            return;
16859        }
16860        self.dismiss_diagnostics(cx);
16861        let snapshot = self.snapshot(window, cx);
16862        let buffer = self.buffer.read(cx).snapshot(cx);
16863        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16864            return;
16865        };
16866
16867        let diagnostic_group = buffer
16868            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16869            .collect::<Vec<_>>();
16870
16871        let blocks =
16872            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16873
16874        let blocks = self.display_map.update(cx, |display_map, cx| {
16875            display_map.insert_blocks(blocks, cx).into_iter().collect()
16876        });
16877        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16878            active_range: buffer.anchor_before(diagnostic.range.start)
16879                ..buffer.anchor_after(diagnostic.range.end),
16880            active_message: diagnostic.diagnostic.message.clone(),
16881            group_id: diagnostic.diagnostic.group_id,
16882            blocks,
16883        });
16884        cx.notify();
16885    }
16886
16887    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16888        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16889            return;
16890        };
16891
16892        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16893        if let ActiveDiagnostic::Group(group) = prev {
16894            self.display_map.update(cx, |display_map, cx| {
16895                display_map.remove_blocks(group.blocks, cx);
16896            });
16897            cx.notify();
16898        }
16899    }
16900
16901    /// Disable inline diagnostics rendering for this editor.
16902    pub fn disable_inline_diagnostics(&mut self) {
16903        self.inline_diagnostics_enabled = false;
16904        self.inline_diagnostics_update = Task::ready(());
16905        self.inline_diagnostics.clear();
16906    }
16907
16908    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16909        self.diagnostics_enabled = false;
16910        self.dismiss_diagnostics(cx);
16911        self.inline_diagnostics_update = Task::ready(());
16912        self.inline_diagnostics.clear();
16913    }
16914
16915    pub fn diagnostics_enabled(&self) -> bool {
16916        self.diagnostics_enabled && self.mode.is_full()
16917    }
16918
16919    pub fn inline_diagnostics_enabled(&self) -> bool {
16920        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16921    }
16922
16923    pub fn show_inline_diagnostics(&self) -> bool {
16924        self.show_inline_diagnostics
16925    }
16926
16927    pub fn toggle_inline_diagnostics(
16928        &mut self,
16929        _: &ToggleInlineDiagnostics,
16930        window: &mut Window,
16931        cx: &mut Context<Editor>,
16932    ) {
16933        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16934        self.refresh_inline_diagnostics(false, window, cx);
16935    }
16936
16937    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16938        self.diagnostics_max_severity = severity;
16939        self.display_map.update(cx, |display_map, _| {
16940            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16941        });
16942    }
16943
16944    pub fn toggle_diagnostics(
16945        &mut self,
16946        _: &ToggleDiagnostics,
16947        window: &mut Window,
16948        cx: &mut Context<Editor>,
16949    ) {
16950        if !self.diagnostics_enabled() {
16951            return;
16952        }
16953
16954        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16955            EditorSettings::get_global(cx)
16956                .diagnostics_max_severity
16957                .filter(|severity| severity != &DiagnosticSeverity::Off)
16958                .unwrap_or(DiagnosticSeverity::Hint)
16959        } else {
16960            DiagnosticSeverity::Off
16961        };
16962        self.set_max_diagnostics_severity(new_severity, cx);
16963        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16964            self.active_diagnostics = ActiveDiagnostic::None;
16965            self.inline_diagnostics_update = Task::ready(());
16966            self.inline_diagnostics.clear();
16967        } else {
16968            self.refresh_inline_diagnostics(false, window, cx);
16969        }
16970
16971        cx.notify();
16972    }
16973
16974    pub fn toggle_minimap(
16975        &mut self,
16976        _: &ToggleMinimap,
16977        window: &mut Window,
16978        cx: &mut Context<Editor>,
16979    ) {
16980        if self.supports_minimap(cx) {
16981            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16982        }
16983    }
16984
16985    fn refresh_inline_diagnostics(
16986        &mut self,
16987        debounce: bool,
16988        window: &mut Window,
16989        cx: &mut Context<Self>,
16990    ) {
16991        let max_severity = ProjectSettings::get_global(cx)
16992            .diagnostics
16993            .inline
16994            .max_severity
16995            .unwrap_or(self.diagnostics_max_severity);
16996
16997        if !self.inline_diagnostics_enabled()
16998            || !self.show_inline_diagnostics
16999            || max_severity == DiagnosticSeverity::Off
17000        {
17001            self.inline_diagnostics_update = Task::ready(());
17002            self.inline_diagnostics.clear();
17003            return;
17004        }
17005
17006        let debounce_ms = ProjectSettings::get_global(cx)
17007            .diagnostics
17008            .inline
17009            .update_debounce_ms;
17010        let debounce = if debounce && debounce_ms > 0 {
17011            Some(Duration::from_millis(debounce_ms))
17012        } else {
17013            None
17014        };
17015        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17016            if let Some(debounce) = debounce {
17017                cx.background_executor().timer(debounce).await;
17018            }
17019            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17020                editor
17021                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17022                    .ok()
17023            }) else {
17024                return;
17025            };
17026
17027            let new_inline_diagnostics = cx
17028                .background_spawn(async move {
17029                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17030                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17031                        let message = diagnostic_entry
17032                            .diagnostic
17033                            .message
17034                            .split_once('\n')
17035                            .map(|(line, _)| line)
17036                            .map(SharedString::new)
17037                            .unwrap_or_else(|| {
17038                                SharedString::from(diagnostic_entry.diagnostic.message)
17039                            });
17040                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17041                        let (Ok(i) | Err(i)) = inline_diagnostics
17042                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17043                        inline_diagnostics.insert(
17044                            i,
17045                            (
17046                                start_anchor,
17047                                InlineDiagnostic {
17048                                    message,
17049                                    group_id: diagnostic_entry.diagnostic.group_id,
17050                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17051                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17052                                    severity: diagnostic_entry.diagnostic.severity,
17053                                },
17054                            ),
17055                        );
17056                    }
17057                    inline_diagnostics
17058                })
17059                .await;
17060
17061            editor
17062                .update(cx, |editor, cx| {
17063                    editor.inline_diagnostics = new_inline_diagnostics;
17064                    cx.notify();
17065                })
17066                .ok();
17067        });
17068    }
17069
17070    fn pull_diagnostics(
17071        &mut self,
17072        buffer_id: Option<BufferId>,
17073        window: &Window,
17074        cx: &mut Context<Self>,
17075    ) -> Option<()> {
17076        if !self.mode().is_full() {
17077            return None;
17078        }
17079        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17080            .diagnostics
17081            .lsp_pull_diagnostics;
17082        if !pull_diagnostics_settings.enabled {
17083            return None;
17084        }
17085        let project = self.project()?.downgrade();
17086        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17087        let mut buffers = self.buffer.read(cx).all_buffers();
17088        if let Some(buffer_id) = buffer_id {
17089            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17090        }
17091
17092        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17093            cx.background_executor().timer(debounce).await;
17094
17095            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17096                buffers
17097                    .into_iter()
17098                    .filter_map(|buffer| {
17099                        project
17100                            .update(cx, |project, cx| {
17101                                project.lsp_store().update(cx, |lsp_store, cx| {
17102                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17103                                })
17104                            })
17105                            .ok()
17106                    })
17107                    .collect::<FuturesUnordered<_>>()
17108            }) else {
17109                return;
17110            };
17111
17112            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17113                match pull_task {
17114                    Ok(()) => {
17115                        if editor
17116                            .update_in(cx, |editor, window, cx| {
17117                                editor.update_diagnostics_state(window, cx);
17118                            })
17119                            .is_err()
17120                        {
17121                            return;
17122                        }
17123                    }
17124                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17125                }
17126            }
17127        });
17128
17129        Some(())
17130    }
17131
17132    pub fn set_selections_from_remote(
17133        &mut self,
17134        selections: Vec<Selection<Anchor>>,
17135        pending_selection: Option<Selection<Anchor>>,
17136        window: &mut Window,
17137        cx: &mut Context<Self>,
17138    ) {
17139        let old_cursor_position = self.selections.newest_anchor().head();
17140        self.selections.change_with(cx, |s| {
17141            s.select_anchors(selections);
17142            if let Some(pending_selection) = pending_selection {
17143                s.set_pending(pending_selection, SelectMode::Character);
17144            } else {
17145                s.clear_pending();
17146            }
17147        });
17148        self.selections_did_change(
17149            false,
17150            &old_cursor_position,
17151            SelectionEffects::default(),
17152            window,
17153            cx,
17154        );
17155    }
17156
17157    pub fn transact(
17158        &mut self,
17159        window: &mut Window,
17160        cx: &mut Context<Self>,
17161        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17162    ) -> Option<TransactionId> {
17163        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17164            this.start_transaction_at(Instant::now(), window, cx);
17165            update(this, window, cx);
17166            this.end_transaction_at(Instant::now(), cx)
17167        })
17168    }
17169
17170    pub fn start_transaction_at(
17171        &mut self,
17172        now: Instant,
17173        window: &mut Window,
17174        cx: &mut Context<Self>,
17175    ) -> Option<TransactionId> {
17176        self.end_selection(window, cx);
17177        if let Some(tx_id) = self
17178            .buffer
17179            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17180        {
17181            self.selection_history
17182                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17183            cx.emit(EditorEvent::TransactionBegun {
17184                transaction_id: tx_id,
17185            });
17186            Some(tx_id)
17187        } else {
17188            None
17189        }
17190    }
17191
17192    pub fn end_transaction_at(
17193        &mut self,
17194        now: Instant,
17195        cx: &mut Context<Self>,
17196    ) -> Option<TransactionId> {
17197        if let Some(transaction_id) = self
17198            .buffer
17199            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17200        {
17201            if let Some((_, end_selections)) =
17202                self.selection_history.transaction_mut(transaction_id)
17203            {
17204                *end_selections = Some(self.selections.disjoint_anchors());
17205            } else {
17206                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17207            }
17208
17209            cx.emit(EditorEvent::Edited { transaction_id });
17210            Some(transaction_id)
17211        } else {
17212            None
17213        }
17214    }
17215
17216    pub fn modify_transaction_selection_history(
17217        &mut self,
17218        transaction_id: TransactionId,
17219        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17220    ) -> bool {
17221        self.selection_history
17222            .transaction_mut(transaction_id)
17223            .map(modify)
17224            .is_some()
17225    }
17226
17227    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17228        if self.selection_mark_mode {
17229            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17230                s.move_with(|_, sel| {
17231                    sel.collapse_to(sel.head(), SelectionGoal::None);
17232                });
17233            })
17234        }
17235        self.selection_mark_mode = true;
17236        cx.notify();
17237    }
17238
17239    pub fn swap_selection_ends(
17240        &mut self,
17241        _: &actions::SwapSelectionEnds,
17242        window: &mut Window,
17243        cx: &mut Context<Self>,
17244    ) {
17245        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17246            s.move_with(|_, sel| {
17247                if sel.start != sel.end {
17248                    sel.reversed = !sel.reversed
17249                }
17250            });
17251        });
17252        self.request_autoscroll(Autoscroll::newest(), cx);
17253        cx.notify();
17254    }
17255
17256    pub fn toggle_focus(
17257        workspace: &mut Workspace,
17258        _: &actions::ToggleFocus,
17259        window: &mut Window,
17260        cx: &mut Context<Workspace>,
17261    ) {
17262        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17263            return;
17264        };
17265        workspace.activate_item(&item, true, true, window, cx);
17266    }
17267
17268    pub fn toggle_fold(
17269        &mut self,
17270        _: &actions::ToggleFold,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) {
17274        if self.is_singleton(cx) {
17275            let selection = self.selections.newest::<Point>(cx);
17276
17277            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17278            let range = if selection.is_empty() {
17279                let point = selection.head().to_display_point(&display_map);
17280                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17281                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17282                    .to_point(&display_map);
17283                start..end
17284            } else {
17285                selection.range()
17286            };
17287            if display_map.folds_in_range(range).next().is_some() {
17288                self.unfold_lines(&Default::default(), window, cx)
17289            } else {
17290                self.fold(&Default::default(), window, cx)
17291            }
17292        } else {
17293            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17294            let buffer_ids: HashSet<_> = self
17295                .selections
17296                .disjoint_anchor_ranges()
17297                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17298                .collect();
17299
17300            let should_unfold = buffer_ids
17301                .iter()
17302                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17303
17304            for buffer_id in buffer_ids {
17305                if should_unfold {
17306                    self.unfold_buffer(buffer_id, cx);
17307                } else {
17308                    self.fold_buffer(buffer_id, cx);
17309                }
17310            }
17311        }
17312    }
17313
17314    pub fn toggle_fold_recursive(
17315        &mut self,
17316        _: &actions::ToggleFoldRecursive,
17317        window: &mut Window,
17318        cx: &mut Context<Self>,
17319    ) {
17320        let selection = self.selections.newest::<Point>(cx);
17321
17322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17323        let range = if selection.is_empty() {
17324            let point = selection.head().to_display_point(&display_map);
17325            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17326            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17327                .to_point(&display_map);
17328            start..end
17329        } else {
17330            selection.range()
17331        };
17332        if display_map.folds_in_range(range).next().is_some() {
17333            self.unfold_recursive(&Default::default(), window, cx)
17334        } else {
17335            self.fold_recursive(&Default::default(), window, cx)
17336        }
17337    }
17338
17339    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17340        if self.is_singleton(cx) {
17341            let mut to_fold = Vec::new();
17342            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17343            let selections = self.selections.all_adjusted(cx);
17344
17345            for selection in selections {
17346                let range = selection.range().sorted();
17347                let buffer_start_row = range.start.row;
17348
17349                if range.start.row != range.end.row {
17350                    let mut found = false;
17351                    let mut row = range.start.row;
17352                    while row <= range.end.row {
17353                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17354                        {
17355                            found = true;
17356                            row = crease.range().end.row + 1;
17357                            to_fold.push(crease);
17358                        } else {
17359                            row += 1
17360                        }
17361                    }
17362                    if found {
17363                        continue;
17364                    }
17365                }
17366
17367                for row in (0..=range.start.row).rev() {
17368                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17369                        && crease.range().end.row >= buffer_start_row
17370                    {
17371                        to_fold.push(crease);
17372                        if row <= range.start.row {
17373                            break;
17374                        }
17375                    }
17376                }
17377            }
17378
17379            self.fold_creases(to_fold, true, window, cx);
17380        } else {
17381            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17382            let buffer_ids = self
17383                .selections
17384                .disjoint_anchor_ranges()
17385                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17386                .collect::<HashSet<_>>();
17387            for buffer_id in buffer_ids {
17388                self.fold_buffer(buffer_id, cx);
17389            }
17390        }
17391    }
17392
17393    pub fn toggle_fold_all(
17394        &mut self,
17395        _: &actions::ToggleFoldAll,
17396        window: &mut Window,
17397        cx: &mut Context<Self>,
17398    ) {
17399        if self.buffer.read(cx).is_singleton() {
17400            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17401            let has_folds = display_map
17402                .folds_in_range(0..display_map.buffer_snapshot.len())
17403                .next()
17404                .is_some();
17405
17406            if has_folds {
17407                self.unfold_all(&actions::UnfoldAll, window, cx);
17408            } else {
17409                self.fold_all(&actions::FoldAll, window, cx);
17410            }
17411        } else {
17412            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17413            let should_unfold = buffer_ids
17414                .iter()
17415                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17416
17417            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17418                editor
17419                    .update_in(cx, |editor, _, cx| {
17420                        for buffer_id in buffer_ids {
17421                            if should_unfold {
17422                                editor.unfold_buffer(buffer_id, cx);
17423                            } else {
17424                                editor.fold_buffer(buffer_id, cx);
17425                            }
17426                        }
17427                    })
17428                    .ok();
17429            });
17430        }
17431    }
17432
17433    fn fold_at_level(
17434        &mut self,
17435        fold_at: &FoldAtLevel,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        if !self.buffer.read(cx).is_singleton() {
17440            return;
17441        }
17442
17443        let fold_at_level = fold_at.0;
17444        let snapshot = self.buffer.read(cx).snapshot(cx);
17445        let mut to_fold = Vec::new();
17446        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17447
17448        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17449            while start_row < end_row {
17450                match self
17451                    .snapshot(window, cx)
17452                    .crease_for_buffer_row(MultiBufferRow(start_row))
17453                {
17454                    Some(crease) => {
17455                        let nested_start_row = crease.range().start.row + 1;
17456                        let nested_end_row = crease.range().end.row;
17457
17458                        if current_level < fold_at_level {
17459                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17460                        } else if current_level == fold_at_level {
17461                            to_fold.push(crease);
17462                        }
17463
17464                        start_row = nested_end_row + 1;
17465                    }
17466                    None => start_row += 1,
17467                }
17468            }
17469        }
17470
17471        self.fold_creases(to_fold, true, window, cx);
17472    }
17473
17474    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17475        if self.buffer.read(cx).is_singleton() {
17476            let mut fold_ranges = Vec::new();
17477            let snapshot = self.buffer.read(cx).snapshot(cx);
17478
17479            for row in 0..snapshot.max_row().0 {
17480                if let Some(foldable_range) = self
17481                    .snapshot(window, cx)
17482                    .crease_for_buffer_row(MultiBufferRow(row))
17483                {
17484                    fold_ranges.push(foldable_range);
17485                }
17486            }
17487
17488            self.fold_creases(fold_ranges, true, window, cx);
17489        } else {
17490            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17491                editor
17492                    .update_in(cx, |editor, _, cx| {
17493                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17494                            editor.fold_buffer(buffer_id, cx);
17495                        }
17496                    })
17497                    .ok();
17498            });
17499        }
17500    }
17501
17502    pub fn fold_function_bodies(
17503        &mut self,
17504        _: &actions::FoldFunctionBodies,
17505        window: &mut Window,
17506        cx: &mut Context<Self>,
17507    ) {
17508        let snapshot = self.buffer.read(cx).snapshot(cx);
17509
17510        let ranges = snapshot
17511            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17512            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17513            .collect::<Vec<_>>();
17514
17515        let creases = ranges
17516            .into_iter()
17517            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17518            .collect();
17519
17520        self.fold_creases(creases, true, window, cx);
17521    }
17522
17523    pub fn fold_recursive(
17524        &mut self,
17525        _: &actions::FoldRecursive,
17526        window: &mut Window,
17527        cx: &mut Context<Self>,
17528    ) {
17529        let mut to_fold = Vec::new();
17530        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17531        let selections = self.selections.all_adjusted(cx);
17532
17533        for selection in selections {
17534            let range = selection.range().sorted();
17535            let buffer_start_row = range.start.row;
17536
17537            if range.start.row != range.end.row {
17538                let mut found = false;
17539                for row in range.start.row..=range.end.row {
17540                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17541                        found = true;
17542                        to_fold.push(crease);
17543                    }
17544                }
17545                if found {
17546                    continue;
17547                }
17548            }
17549
17550            for row in (0..=range.start.row).rev() {
17551                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17552                    if crease.range().end.row >= buffer_start_row {
17553                        to_fold.push(crease);
17554                    } else {
17555                        break;
17556                    }
17557                }
17558            }
17559        }
17560
17561        self.fold_creases(to_fold, true, window, cx);
17562    }
17563
17564    pub fn fold_at(
17565        &mut self,
17566        buffer_row: MultiBufferRow,
17567        window: &mut Window,
17568        cx: &mut Context<Self>,
17569    ) {
17570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17571
17572        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17573            let autoscroll = self
17574                .selections
17575                .all::<Point>(cx)
17576                .iter()
17577                .any(|selection| crease.range().overlaps(&selection.range()));
17578
17579            self.fold_creases(vec![crease], autoscroll, window, cx);
17580        }
17581    }
17582
17583    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17584        if self.is_singleton(cx) {
17585            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17586            let buffer = &display_map.buffer_snapshot;
17587            let selections = self.selections.all::<Point>(cx);
17588            let ranges = selections
17589                .iter()
17590                .map(|s| {
17591                    let range = s.display_range(&display_map).sorted();
17592                    let mut start = range.start.to_point(&display_map);
17593                    let mut end = range.end.to_point(&display_map);
17594                    start.column = 0;
17595                    end.column = buffer.line_len(MultiBufferRow(end.row));
17596                    start..end
17597                })
17598                .collect::<Vec<_>>();
17599
17600            self.unfold_ranges(&ranges, true, true, cx);
17601        } else {
17602            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17603            let buffer_ids = self
17604                .selections
17605                .disjoint_anchor_ranges()
17606                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17607                .collect::<HashSet<_>>();
17608            for buffer_id in buffer_ids {
17609                self.unfold_buffer(buffer_id, cx);
17610            }
17611        }
17612    }
17613
17614    pub fn unfold_recursive(
17615        &mut self,
17616        _: &UnfoldRecursive,
17617        _window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17621        let selections = self.selections.all::<Point>(cx);
17622        let ranges = selections
17623            .iter()
17624            .map(|s| {
17625                let mut range = s.display_range(&display_map).sorted();
17626                *range.start.column_mut() = 0;
17627                *range.end.column_mut() = display_map.line_len(range.end.row());
17628                let start = range.start.to_point(&display_map);
17629                let end = range.end.to_point(&display_map);
17630                start..end
17631            })
17632            .collect::<Vec<_>>();
17633
17634        self.unfold_ranges(&ranges, true, true, cx);
17635    }
17636
17637    pub fn unfold_at(
17638        &mut self,
17639        buffer_row: MultiBufferRow,
17640        _window: &mut Window,
17641        cx: &mut Context<Self>,
17642    ) {
17643        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17644
17645        let intersection_range = Point::new(buffer_row.0, 0)
17646            ..Point::new(
17647                buffer_row.0,
17648                display_map.buffer_snapshot.line_len(buffer_row),
17649            );
17650
17651        let autoscroll = self
17652            .selections
17653            .all::<Point>(cx)
17654            .iter()
17655            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17656
17657        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17658    }
17659
17660    pub fn unfold_all(
17661        &mut self,
17662        _: &actions::UnfoldAll,
17663        _window: &mut Window,
17664        cx: &mut Context<Self>,
17665    ) {
17666        if self.buffer.read(cx).is_singleton() {
17667            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17668            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17669        } else {
17670            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17671                editor
17672                    .update(cx, |editor, cx| {
17673                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17674                            editor.unfold_buffer(buffer_id, cx);
17675                        }
17676                    })
17677                    .ok();
17678            });
17679        }
17680    }
17681
17682    pub fn fold_selected_ranges(
17683        &mut self,
17684        _: &FoldSelectedRanges,
17685        window: &mut Window,
17686        cx: &mut Context<Self>,
17687    ) {
17688        let selections = self.selections.all_adjusted(cx);
17689        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17690        let ranges = selections
17691            .into_iter()
17692            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17693            .collect::<Vec<_>>();
17694        self.fold_creases(ranges, true, window, cx);
17695    }
17696
17697    pub fn fold_ranges<T: ToOffset + Clone>(
17698        &mut self,
17699        ranges: Vec<Range<T>>,
17700        auto_scroll: bool,
17701        window: &mut Window,
17702        cx: &mut Context<Self>,
17703    ) {
17704        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17705        let ranges = ranges
17706            .into_iter()
17707            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17708            .collect::<Vec<_>>();
17709        self.fold_creases(ranges, auto_scroll, window, cx);
17710    }
17711
17712    pub fn fold_creases<T: ToOffset + Clone>(
17713        &mut self,
17714        creases: Vec<Crease<T>>,
17715        auto_scroll: bool,
17716        _window: &mut Window,
17717        cx: &mut Context<Self>,
17718    ) {
17719        if creases.is_empty() {
17720            return;
17721        }
17722
17723        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17724
17725        if auto_scroll {
17726            self.request_autoscroll(Autoscroll::fit(), cx);
17727        }
17728
17729        cx.notify();
17730
17731        self.scrollbar_marker_state.dirty = true;
17732        self.folds_did_change(cx);
17733    }
17734
17735    /// Removes any folds whose ranges intersect any of the given ranges.
17736    pub fn unfold_ranges<T: ToOffset + Clone>(
17737        &mut self,
17738        ranges: &[Range<T>],
17739        inclusive: bool,
17740        auto_scroll: bool,
17741        cx: &mut Context<Self>,
17742    ) {
17743        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17744            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17745        });
17746        self.folds_did_change(cx);
17747    }
17748
17749    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17750        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17751            return;
17752        }
17753        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17754        self.display_map.update(cx, |display_map, cx| {
17755            display_map.fold_buffers([buffer_id], cx)
17756        });
17757        cx.emit(EditorEvent::BufferFoldToggled {
17758            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17759            folded: true,
17760        });
17761        cx.notify();
17762    }
17763
17764    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17765        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17766            return;
17767        }
17768        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17769        self.display_map.update(cx, |display_map, cx| {
17770            display_map.unfold_buffers([buffer_id], cx);
17771        });
17772        cx.emit(EditorEvent::BufferFoldToggled {
17773            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17774            folded: false,
17775        });
17776        cx.notify();
17777    }
17778
17779    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17780        self.display_map.read(cx).is_buffer_folded(buffer)
17781    }
17782
17783    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17784        self.display_map.read(cx).folded_buffers()
17785    }
17786
17787    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17788        self.display_map.update(cx, |display_map, cx| {
17789            display_map.disable_header_for_buffer(buffer_id, cx);
17790        });
17791        cx.notify();
17792    }
17793
17794    /// Removes any folds with the given ranges.
17795    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17796        &mut self,
17797        ranges: &[Range<T>],
17798        type_id: TypeId,
17799        auto_scroll: bool,
17800        cx: &mut Context<Self>,
17801    ) {
17802        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17803            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17804        });
17805        self.folds_did_change(cx);
17806    }
17807
17808    fn remove_folds_with<T: ToOffset + Clone>(
17809        &mut self,
17810        ranges: &[Range<T>],
17811        auto_scroll: bool,
17812        cx: &mut Context<Self>,
17813        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17814    ) {
17815        if ranges.is_empty() {
17816            return;
17817        }
17818
17819        let mut buffers_affected = HashSet::default();
17820        let multi_buffer = self.buffer().read(cx);
17821        for range in ranges {
17822            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17823                buffers_affected.insert(buffer.read(cx).remote_id());
17824            };
17825        }
17826
17827        self.display_map.update(cx, update);
17828
17829        if auto_scroll {
17830            self.request_autoscroll(Autoscroll::fit(), cx);
17831        }
17832
17833        cx.notify();
17834        self.scrollbar_marker_state.dirty = true;
17835        self.active_indent_guides_state.dirty = true;
17836    }
17837
17838    pub fn update_renderer_widths(
17839        &mut self,
17840        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17841        cx: &mut Context<Self>,
17842    ) -> bool {
17843        self.display_map
17844            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17845    }
17846
17847    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17848        self.display_map.read(cx).fold_placeholder.clone()
17849    }
17850
17851    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17852        self.buffer.update(cx, |buffer, cx| {
17853            buffer.set_all_diff_hunks_expanded(cx);
17854        });
17855    }
17856
17857    pub fn expand_all_diff_hunks(
17858        &mut self,
17859        _: &ExpandAllDiffHunks,
17860        _window: &mut Window,
17861        cx: &mut Context<Self>,
17862    ) {
17863        self.buffer.update(cx, |buffer, cx| {
17864            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17865        });
17866    }
17867
17868    pub fn toggle_selected_diff_hunks(
17869        &mut self,
17870        _: &ToggleSelectedDiffHunks,
17871        _window: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) {
17874        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17875        self.toggle_diff_hunks_in_ranges(ranges, cx);
17876    }
17877
17878    pub fn diff_hunks_in_ranges<'a>(
17879        &'a self,
17880        ranges: &'a [Range<Anchor>],
17881        buffer: &'a MultiBufferSnapshot,
17882    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17883        ranges.iter().flat_map(move |range| {
17884            let end_excerpt_id = range.end.excerpt_id;
17885            let range = range.to_point(buffer);
17886            let mut peek_end = range.end;
17887            if range.end.row < buffer.max_row().0 {
17888                peek_end = Point::new(range.end.row + 1, 0);
17889            }
17890            buffer
17891                .diff_hunks_in_range(range.start..peek_end)
17892                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17893        })
17894    }
17895
17896    pub fn has_stageable_diff_hunks_in_ranges(
17897        &self,
17898        ranges: &[Range<Anchor>],
17899        snapshot: &MultiBufferSnapshot,
17900    ) -> bool {
17901        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17902        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17903    }
17904
17905    pub fn toggle_staged_selected_diff_hunks(
17906        &mut self,
17907        _: &::git::ToggleStaged,
17908        _: &mut Window,
17909        cx: &mut Context<Self>,
17910    ) {
17911        let snapshot = self.buffer.read(cx).snapshot(cx);
17912        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17913        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17914        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17915    }
17916
17917    pub fn set_render_diff_hunk_controls(
17918        &mut self,
17919        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17920        cx: &mut Context<Self>,
17921    ) {
17922        self.render_diff_hunk_controls = render_diff_hunk_controls;
17923        cx.notify();
17924    }
17925
17926    pub fn stage_and_next(
17927        &mut self,
17928        _: &::git::StageAndNext,
17929        window: &mut Window,
17930        cx: &mut Context<Self>,
17931    ) {
17932        self.do_stage_or_unstage_and_next(true, window, cx);
17933    }
17934
17935    pub fn unstage_and_next(
17936        &mut self,
17937        _: &::git::UnstageAndNext,
17938        window: &mut Window,
17939        cx: &mut Context<Self>,
17940    ) {
17941        self.do_stage_or_unstage_and_next(false, window, cx);
17942    }
17943
17944    pub fn stage_or_unstage_diff_hunks(
17945        &mut self,
17946        stage: bool,
17947        ranges: Vec<Range<Anchor>>,
17948        cx: &mut Context<Self>,
17949    ) {
17950        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17951        cx.spawn(async move |this, cx| {
17952            task.await?;
17953            this.update(cx, |this, cx| {
17954                let snapshot = this.buffer.read(cx).snapshot(cx);
17955                let chunk_by = this
17956                    .diff_hunks_in_ranges(&ranges, &snapshot)
17957                    .chunk_by(|hunk| hunk.buffer_id);
17958                for (buffer_id, hunks) in &chunk_by {
17959                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17960                }
17961            })
17962        })
17963        .detach_and_log_err(cx);
17964    }
17965
17966    fn save_buffers_for_ranges_if_needed(
17967        &mut self,
17968        ranges: &[Range<Anchor>],
17969        cx: &mut Context<Editor>,
17970    ) -> Task<Result<()>> {
17971        let multibuffer = self.buffer.read(cx);
17972        let snapshot = multibuffer.read(cx);
17973        let buffer_ids: HashSet<_> = ranges
17974            .iter()
17975            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17976            .collect();
17977        drop(snapshot);
17978
17979        let mut buffers = HashSet::default();
17980        for buffer_id in buffer_ids {
17981            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17982                let buffer = buffer_entity.read(cx);
17983                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17984                {
17985                    buffers.insert(buffer_entity);
17986                }
17987            }
17988        }
17989
17990        if let Some(project) = &self.project {
17991            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17992        } else {
17993            Task::ready(Ok(()))
17994        }
17995    }
17996
17997    fn do_stage_or_unstage_and_next(
17998        &mut self,
17999        stage: bool,
18000        window: &mut Window,
18001        cx: &mut Context<Self>,
18002    ) {
18003        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18004
18005        if ranges.iter().any(|range| range.start != range.end) {
18006            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18007            return;
18008        }
18009
18010        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18011        let snapshot = self.snapshot(window, cx);
18012        let position = self.selections.newest::<Point>(cx).head();
18013        let mut row = snapshot
18014            .buffer_snapshot
18015            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18016            .find(|hunk| hunk.row_range.start.0 > position.row)
18017            .map(|hunk| hunk.row_range.start);
18018
18019        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18020        // Outside of the project diff editor, wrap around to the beginning.
18021        if !all_diff_hunks_expanded {
18022            row = row.or_else(|| {
18023                snapshot
18024                    .buffer_snapshot
18025                    .diff_hunks_in_range(Point::zero()..position)
18026                    .find(|hunk| hunk.row_range.end.0 < position.row)
18027                    .map(|hunk| hunk.row_range.start)
18028            });
18029        }
18030
18031        if let Some(row) = row {
18032            let destination = Point::new(row.0, 0);
18033            let autoscroll = Autoscroll::center();
18034
18035            self.unfold_ranges(&[destination..destination], false, false, cx);
18036            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18037                s.select_ranges([destination..destination]);
18038            });
18039        }
18040    }
18041
18042    fn do_stage_or_unstage(
18043        &self,
18044        stage: bool,
18045        buffer_id: BufferId,
18046        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18047        cx: &mut App,
18048    ) -> Option<()> {
18049        let project = self.project()?;
18050        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18051        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18052        let buffer_snapshot = buffer.read(cx).snapshot();
18053        let file_exists = buffer_snapshot
18054            .file()
18055            .is_some_and(|file| file.disk_state().exists());
18056        diff.update(cx, |diff, cx| {
18057            diff.stage_or_unstage_hunks(
18058                stage,
18059                &hunks
18060                    .map(|hunk| buffer_diff::DiffHunk {
18061                        buffer_range: hunk.buffer_range,
18062                        diff_base_byte_range: hunk.diff_base_byte_range,
18063                        secondary_status: hunk.secondary_status,
18064                        range: Point::zero()..Point::zero(), // unused
18065                    })
18066                    .collect::<Vec<_>>(),
18067                &buffer_snapshot,
18068                file_exists,
18069                cx,
18070            )
18071        });
18072        None
18073    }
18074
18075    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18076        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18077        self.buffer
18078            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18079    }
18080
18081    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18082        self.buffer.update(cx, |buffer, cx| {
18083            let ranges = vec![Anchor::min()..Anchor::max()];
18084            if !buffer.all_diff_hunks_expanded()
18085                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18086            {
18087                buffer.collapse_diff_hunks(ranges, cx);
18088                true
18089            } else {
18090                false
18091            }
18092        })
18093    }
18094
18095    fn toggle_diff_hunks_in_ranges(
18096        &mut self,
18097        ranges: Vec<Range<Anchor>>,
18098        cx: &mut Context<Editor>,
18099    ) {
18100        self.buffer.update(cx, |buffer, cx| {
18101            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18102            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18103        })
18104    }
18105
18106    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18107        self.buffer.update(cx, |buffer, cx| {
18108            let snapshot = buffer.snapshot(cx);
18109            let excerpt_id = range.end.excerpt_id;
18110            let point_range = range.to_point(&snapshot);
18111            let expand = !buffer.single_hunk_is_expanded(range, cx);
18112            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18113        })
18114    }
18115
18116    pub(crate) fn apply_all_diff_hunks(
18117        &mut self,
18118        _: &ApplyAllDiffHunks,
18119        window: &mut Window,
18120        cx: &mut Context<Self>,
18121    ) {
18122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18123
18124        let buffers = self.buffer.read(cx).all_buffers();
18125        for branch_buffer in buffers {
18126            branch_buffer.update(cx, |branch_buffer, cx| {
18127                branch_buffer.merge_into_base(Vec::new(), cx);
18128            });
18129        }
18130
18131        if let Some(project) = self.project.clone() {
18132            self.save(
18133                SaveOptions {
18134                    format: true,
18135                    autosave: false,
18136                },
18137                project,
18138                window,
18139                cx,
18140            )
18141            .detach_and_log_err(cx);
18142        }
18143    }
18144
18145    pub(crate) fn apply_selected_diff_hunks(
18146        &mut self,
18147        _: &ApplyDiffHunk,
18148        window: &mut Window,
18149        cx: &mut Context<Self>,
18150    ) {
18151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18152        let snapshot = self.snapshot(window, cx);
18153        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18154        let mut ranges_by_buffer = HashMap::default();
18155        self.transact(window, cx, |editor, _window, cx| {
18156            for hunk in hunks {
18157                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18158                    ranges_by_buffer
18159                        .entry(buffer.clone())
18160                        .or_insert_with(Vec::new)
18161                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18162                }
18163            }
18164
18165            for (buffer, ranges) in ranges_by_buffer {
18166                buffer.update(cx, |buffer, cx| {
18167                    buffer.merge_into_base(ranges, cx);
18168                });
18169            }
18170        });
18171
18172        if let Some(project) = self.project.clone() {
18173            self.save(
18174                SaveOptions {
18175                    format: true,
18176                    autosave: false,
18177                },
18178                project,
18179                window,
18180                cx,
18181            )
18182            .detach_and_log_err(cx);
18183        }
18184    }
18185
18186    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18187        if hovered != self.gutter_hovered {
18188            self.gutter_hovered = hovered;
18189            cx.notify();
18190        }
18191    }
18192
18193    pub fn insert_blocks(
18194        &mut self,
18195        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18196        autoscroll: Option<Autoscroll>,
18197        cx: &mut Context<Self>,
18198    ) -> Vec<CustomBlockId> {
18199        let blocks = self
18200            .display_map
18201            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18202        if let Some(autoscroll) = autoscroll {
18203            self.request_autoscroll(autoscroll, cx);
18204        }
18205        cx.notify();
18206        blocks
18207    }
18208
18209    pub fn resize_blocks(
18210        &mut self,
18211        heights: HashMap<CustomBlockId, u32>,
18212        autoscroll: Option<Autoscroll>,
18213        cx: &mut Context<Self>,
18214    ) {
18215        self.display_map
18216            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18217        if let Some(autoscroll) = autoscroll {
18218            self.request_autoscroll(autoscroll, cx);
18219        }
18220        cx.notify();
18221    }
18222
18223    pub fn replace_blocks(
18224        &mut self,
18225        renderers: HashMap<CustomBlockId, RenderBlock>,
18226        autoscroll: Option<Autoscroll>,
18227        cx: &mut Context<Self>,
18228    ) {
18229        self.display_map
18230            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18231        if let Some(autoscroll) = autoscroll {
18232            self.request_autoscroll(autoscroll, cx);
18233        }
18234        cx.notify();
18235    }
18236
18237    pub fn remove_blocks(
18238        &mut self,
18239        block_ids: HashSet<CustomBlockId>,
18240        autoscroll: Option<Autoscroll>,
18241        cx: &mut Context<Self>,
18242    ) {
18243        self.display_map.update(cx, |display_map, cx| {
18244            display_map.remove_blocks(block_ids, cx)
18245        });
18246        if let Some(autoscroll) = autoscroll {
18247            self.request_autoscroll(autoscroll, cx);
18248        }
18249        cx.notify();
18250    }
18251
18252    pub fn row_for_block(
18253        &self,
18254        block_id: CustomBlockId,
18255        cx: &mut Context<Self>,
18256    ) -> Option<DisplayRow> {
18257        self.display_map
18258            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18259    }
18260
18261    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18262        self.focused_block = Some(focused_block);
18263    }
18264
18265    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18266        self.focused_block.take()
18267    }
18268
18269    pub fn insert_creases(
18270        &mut self,
18271        creases: impl IntoIterator<Item = Crease<Anchor>>,
18272        cx: &mut Context<Self>,
18273    ) -> Vec<CreaseId> {
18274        self.display_map
18275            .update(cx, |map, cx| map.insert_creases(creases, cx))
18276    }
18277
18278    pub fn remove_creases(
18279        &mut self,
18280        ids: impl IntoIterator<Item = CreaseId>,
18281        cx: &mut Context<Self>,
18282    ) -> Vec<(CreaseId, Range<Anchor>)> {
18283        self.display_map
18284            .update(cx, |map, cx| map.remove_creases(ids, cx))
18285    }
18286
18287    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18288        self.display_map
18289            .update(cx, |map, cx| map.snapshot(cx))
18290            .longest_row()
18291    }
18292
18293    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18294        self.display_map
18295            .update(cx, |map, cx| map.snapshot(cx))
18296            .max_point()
18297    }
18298
18299    pub fn text(&self, cx: &App) -> String {
18300        self.buffer.read(cx).read(cx).text()
18301    }
18302
18303    pub fn is_empty(&self, cx: &App) -> bool {
18304        self.buffer.read(cx).read(cx).is_empty()
18305    }
18306
18307    pub fn text_option(&self, cx: &App) -> Option<String> {
18308        let text = self.text(cx);
18309        let text = text.trim();
18310
18311        if text.is_empty() {
18312            return None;
18313        }
18314
18315        Some(text.to_string())
18316    }
18317
18318    pub fn set_text(
18319        &mut self,
18320        text: impl Into<Arc<str>>,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        self.transact(window, cx, |this, _, cx| {
18325            this.buffer
18326                .read(cx)
18327                .as_singleton()
18328                .expect("you can only call set_text on editors for singleton buffers")
18329                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18330        });
18331    }
18332
18333    pub fn display_text(&self, cx: &mut App) -> String {
18334        self.display_map
18335            .update(cx, |map, cx| map.snapshot(cx))
18336            .text()
18337    }
18338
18339    fn create_minimap(
18340        &self,
18341        minimap_settings: MinimapSettings,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) -> Option<Entity<Self>> {
18345        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18346            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18347    }
18348
18349    fn initialize_new_minimap(
18350        &self,
18351        minimap_settings: MinimapSettings,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) -> Entity<Self> {
18355        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18356
18357        let mut minimap = Editor::new_internal(
18358            EditorMode::Minimap {
18359                parent: cx.weak_entity(),
18360            },
18361            self.buffer.clone(),
18362            None,
18363            Some(self.display_map.clone()),
18364            window,
18365            cx,
18366        );
18367        minimap.scroll_manager.clone_state(&self.scroll_manager);
18368        minimap.set_text_style_refinement(TextStyleRefinement {
18369            font_size: Some(MINIMAP_FONT_SIZE),
18370            font_weight: Some(MINIMAP_FONT_WEIGHT),
18371            ..Default::default()
18372        });
18373        minimap.update_minimap_configuration(minimap_settings, cx);
18374        cx.new(|_| minimap)
18375    }
18376
18377    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18378        let current_line_highlight = minimap_settings
18379            .current_line_highlight
18380            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18381        self.set_current_line_highlight(Some(current_line_highlight));
18382    }
18383
18384    pub fn minimap(&self) -> Option<&Entity<Self>> {
18385        self.minimap
18386            .as_ref()
18387            .filter(|_| self.minimap_visibility.visible())
18388    }
18389
18390    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18391        let mut wrap_guides = smallvec![];
18392
18393        if self.show_wrap_guides == Some(false) {
18394            return wrap_guides;
18395        }
18396
18397        let settings = self.buffer.read(cx).language_settings(cx);
18398        if settings.show_wrap_guides {
18399            match self.soft_wrap_mode(cx) {
18400                SoftWrap::Column(soft_wrap) => {
18401                    wrap_guides.push((soft_wrap as usize, true));
18402                }
18403                SoftWrap::Bounded(soft_wrap) => {
18404                    wrap_guides.push((soft_wrap as usize, true));
18405                }
18406                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18407            }
18408            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18409        }
18410
18411        wrap_guides
18412    }
18413
18414    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18415        let settings = self.buffer.read(cx).language_settings(cx);
18416        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18417        match mode {
18418            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18419                SoftWrap::None
18420            }
18421            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18422            language_settings::SoftWrap::PreferredLineLength => {
18423                SoftWrap::Column(settings.preferred_line_length)
18424            }
18425            language_settings::SoftWrap::Bounded => {
18426                SoftWrap::Bounded(settings.preferred_line_length)
18427            }
18428        }
18429    }
18430
18431    pub fn set_soft_wrap_mode(
18432        &mut self,
18433        mode: language_settings::SoftWrap,
18434
18435        cx: &mut Context<Self>,
18436    ) {
18437        self.soft_wrap_mode_override = Some(mode);
18438        cx.notify();
18439    }
18440
18441    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18442        self.hard_wrap = hard_wrap;
18443        cx.notify();
18444    }
18445
18446    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18447        self.text_style_refinement = Some(style);
18448    }
18449
18450    /// called by the Element so we know what style we were most recently rendered with.
18451    pub(crate) fn set_style(
18452        &mut self,
18453        style: EditorStyle,
18454        window: &mut Window,
18455        cx: &mut Context<Self>,
18456    ) {
18457        // We intentionally do not inform the display map about the minimap style
18458        // so that wrapping is not recalculated and stays consistent for the editor
18459        // and its linked minimap.
18460        if !self.mode.is_minimap() {
18461            let rem_size = window.rem_size();
18462            self.display_map.update(cx, |map, cx| {
18463                map.set_font(
18464                    style.text.font(),
18465                    style.text.font_size.to_pixels(rem_size),
18466                    cx,
18467                )
18468            });
18469        }
18470        self.style = Some(style);
18471    }
18472
18473    pub fn style(&self) -> Option<&EditorStyle> {
18474        self.style.as_ref()
18475    }
18476
18477    // Called by the element. This method is not designed to be called outside of the editor
18478    // element's layout code because it does not notify when rewrapping is computed synchronously.
18479    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18480        self.display_map
18481            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18482    }
18483
18484    pub fn set_soft_wrap(&mut self) {
18485        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18486    }
18487
18488    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18489        if self.soft_wrap_mode_override.is_some() {
18490            self.soft_wrap_mode_override.take();
18491        } else {
18492            let soft_wrap = match self.soft_wrap_mode(cx) {
18493                SoftWrap::GitDiff => return,
18494                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18495                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18496                    language_settings::SoftWrap::None
18497                }
18498            };
18499            self.soft_wrap_mode_override = Some(soft_wrap);
18500        }
18501        cx.notify();
18502    }
18503
18504    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18505        let Some(workspace) = self.workspace() else {
18506            return;
18507        };
18508        let fs = workspace.read(cx).app_state().fs.clone();
18509        let current_show = TabBarSettings::get_global(cx).show;
18510        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18511            setting.show = Some(!current_show);
18512        });
18513    }
18514
18515    pub fn toggle_indent_guides(
18516        &mut self,
18517        _: &ToggleIndentGuides,
18518        _: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) {
18521        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18522            self.buffer
18523                .read(cx)
18524                .language_settings(cx)
18525                .indent_guides
18526                .enabled
18527        });
18528        self.show_indent_guides = Some(!currently_enabled);
18529        cx.notify();
18530    }
18531
18532    fn should_show_indent_guides(&self) -> Option<bool> {
18533        self.show_indent_guides
18534    }
18535
18536    pub fn toggle_line_numbers(
18537        &mut self,
18538        _: &ToggleLineNumbers,
18539        _: &mut Window,
18540        cx: &mut Context<Self>,
18541    ) {
18542        let mut editor_settings = EditorSettings::get_global(cx).clone();
18543        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18544        EditorSettings::override_global(editor_settings, cx);
18545    }
18546
18547    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18548        if let Some(show_line_numbers) = self.show_line_numbers {
18549            return show_line_numbers;
18550        }
18551        EditorSettings::get_global(cx).gutter.line_numbers
18552    }
18553
18554    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18555        self.use_relative_line_numbers
18556            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18557    }
18558
18559    pub fn toggle_relative_line_numbers(
18560        &mut self,
18561        _: &ToggleRelativeLineNumbers,
18562        _: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        let is_relative = self.should_use_relative_line_numbers(cx);
18566        self.set_relative_line_number(Some(!is_relative), cx)
18567    }
18568
18569    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18570        self.use_relative_line_numbers = is_relative;
18571        cx.notify();
18572    }
18573
18574    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18575        self.show_gutter = show_gutter;
18576        cx.notify();
18577    }
18578
18579    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18580        self.show_scrollbars = ScrollbarAxes {
18581            horizontal: show,
18582            vertical: show,
18583        };
18584        cx.notify();
18585    }
18586
18587    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18588        self.show_scrollbars.vertical = show;
18589        cx.notify();
18590    }
18591
18592    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18593        self.show_scrollbars.horizontal = show;
18594        cx.notify();
18595    }
18596
18597    pub fn set_minimap_visibility(
18598        &mut self,
18599        minimap_visibility: MinimapVisibility,
18600        window: &mut Window,
18601        cx: &mut Context<Self>,
18602    ) {
18603        if self.minimap_visibility != minimap_visibility {
18604            if minimap_visibility.visible() && self.minimap.is_none() {
18605                let minimap_settings = EditorSettings::get_global(cx).minimap;
18606                self.minimap =
18607                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18608            }
18609            self.minimap_visibility = minimap_visibility;
18610            cx.notify();
18611        }
18612    }
18613
18614    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18615        self.set_show_scrollbars(false, cx);
18616        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18617    }
18618
18619    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18620        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18621    }
18622
18623    /// Normally the text in full mode and auto height editors is padded on the
18624    /// left side by roughly half a character width for improved hit testing.
18625    ///
18626    /// Use this method to disable this for cases where this is not wanted (e.g.
18627    /// if you want to align the editor text with some other text above or below)
18628    /// or if you want to add this padding to single-line editors.
18629    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18630        self.offset_content = offset_content;
18631        cx.notify();
18632    }
18633
18634    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18635        self.show_line_numbers = Some(show_line_numbers);
18636        cx.notify();
18637    }
18638
18639    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18640        self.disable_expand_excerpt_buttons = true;
18641        cx.notify();
18642    }
18643
18644    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18645        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18646        cx.notify();
18647    }
18648
18649    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18650        self.show_code_actions = Some(show_code_actions);
18651        cx.notify();
18652    }
18653
18654    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18655        self.show_runnables = Some(show_runnables);
18656        cx.notify();
18657    }
18658
18659    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18660        self.show_breakpoints = Some(show_breakpoints);
18661        cx.notify();
18662    }
18663
18664    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18665        if self.display_map.read(cx).masked != masked {
18666            self.display_map.update(cx, |map, _| map.masked = masked);
18667        }
18668        cx.notify()
18669    }
18670
18671    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18672        self.show_wrap_guides = Some(show_wrap_guides);
18673        cx.notify();
18674    }
18675
18676    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18677        self.show_indent_guides = Some(show_indent_guides);
18678        cx.notify();
18679    }
18680
18681    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18682        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18683            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18684                && let Some(dir) = file.abs_path(cx).parent()
18685            {
18686                return Some(dir.to_owned());
18687            }
18688
18689            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18690                return Some(project_path.path.to_path_buf());
18691            }
18692        }
18693
18694        None
18695    }
18696
18697    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18698        self.active_excerpt(cx)?
18699            .1
18700            .read(cx)
18701            .file()
18702            .and_then(|f| f.as_local())
18703    }
18704
18705    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18706        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18707            let buffer = buffer.read(cx);
18708            if let Some(project_path) = buffer.project_path(cx) {
18709                let project = self.project()?.read(cx);
18710                project.absolute_path(&project_path, cx)
18711            } else {
18712                buffer
18713                    .file()
18714                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18715            }
18716        })
18717    }
18718
18719    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18720        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18721            let project_path = buffer.read(cx).project_path(cx)?;
18722            let project = self.project()?.read(cx);
18723            let entry = project.entry_for_path(&project_path, cx)?;
18724            let path = entry.path.to_path_buf();
18725            Some(path)
18726        })
18727    }
18728
18729    pub fn reveal_in_finder(
18730        &mut self,
18731        _: &RevealInFileManager,
18732        _window: &mut Window,
18733        cx: &mut Context<Self>,
18734    ) {
18735        if let Some(target) = self.target_file(cx) {
18736            cx.reveal_path(&target.abs_path(cx));
18737        }
18738    }
18739
18740    pub fn copy_path(
18741        &mut self,
18742        _: &zed_actions::workspace::CopyPath,
18743        _window: &mut Window,
18744        cx: &mut Context<Self>,
18745    ) {
18746        if let Some(path) = self.target_file_abs_path(cx)
18747            && let Some(path) = path.to_str()
18748        {
18749            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18750        }
18751    }
18752
18753    pub fn copy_relative_path(
18754        &mut self,
18755        _: &zed_actions::workspace::CopyRelativePath,
18756        _window: &mut Window,
18757        cx: &mut Context<Self>,
18758    ) {
18759        if let Some(path) = self.target_file_path(cx)
18760            && let Some(path) = path.to_str()
18761        {
18762            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18763        }
18764    }
18765
18766    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18767        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18768            buffer.read(cx).project_path(cx)
18769        } else {
18770            None
18771        }
18772    }
18773
18774    // Returns true if the editor handled a go-to-line request
18775    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18776        maybe!({
18777            let breakpoint_store = self.breakpoint_store.as_ref()?;
18778
18779            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18780            else {
18781                self.clear_row_highlights::<ActiveDebugLine>();
18782                return None;
18783            };
18784
18785            let position = active_stack_frame.position;
18786            let buffer_id = position.buffer_id?;
18787            let snapshot = self
18788                .project
18789                .as_ref()?
18790                .read(cx)
18791                .buffer_for_id(buffer_id, cx)?
18792                .read(cx)
18793                .snapshot();
18794
18795            let mut handled = false;
18796            for (id, ExcerptRange { context, .. }) in
18797                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18798            {
18799                if context.start.cmp(&position, &snapshot).is_ge()
18800                    || context.end.cmp(&position, &snapshot).is_lt()
18801                {
18802                    continue;
18803                }
18804                let snapshot = self.buffer.read(cx).snapshot(cx);
18805                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18806
18807                handled = true;
18808                self.clear_row_highlights::<ActiveDebugLine>();
18809
18810                self.go_to_line::<ActiveDebugLine>(
18811                    multibuffer_anchor,
18812                    Some(cx.theme().colors().editor_debugger_active_line_background),
18813                    window,
18814                    cx,
18815                );
18816
18817                cx.notify();
18818            }
18819
18820            handled.then_some(())
18821        })
18822        .is_some()
18823    }
18824
18825    pub fn copy_file_name_without_extension(
18826        &mut self,
18827        _: &CopyFileNameWithoutExtension,
18828        _: &mut Window,
18829        cx: &mut Context<Self>,
18830    ) {
18831        if let Some(file) = self.target_file(cx)
18832            && let Some(file_stem) = file.path().file_stem()
18833            && let Some(name) = file_stem.to_str()
18834        {
18835            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18836        }
18837    }
18838
18839    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18840        if let Some(file) = self.target_file(cx)
18841            && let Some(file_name) = file.path().file_name()
18842            && let Some(name) = file_name.to_str()
18843        {
18844            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18845        }
18846    }
18847
18848    pub fn toggle_git_blame(
18849        &mut self,
18850        _: &::git::Blame,
18851        window: &mut Window,
18852        cx: &mut Context<Self>,
18853    ) {
18854        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18855
18856        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18857            self.start_git_blame(true, window, cx);
18858        }
18859
18860        cx.notify();
18861    }
18862
18863    pub fn toggle_git_blame_inline(
18864        &mut self,
18865        _: &ToggleGitBlameInline,
18866        window: &mut Window,
18867        cx: &mut Context<Self>,
18868    ) {
18869        self.toggle_git_blame_inline_internal(true, window, cx);
18870        cx.notify();
18871    }
18872
18873    pub fn open_git_blame_commit(
18874        &mut self,
18875        _: &OpenGitBlameCommit,
18876        window: &mut Window,
18877        cx: &mut Context<Self>,
18878    ) {
18879        self.open_git_blame_commit_internal(window, cx);
18880    }
18881
18882    fn open_git_blame_commit_internal(
18883        &mut self,
18884        window: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) -> Option<()> {
18887        let blame = self.blame.as_ref()?;
18888        let snapshot = self.snapshot(window, cx);
18889        let cursor = self.selections.newest::<Point>(cx).head();
18890        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18891        let blame_entry = blame
18892            .update(cx, |blame, cx| {
18893                blame
18894                    .blame_for_rows(
18895                        &[RowInfo {
18896                            buffer_id: Some(buffer.remote_id()),
18897                            buffer_row: Some(point.row),
18898                            ..Default::default()
18899                        }],
18900                        cx,
18901                    )
18902                    .next()
18903            })
18904            .flatten()?;
18905        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18906        let repo = blame.read(cx).repository(cx)?;
18907        let workspace = self.workspace()?.downgrade();
18908        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18909        None
18910    }
18911
18912    pub fn git_blame_inline_enabled(&self) -> bool {
18913        self.git_blame_inline_enabled
18914    }
18915
18916    pub fn toggle_selection_menu(
18917        &mut self,
18918        _: &ToggleSelectionMenu,
18919        _: &mut Window,
18920        cx: &mut Context<Self>,
18921    ) {
18922        self.show_selection_menu = self
18923            .show_selection_menu
18924            .map(|show_selections_menu| !show_selections_menu)
18925            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18926
18927        cx.notify();
18928    }
18929
18930    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18931        self.show_selection_menu
18932            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18933    }
18934
18935    fn start_git_blame(
18936        &mut self,
18937        user_triggered: bool,
18938        window: &mut Window,
18939        cx: &mut Context<Self>,
18940    ) {
18941        if let Some(project) = self.project() {
18942            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18943                return;
18944            };
18945
18946            if buffer.read(cx).file().is_none() {
18947                return;
18948            }
18949
18950            let focused = self.focus_handle(cx).contains_focused(window, cx);
18951
18952            let project = project.clone();
18953            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18954            self.blame_subscription =
18955                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18956            self.blame = Some(blame);
18957        }
18958    }
18959
18960    fn toggle_git_blame_inline_internal(
18961        &mut self,
18962        user_triggered: bool,
18963        window: &mut Window,
18964        cx: &mut Context<Self>,
18965    ) {
18966        if self.git_blame_inline_enabled {
18967            self.git_blame_inline_enabled = false;
18968            self.show_git_blame_inline = false;
18969            self.show_git_blame_inline_delay_task.take();
18970        } else {
18971            self.git_blame_inline_enabled = true;
18972            self.start_git_blame_inline(user_triggered, window, cx);
18973        }
18974
18975        cx.notify();
18976    }
18977
18978    fn start_git_blame_inline(
18979        &mut self,
18980        user_triggered: bool,
18981        window: &mut Window,
18982        cx: &mut Context<Self>,
18983    ) {
18984        self.start_git_blame(user_triggered, window, cx);
18985
18986        if ProjectSettings::get_global(cx)
18987            .git
18988            .inline_blame_delay()
18989            .is_some()
18990        {
18991            self.start_inline_blame_timer(window, cx);
18992        } else {
18993            self.show_git_blame_inline = true
18994        }
18995    }
18996
18997    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18998        self.blame.as_ref()
18999    }
19000
19001    pub fn show_git_blame_gutter(&self) -> bool {
19002        self.show_git_blame_gutter
19003    }
19004
19005    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19006        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19007    }
19008
19009    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19010        self.show_git_blame_inline
19011            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19012            && !self.newest_selection_head_on_empty_line(cx)
19013            && self.has_blame_entries(cx)
19014    }
19015
19016    fn has_blame_entries(&self, cx: &App) -> bool {
19017        self.blame()
19018            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19019    }
19020
19021    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19022        let cursor_anchor = self.selections.newest_anchor().head();
19023
19024        let snapshot = self.buffer.read(cx).snapshot(cx);
19025        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19026
19027        snapshot.line_len(buffer_row) == 0
19028    }
19029
19030    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19031        let buffer_and_selection = maybe!({
19032            let selection = self.selections.newest::<Point>(cx);
19033            let selection_range = selection.range();
19034
19035            let multi_buffer = self.buffer().read(cx);
19036            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19037            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19038
19039            let (buffer, range, _) = if selection.reversed {
19040                buffer_ranges.first()
19041            } else {
19042                buffer_ranges.last()
19043            }?;
19044
19045            let selection = text::ToPoint::to_point(&range.start, buffer).row
19046                ..text::ToPoint::to_point(&range.end, buffer).row;
19047            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19048        });
19049
19050        let Some((buffer, selection)) = buffer_and_selection else {
19051            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19052        };
19053
19054        let Some(project) = self.project() else {
19055            return Task::ready(Err(anyhow!("editor does not have project")));
19056        };
19057
19058        project.update(cx, |project, cx| {
19059            project.get_permalink_to_line(&buffer, selection, cx)
19060        })
19061    }
19062
19063    pub fn copy_permalink_to_line(
19064        &mut self,
19065        _: &CopyPermalinkToLine,
19066        window: &mut Window,
19067        cx: &mut Context<Self>,
19068    ) {
19069        let permalink_task = self.get_permalink_to_line(cx);
19070        let workspace = self.workspace();
19071
19072        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19073            Ok(permalink) => {
19074                cx.update(|_, cx| {
19075                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19076                })
19077                .ok();
19078            }
19079            Err(err) => {
19080                let message = format!("Failed to copy permalink: {err}");
19081
19082                anyhow::Result::<()>::Err(err).log_err();
19083
19084                if let Some(workspace) = workspace {
19085                    workspace
19086                        .update_in(cx, |workspace, _, cx| {
19087                            struct CopyPermalinkToLine;
19088
19089                            workspace.show_toast(
19090                                Toast::new(
19091                                    NotificationId::unique::<CopyPermalinkToLine>(),
19092                                    message,
19093                                ),
19094                                cx,
19095                            )
19096                        })
19097                        .ok();
19098                }
19099            }
19100        })
19101        .detach();
19102    }
19103
19104    pub fn copy_file_location(
19105        &mut self,
19106        _: &CopyFileLocation,
19107        _: &mut Window,
19108        cx: &mut Context<Self>,
19109    ) {
19110        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19111        if let Some(file) = self.target_file(cx)
19112            && let Some(path) = file.path().to_str()
19113        {
19114            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19115        }
19116    }
19117
19118    pub fn open_permalink_to_line(
19119        &mut self,
19120        _: &OpenPermalinkToLine,
19121        window: &mut Window,
19122        cx: &mut Context<Self>,
19123    ) {
19124        let permalink_task = self.get_permalink_to_line(cx);
19125        let workspace = self.workspace();
19126
19127        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19128            Ok(permalink) => {
19129                cx.update(|_, cx| {
19130                    cx.open_url(permalink.as_ref());
19131                })
19132                .ok();
19133            }
19134            Err(err) => {
19135                let message = format!("Failed to open permalink: {err}");
19136
19137                anyhow::Result::<()>::Err(err).log_err();
19138
19139                if let Some(workspace) = workspace {
19140                    workspace
19141                        .update(cx, |workspace, cx| {
19142                            struct OpenPermalinkToLine;
19143
19144                            workspace.show_toast(
19145                                Toast::new(
19146                                    NotificationId::unique::<OpenPermalinkToLine>(),
19147                                    message,
19148                                ),
19149                                cx,
19150                            )
19151                        })
19152                        .ok();
19153                }
19154            }
19155        })
19156        .detach();
19157    }
19158
19159    pub fn insert_uuid_v4(
19160        &mut self,
19161        _: &InsertUuidV4,
19162        window: &mut Window,
19163        cx: &mut Context<Self>,
19164    ) {
19165        self.insert_uuid(UuidVersion::V4, window, cx);
19166    }
19167
19168    pub fn insert_uuid_v7(
19169        &mut self,
19170        _: &InsertUuidV7,
19171        window: &mut Window,
19172        cx: &mut Context<Self>,
19173    ) {
19174        self.insert_uuid(UuidVersion::V7, window, cx);
19175    }
19176
19177    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19179        self.transact(window, cx, |this, window, cx| {
19180            let edits = this
19181                .selections
19182                .all::<Point>(cx)
19183                .into_iter()
19184                .map(|selection| {
19185                    let uuid = match version {
19186                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19187                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19188                    };
19189
19190                    (selection.range(), uuid.to_string())
19191                });
19192            this.edit(edits, cx);
19193            this.refresh_edit_prediction(true, false, window, cx);
19194        });
19195    }
19196
19197    pub fn open_selections_in_multibuffer(
19198        &mut self,
19199        _: &OpenSelectionsInMultibuffer,
19200        window: &mut Window,
19201        cx: &mut Context<Self>,
19202    ) {
19203        let multibuffer = self.buffer.read(cx);
19204
19205        let Some(buffer) = multibuffer.as_singleton() else {
19206            return;
19207        };
19208
19209        let Some(workspace) = self.workspace() else {
19210            return;
19211        };
19212
19213        let title = multibuffer.title(cx).to_string();
19214
19215        let locations = self
19216            .selections
19217            .all_anchors(cx)
19218            .iter()
19219            .map(|selection| Location {
19220                buffer: buffer.clone(),
19221                range: selection.start.text_anchor..selection.end.text_anchor,
19222            })
19223            .collect::<Vec<_>>();
19224
19225        cx.spawn_in(window, async move |_, cx| {
19226            workspace.update_in(cx, |workspace, window, cx| {
19227                Self::open_locations_in_multibuffer(
19228                    workspace,
19229                    locations,
19230                    format!("Selections for '{title}'"),
19231                    false,
19232                    MultibufferSelectionMode::All,
19233                    window,
19234                    cx,
19235                );
19236            })
19237        })
19238        .detach();
19239    }
19240
19241    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19242    /// last highlight added will be used.
19243    ///
19244    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19245    pub fn highlight_rows<T: 'static>(
19246        &mut self,
19247        range: Range<Anchor>,
19248        color: Hsla,
19249        options: RowHighlightOptions,
19250        cx: &mut Context<Self>,
19251    ) {
19252        let snapshot = self.buffer().read(cx).snapshot(cx);
19253        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19254        let ix = row_highlights.binary_search_by(|highlight| {
19255            Ordering::Equal
19256                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19257                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19258        });
19259
19260        if let Err(mut ix) = ix {
19261            let index = post_inc(&mut self.highlight_order);
19262
19263            // If this range intersects with the preceding highlight, then merge it with
19264            // the preceding highlight. Otherwise insert a new highlight.
19265            let mut merged = false;
19266            if ix > 0 {
19267                let prev_highlight = &mut row_highlights[ix - 1];
19268                if prev_highlight
19269                    .range
19270                    .end
19271                    .cmp(&range.start, &snapshot)
19272                    .is_ge()
19273                {
19274                    ix -= 1;
19275                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19276                        prev_highlight.range.end = range.end;
19277                    }
19278                    merged = true;
19279                    prev_highlight.index = index;
19280                    prev_highlight.color = color;
19281                    prev_highlight.options = options;
19282                }
19283            }
19284
19285            if !merged {
19286                row_highlights.insert(
19287                    ix,
19288                    RowHighlight {
19289                        range,
19290                        index,
19291                        color,
19292                        options,
19293                        type_id: TypeId::of::<T>(),
19294                    },
19295                );
19296            }
19297
19298            // If any of the following highlights intersect with this one, merge them.
19299            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19300                let highlight = &row_highlights[ix];
19301                if next_highlight
19302                    .range
19303                    .start
19304                    .cmp(&highlight.range.end, &snapshot)
19305                    .is_le()
19306                {
19307                    if next_highlight
19308                        .range
19309                        .end
19310                        .cmp(&highlight.range.end, &snapshot)
19311                        .is_gt()
19312                    {
19313                        row_highlights[ix].range.end = next_highlight.range.end;
19314                    }
19315                    row_highlights.remove(ix + 1);
19316                } else {
19317                    break;
19318                }
19319            }
19320        }
19321    }
19322
19323    /// Remove any highlighted row ranges of the given type that intersect the
19324    /// given ranges.
19325    pub fn remove_highlighted_rows<T: 'static>(
19326        &mut self,
19327        ranges_to_remove: Vec<Range<Anchor>>,
19328        cx: &mut Context<Self>,
19329    ) {
19330        let snapshot = self.buffer().read(cx).snapshot(cx);
19331        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19332        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19333        row_highlights.retain(|highlight| {
19334            while let Some(range_to_remove) = ranges_to_remove.peek() {
19335                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19336                    Ordering::Less | Ordering::Equal => {
19337                        ranges_to_remove.next();
19338                    }
19339                    Ordering::Greater => {
19340                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19341                            Ordering::Less | Ordering::Equal => {
19342                                return false;
19343                            }
19344                            Ordering::Greater => break,
19345                        }
19346                    }
19347                }
19348            }
19349
19350            true
19351        })
19352    }
19353
19354    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19355    pub fn clear_row_highlights<T: 'static>(&mut self) {
19356        self.highlighted_rows.remove(&TypeId::of::<T>());
19357    }
19358
19359    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19360    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19361        self.highlighted_rows
19362            .get(&TypeId::of::<T>())
19363            .map_or(&[] as &[_], |vec| vec.as_slice())
19364            .iter()
19365            .map(|highlight| (highlight.range.clone(), highlight.color))
19366    }
19367
19368    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19369    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19370    /// Allows to ignore certain kinds of highlights.
19371    pub fn highlighted_display_rows(
19372        &self,
19373        window: &mut Window,
19374        cx: &mut App,
19375    ) -> BTreeMap<DisplayRow, LineHighlight> {
19376        let snapshot = self.snapshot(window, cx);
19377        let mut used_highlight_orders = HashMap::default();
19378        self.highlighted_rows
19379            .iter()
19380            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19381            .fold(
19382                BTreeMap::<DisplayRow, LineHighlight>::new(),
19383                |mut unique_rows, highlight| {
19384                    let start = highlight.range.start.to_display_point(&snapshot);
19385                    let end = highlight.range.end.to_display_point(&snapshot);
19386                    let start_row = start.row().0;
19387                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19388                        && end.column() == 0
19389                    {
19390                        end.row().0.saturating_sub(1)
19391                    } else {
19392                        end.row().0
19393                    };
19394                    for row in start_row..=end_row {
19395                        let used_index =
19396                            used_highlight_orders.entry(row).or_insert(highlight.index);
19397                        if highlight.index >= *used_index {
19398                            *used_index = highlight.index;
19399                            unique_rows.insert(
19400                                DisplayRow(row),
19401                                LineHighlight {
19402                                    include_gutter: highlight.options.include_gutter,
19403                                    border: None,
19404                                    background: highlight.color.into(),
19405                                    type_id: Some(highlight.type_id),
19406                                },
19407                            );
19408                        }
19409                    }
19410                    unique_rows
19411                },
19412            )
19413    }
19414
19415    pub fn highlighted_display_row_for_autoscroll(
19416        &self,
19417        snapshot: &DisplaySnapshot,
19418    ) -> Option<DisplayRow> {
19419        self.highlighted_rows
19420            .values()
19421            .flat_map(|highlighted_rows| highlighted_rows.iter())
19422            .filter_map(|highlight| {
19423                if highlight.options.autoscroll {
19424                    Some(highlight.range.start.to_display_point(snapshot).row())
19425                } else {
19426                    None
19427                }
19428            })
19429            .min()
19430    }
19431
19432    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19433        self.highlight_background::<SearchWithinRange>(
19434            ranges,
19435            |colors| colors.colors().editor_document_highlight_read_background,
19436            cx,
19437        )
19438    }
19439
19440    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19441        self.breadcrumb_header = Some(new_header);
19442    }
19443
19444    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19445        self.clear_background_highlights::<SearchWithinRange>(cx);
19446    }
19447
19448    pub fn highlight_background<T: 'static>(
19449        &mut self,
19450        ranges: &[Range<Anchor>],
19451        color_fetcher: fn(&Theme) -> Hsla,
19452        cx: &mut Context<Self>,
19453    ) {
19454        self.background_highlights.insert(
19455            HighlightKey::Type(TypeId::of::<T>()),
19456            (color_fetcher, Arc::from(ranges)),
19457        );
19458        self.scrollbar_marker_state.dirty = true;
19459        cx.notify();
19460    }
19461
19462    pub fn highlight_background_key<T: 'static>(
19463        &mut self,
19464        key: usize,
19465        ranges: &[Range<Anchor>],
19466        color_fetcher: fn(&Theme) -> Hsla,
19467        cx: &mut Context<Self>,
19468    ) {
19469        self.background_highlights.insert(
19470            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19471            (color_fetcher, Arc::from(ranges)),
19472        );
19473        self.scrollbar_marker_state.dirty = true;
19474        cx.notify();
19475    }
19476
19477    pub fn clear_background_highlights<T: 'static>(
19478        &mut self,
19479        cx: &mut Context<Self>,
19480    ) -> Option<BackgroundHighlight> {
19481        let text_highlights = self
19482            .background_highlights
19483            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19484        if !text_highlights.1.is_empty() {
19485            self.scrollbar_marker_state.dirty = true;
19486            cx.notify();
19487        }
19488        Some(text_highlights)
19489    }
19490
19491    pub fn highlight_gutter<T: 'static>(
19492        &mut self,
19493        ranges: impl Into<Vec<Range<Anchor>>>,
19494        color_fetcher: fn(&App) -> Hsla,
19495        cx: &mut Context<Self>,
19496    ) {
19497        self.gutter_highlights
19498            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19499        cx.notify();
19500    }
19501
19502    pub fn clear_gutter_highlights<T: 'static>(
19503        &mut self,
19504        cx: &mut Context<Self>,
19505    ) -> Option<GutterHighlight> {
19506        cx.notify();
19507        self.gutter_highlights.remove(&TypeId::of::<T>())
19508    }
19509
19510    pub fn insert_gutter_highlight<T: 'static>(
19511        &mut self,
19512        range: Range<Anchor>,
19513        color_fetcher: fn(&App) -> Hsla,
19514        cx: &mut Context<Self>,
19515    ) {
19516        let snapshot = self.buffer().read(cx).snapshot(cx);
19517        let mut highlights = self
19518            .gutter_highlights
19519            .remove(&TypeId::of::<T>())
19520            .map(|(_, highlights)| highlights)
19521            .unwrap_or_default();
19522        let ix = highlights.binary_search_by(|highlight| {
19523            Ordering::Equal
19524                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19525                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19526        });
19527        if let Err(ix) = ix {
19528            highlights.insert(ix, range);
19529        }
19530        self.gutter_highlights
19531            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19532    }
19533
19534    pub fn remove_gutter_highlights<T: 'static>(
19535        &mut self,
19536        ranges_to_remove: Vec<Range<Anchor>>,
19537        cx: &mut Context<Self>,
19538    ) {
19539        let snapshot = self.buffer().read(cx).snapshot(cx);
19540        let Some((color_fetcher, mut gutter_highlights)) =
19541            self.gutter_highlights.remove(&TypeId::of::<T>())
19542        else {
19543            return;
19544        };
19545        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19546        gutter_highlights.retain(|highlight| {
19547            while let Some(range_to_remove) = ranges_to_remove.peek() {
19548                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19549                    Ordering::Less | Ordering::Equal => {
19550                        ranges_to_remove.next();
19551                    }
19552                    Ordering::Greater => {
19553                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19554                            Ordering::Less | Ordering::Equal => {
19555                                return false;
19556                            }
19557                            Ordering::Greater => break,
19558                        }
19559                    }
19560                }
19561            }
19562
19563            true
19564        });
19565        self.gutter_highlights
19566            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19567    }
19568
19569    #[cfg(feature = "test-support")]
19570    pub fn all_text_highlights(
19571        &self,
19572        window: &mut Window,
19573        cx: &mut Context<Self>,
19574    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19575        let snapshot = self.snapshot(window, cx);
19576        self.display_map.update(cx, |display_map, _| {
19577            display_map
19578                .all_text_highlights()
19579                .map(|highlight| {
19580                    let (style, ranges) = highlight.as_ref();
19581                    (
19582                        *style,
19583                        ranges
19584                            .iter()
19585                            .map(|range| range.clone().to_display_points(&snapshot))
19586                            .collect(),
19587                    )
19588                })
19589                .collect()
19590        })
19591    }
19592
19593    #[cfg(feature = "test-support")]
19594    pub fn all_text_background_highlights(
19595        &self,
19596        window: &mut Window,
19597        cx: &mut Context<Self>,
19598    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19599        let snapshot = self.snapshot(window, cx);
19600        let buffer = &snapshot.buffer_snapshot;
19601        let start = buffer.anchor_before(0);
19602        let end = buffer.anchor_after(buffer.len());
19603        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19604    }
19605
19606    #[cfg(feature = "test-support")]
19607    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19608        let snapshot = self.buffer().read(cx).snapshot(cx);
19609
19610        let highlights = self
19611            .background_highlights
19612            .get(&HighlightKey::Type(TypeId::of::<
19613                items::BufferSearchHighlights,
19614            >()));
19615
19616        if let Some((_color, ranges)) = highlights {
19617            ranges
19618                .iter()
19619                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19620                .collect_vec()
19621        } else {
19622            vec![]
19623        }
19624    }
19625
19626    fn document_highlights_for_position<'a>(
19627        &'a self,
19628        position: Anchor,
19629        buffer: &'a MultiBufferSnapshot,
19630    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19631        let read_highlights = self
19632            .background_highlights
19633            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19634            .map(|h| &h.1);
19635        let write_highlights = self
19636            .background_highlights
19637            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19638            .map(|h| &h.1);
19639        let left_position = position.bias_left(buffer);
19640        let right_position = position.bias_right(buffer);
19641        read_highlights
19642            .into_iter()
19643            .chain(write_highlights)
19644            .flat_map(move |ranges| {
19645                let start_ix = match ranges.binary_search_by(|probe| {
19646                    let cmp = probe.end.cmp(&left_position, buffer);
19647                    if cmp.is_ge() {
19648                        Ordering::Greater
19649                    } else {
19650                        Ordering::Less
19651                    }
19652                }) {
19653                    Ok(i) | Err(i) => i,
19654                };
19655
19656                ranges[start_ix..]
19657                    .iter()
19658                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19659            })
19660    }
19661
19662    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19663        self.background_highlights
19664            .get(&HighlightKey::Type(TypeId::of::<T>()))
19665            .is_some_and(|(_, highlights)| !highlights.is_empty())
19666    }
19667
19668    pub fn background_highlights_in_range(
19669        &self,
19670        search_range: Range<Anchor>,
19671        display_snapshot: &DisplaySnapshot,
19672        theme: &Theme,
19673    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19674        let mut results = Vec::new();
19675        for (color_fetcher, ranges) in self.background_highlights.values() {
19676            let color = color_fetcher(theme);
19677            let start_ix = match ranges.binary_search_by(|probe| {
19678                let cmp = probe
19679                    .end
19680                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19681                if cmp.is_gt() {
19682                    Ordering::Greater
19683                } else {
19684                    Ordering::Less
19685                }
19686            }) {
19687                Ok(i) | Err(i) => i,
19688            };
19689            for range in &ranges[start_ix..] {
19690                if range
19691                    .start
19692                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19693                    .is_ge()
19694                {
19695                    break;
19696                }
19697
19698                let start = range.start.to_display_point(display_snapshot);
19699                let end = range.end.to_display_point(display_snapshot);
19700                results.push((start..end, color))
19701            }
19702        }
19703        results
19704    }
19705
19706    pub fn background_highlight_row_ranges<T: 'static>(
19707        &self,
19708        search_range: Range<Anchor>,
19709        display_snapshot: &DisplaySnapshot,
19710        count: usize,
19711    ) -> Vec<RangeInclusive<DisplayPoint>> {
19712        let mut results = Vec::new();
19713        let Some((_, ranges)) = self
19714            .background_highlights
19715            .get(&HighlightKey::Type(TypeId::of::<T>()))
19716        else {
19717            return vec![];
19718        };
19719
19720        let start_ix = match ranges.binary_search_by(|probe| {
19721            let cmp = probe
19722                .end
19723                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19724            if cmp.is_gt() {
19725                Ordering::Greater
19726            } else {
19727                Ordering::Less
19728            }
19729        }) {
19730            Ok(i) | Err(i) => i,
19731        };
19732        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19733            if let (Some(start_display), Some(end_display)) = (start, end) {
19734                results.push(
19735                    start_display.to_display_point(display_snapshot)
19736                        ..=end_display.to_display_point(display_snapshot),
19737                );
19738            }
19739        };
19740        let mut start_row: Option<Point> = None;
19741        let mut end_row: Option<Point> = None;
19742        if ranges.len() > count {
19743            return Vec::new();
19744        }
19745        for range in &ranges[start_ix..] {
19746            if range
19747                .start
19748                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19749                .is_ge()
19750            {
19751                break;
19752            }
19753            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19754            if let Some(current_row) = &end_row
19755                && end.row == current_row.row
19756            {
19757                continue;
19758            }
19759            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19760            if start_row.is_none() {
19761                assert_eq!(end_row, None);
19762                start_row = Some(start);
19763                end_row = Some(end);
19764                continue;
19765            }
19766            if let Some(current_end) = end_row.as_mut() {
19767                if start.row > current_end.row + 1 {
19768                    push_region(start_row, end_row);
19769                    start_row = Some(start);
19770                    end_row = Some(end);
19771                } else {
19772                    // Merge two hunks.
19773                    *current_end = end;
19774                }
19775            } else {
19776                unreachable!();
19777            }
19778        }
19779        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19780        push_region(start_row, end_row);
19781        results
19782    }
19783
19784    pub fn gutter_highlights_in_range(
19785        &self,
19786        search_range: Range<Anchor>,
19787        display_snapshot: &DisplaySnapshot,
19788        cx: &App,
19789    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19790        let mut results = Vec::new();
19791        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19792            let color = color_fetcher(cx);
19793            let start_ix = match ranges.binary_search_by(|probe| {
19794                let cmp = probe
19795                    .end
19796                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19797                if cmp.is_gt() {
19798                    Ordering::Greater
19799                } else {
19800                    Ordering::Less
19801                }
19802            }) {
19803                Ok(i) | Err(i) => i,
19804            };
19805            for range in &ranges[start_ix..] {
19806                if range
19807                    .start
19808                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19809                    .is_ge()
19810                {
19811                    break;
19812                }
19813
19814                let start = range.start.to_display_point(display_snapshot);
19815                let end = range.end.to_display_point(display_snapshot);
19816                results.push((start..end, color))
19817            }
19818        }
19819        results
19820    }
19821
19822    /// Get the text ranges corresponding to the redaction query
19823    pub fn redacted_ranges(
19824        &self,
19825        search_range: Range<Anchor>,
19826        display_snapshot: &DisplaySnapshot,
19827        cx: &App,
19828    ) -> Vec<Range<DisplayPoint>> {
19829        display_snapshot
19830            .buffer_snapshot
19831            .redacted_ranges(search_range, |file| {
19832                if let Some(file) = file {
19833                    file.is_private()
19834                        && EditorSettings::get(
19835                            Some(SettingsLocation {
19836                                worktree_id: file.worktree_id(cx),
19837                                path: file.path().as_ref(),
19838                            }),
19839                            cx,
19840                        )
19841                        .redact_private_values
19842                } else {
19843                    false
19844                }
19845            })
19846            .map(|range| {
19847                range.start.to_display_point(display_snapshot)
19848                    ..range.end.to_display_point(display_snapshot)
19849            })
19850            .collect()
19851    }
19852
19853    pub fn highlight_text_key<T: 'static>(
19854        &mut self,
19855        key: usize,
19856        ranges: Vec<Range<Anchor>>,
19857        style: HighlightStyle,
19858        cx: &mut Context<Self>,
19859    ) {
19860        self.display_map.update(cx, |map, _| {
19861            map.highlight_text(
19862                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19863                ranges,
19864                style,
19865            );
19866        });
19867        cx.notify();
19868    }
19869
19870    pub fn highlight_text<T: 'static>(
19871        &mut self,
19872        ranges: Vec<Range<Anchor>>,
19873        style: HighlightStyle,
19874        cx: &mut Context<Self>,
19875    ) {
19876        self.display_map.update(cx, |map, _| {
19877            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19878        });
19879        cx.notify();
19880    }
19881
19882    pub(crate) fn highlight_inlays<T: 'static>(
19883        &mut self,
19884        highlights: Vec<InlayHighlight>,
19885        style: HighlightStyle,
19886        cx: &mut Context<Self>,
19887    ) {
19888        self.display_map.update(cx, |map, _| {
19889            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19890        });
19891        cx.notify();
19892    }
19893
19894    pub fn text_highlights<'a, T: 'static>(
19895        &'a self,
19896        cx: &'a App,
19897    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19898        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19899    }
19900
19901    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19902        let cleared = self
19903            .display_map
19904            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19905        if cleared {
19906            cx.notify();
19907        }
19908    }
19909
19910    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19911        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19912            && self.focus_handle.is_focused(window)
19913    }
19914
19915    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19916        self.show_cursor_when_unfocused = is_enabled;
19917        cx.notify();
19918    }
19919
19920    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19921        cx.notify();
19922    }
19923
19924    fn on_debug_session_event(
19925        &mut self,
19926        _session: Entity<Session>,
19927        event: &SessionEvent,
19928        cx: &mut Context<Self>,
19929    ) {
19930        if let SessionEvent::InvalidateInlineValue = event {
19931            self.refresh_inline_values(cx);
19932        }
19933    }
19934
19935    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19936        let Some(project) = self.project.clone() else {
19937            return;
19938        };
19939
19940        if !self.inline_value_cache.enabled {
19941            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19942            self.splice_inlays(&inlays, Vec::new(), cx);
19943            return;
19944        }
19945
19946        let current_execution_position = self
19947            .highlighted_rows
19948            .get(&TypeId::of::<ActiveDebugLine>())
19949            .and_then(|lines| lines.last().map(|line| line.range.end));
19950
19951        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19952            let inline_values = editor
19953                .update(cx, |editor, cx| {
19954                    let Some(current_execution_position) = current_execution_position else {
19955                        return Some(Task::ready(Ok(Vec::new())));
19956                    };
19957
19958                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19959                        let snapshot = buffer.snapshot(cx);
19960
19961                        let excerpt = snapshot.excerpt_containing(
19962                            current_execution_position..current_execution_position,
19963                        )?;
19964
19965                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19966                    })?;
19967
19968                    let range =
19969                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19970
19971                    project.inline_values(buffer, range, cx)
19972                })
19973                .ok()
19974                .flatten()?
19975                .await
19976                .context("refreshing debugger inlays")
19977                .log_err()?;
19978
19979            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19980
19981            for (buffer_id, inline_value) in inline_values
19982                .into_iter()
19983                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19984            {
19985                buffer_inline_values
19986                    .entry(buffer_id)
19987                    .or_default()
19988                    .push(inline_value);
19989            }
19990
19991            editor
19992                .update(cx, |editor, cx| {
19993                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19994                    let mut new_inlays = Vec::default();
19995
19996                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19997                        let buffer_id = buffer_snapshot.remote_id();
19998                        buffer_inline_values
19999                            .get(&buffer_id)
20000                            .into_iter()
20001                            .flatten()
20002                            .for_each(|hint| {
20003                                let inlay = Inlay::debugger(
20004                                    post_inc(&mut editor.next_inlay_id),
20005                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20006                                    hint.text(),
20007                                );
20008                                if !inlay.text.chars().contains(&'\n') {
20009                                    new_inlays.push(inlay);
20010                                }
20011                            });
20012                    }
20013
20014                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20015                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20016
20017                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20018                })
20019                .ok()?;
20020            Some(())
20021        });
20022    }
20023
20024    fn on_buffer_event(
20025        &mut self,
20026        multibuffer: &Entity<MultiBuffer>,
20027        event: &multi_buffer::Event,
20028        window: &mut Window,
20029        cx: &mut Context<Self>,
20030    ) {
20031        match event {
20032            multi_buffer::Event::Edited {
20033                singleton_buffer_edited,
20034                edited_buffer,
20035            } => {
20036                self.scrollbar_marker_state.dirty = true;
20037                self.active_indent_guides_state.dirty = true;
20038                self.refresh_active_diagnostics(cx);
20039                self.refresh_code_actions(window, cx);
20040                self.refresh_selected_text_highlights(true, window, cx);
20041                self.refresh_single_line_folds(window, cx);
20042                refresh_matching_bracket_highlights(self, window, cx);
20043                if self.has_active_edit_prediction() {
20044                    self.update_visible_edit_prediction(window, cx);
20045                }
20046                if let Some(project) = self.project.as_ref()
20047                    && let Some(edited_buffer) = edited_buffer
20048                {
20049                    project.update(cx, |project, cx| {
20050                        self.registered_buffers
20051                            .entry(edited_buffer.read(cx).remote_id())
20052                            .or_insert_with(|| {
20053                                project.register_buffer_with_language_servers(edited_buffer, cx)
20054                            });
20055                    });
20056                }
20057                cx.emit(EditorEvent::BufferEdited);
20058                cx.emit(SearchEvent::MatchesInvalidated);
20059
20060                if let Some(buffer) = edited_buffer {
20061                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20062                }
20063
20064                if *singleton_buffer_edited {
20065                    if let Some(buffer) = edited_buffer
20066                        && buffer.read(cx).file().is_none()
20067                    {
20068                        cx.emit(EditorEvent::TitleChanged);
20069                    }
20070                    if let Some(project) = &self.project {
20071                        #[allow(clippy::mutable_key_type)]
20072                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20073                            multibuffer
20074                                .all_buffers()
20075                                .into_iter()
20076                                .filter_map(|buffer| {
20077                                    buffer.update(cx, |buffer, cx| {
20078                                        let language = buffer.language()?;
20079                                        let should_discard = project.update(cx, |project, cx| {
20080                                            project.is_local()
20081                                                && !project.has_language_servers_for(buffer, cx)
20082                                        });
20083                                        should_discard.not().then_some(language.clone())
20084                                    })
20085                                })
20086                                .collect::<HashSet<_>>()
20087                        });
20088                        if !languages_affected.is_empty() {
20089                            self.refresh_inlay_hints(
20090                                InlayHintRefreshReason::BufferEdited(languages_affected),
20091                                cx,
20092                            );
20093                        }
20094                    }
20095                }
20096
20097                let Some(project) = &self.project else { return };
20098                let (telemetry, is_via_ssh) = {
20099                    let project = project.read(cx);
20100                    let telemetry = project.client().telemetry().clone();
20101                    let is_via_ssh = project.is_via_ssh();
20102                    (telemetry, is_via_ssh)
20103                };
20104                refresh_linked_ranges(self, window, cx);
20105                telemetry.log_edit_event("editor", is_via_ssh);
20106            }
20107            multi_buffer::Event::ExcerptsAdded {
20108                buffer,
20109                predecessor,
20110                excerpts,
20111            } => {
20112                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20113                let buffer_id = buffer.read(cx).remote_id();
20114                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20115                    && let Some(project) = &self.project
20116                {
20117                    update_uncommitted_diff_for_buffer(
20118                        cx.entity(),
20119                        project,
20120                        [buffer.clone()],
20121                        self.buffer.clone(),
20122                        cx,
20123                    )
20124                    .detach();
20125                }
20126                self.update_lsp_data(false, Some(buffer_id), window, cx);
20127                cx.emit(EditorEvent::ExcerptsAdded {
20128                    buffer: buffer.clone(),
20129                    predecessor: *predecessor,
20130                    excerpts: excerpts.clone(),
20131                });
20132                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20133            }
20134            multi_buffer::Event::ExcerptsRemoved {
20135                ids,
20136                removed_buffer_ids,
20137            } => {
20138                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20139                let buffer = self.buffer.read(cx);
20140                self.registered_buffers
20141                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20142                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20143                cx.emit(EditorEvent::ExcerptsRemoved {
20144                    ids: ids.clone(),
20145                    removed_buffer_ids: removed_buffer_ids.clone(),
20146                });
20147            }
20148            multi_buffer::Event::ExcerptsEdited {
20149                excerpt_ids,
20150                buffer_ids,
20151            } => {
20152                self.display_map.update(cx, |map, cx| {
20153                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20154                });
20155                cx.emit(EditorEvent::ExcerptsEdited {
20156                    ids: excerpt_ids.clone(),
20157                });
20158            }
20159            multi_buffer::Event::ExcerptsExpanded { ids } => {
20160                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20161                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20162            }
20163            multi_buffer::Event::Reparsed(buffer_id) => {
20164                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20165                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20166
20167                cx.emit(EditorEvent::Reparsed(*buffer_id));
20168            }
20169            multi_buffer::Event::DiffHunksToggled => {
20170                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20171            }
20172            multi_buffer::Event::LanguageChanged(buffer_id) => {
20173                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20174                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20175                cx.emit(EditorEvent::Reparsed(*buffer_id));
20176                cx.notify();
20177            }
20178            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20179            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20180            multi_buffer::Event::FileHandleChanged
20181            | multi_buffer::Event::Reloaded
20182            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20183            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20184            multi_buffer::Event::DiagnosticsUpdated => {
20185                self.update_diagnostics_state(window, cx);
20186            }
20187            _ => {}
20188        };
20189    }
20190
20191    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20192        if !self.diagnostics_enabled() {
20193            return;
20194        }
20195        self.refresh_active_diagnostics(cx);
20196        self.refresh_inline_diagnostics(true, window, cx);
20197        self.scrollbar_marker_state.dirty = true;
20198        cx.notify();
20199    }
20200
20201    pub fn start_temporary_diff_override(&mut self) {
20202        self.load_diff_task.take();
20203        self.temporary_diff_override = true;
20204    }
20205
20206    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20207        self.temporary_diff_override = false;
20208        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20209        self.buffer.update(cx, |buffer, cx| {
20210            buffer.set_all_diff_hunks_collapsed(cx);
20211        });
20212
20213        if let Some(project) = self.project.clone() {
20214            self.load_diff_task = Some(
20215                update_uncommitted_diff_for_buffer(
20216                    cx.entity(),
20217                    &project,
20218                    self.buffer.read(cx).all_buffers(),
20219                    self.buffer.clone(),
20220                    cx,
20221                )
20222                .shared(),
20223            );
20224        }
20225    }
20226
20227    fn on_display_map_changed(
20228        &mut self,
20229        _: Entity<DisplayMap>,
20230        _: &mut Window,
20231        cx: &mut Context<Self>,
20232    ) {
20233        cx.notify();
20234    }
20235
20236    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20237        if self.diagnostics_enabled() {
20238            let new_severity = EditorSettings::get_global(cx)
20239                .diagnostics_max_severity
20240                .unwrap_or(DiagnosticSeverity::Hint);
20241            self.set_max_diagnostics_severity(new_severity, cx);
20242        }
20243        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20244        self.update_edit_prediction_settings(cx);
20245        self.refresh_edit_prediction(true, false, window, cx);
20246        self.refresh_inline_values(cx);
20247        self.refresh_inlay_hints(
20248            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20249                self.selections.newest_anchor().head(),
20250                &self.buffer.read(cx).snapshot(cx),
20251                cx,
20252            )),
20253            cx,
20254        );
20255
20256        let old_cursor_shape = self.cursor_shape;
20257        let old_show_breadcrumbs = self.show_breadcrumbs;
20258
20259        {
20260            let editor_settings = EditorSettings::get_global(cx);
20261            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20262            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20263            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20264            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20265        }
20266
20267        if old_cursor_shape != self.cursor_shape {
20268            cx.emit(EditorEvent::CursorShapeChanged);
20269        }
20270
20271        if old_show_breadcrumbs != self.show_breadcrumbs {
20272            cx.emit(EditorEvent::BreadcrumbsChanged);
20273        }
20274
20275        let project_settings = ProjectSettings::get_global(cx);
20276        self.serialize_dirty_buffers =
20277            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20278
20279        if self.mode.is_full() {
20280            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20281            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20282            if self.show_inline_diagnostics != show_inline_diagnostics {
20283                self.show_inline_diagnostics = show_inline_diagnostics;
20284                self.refresh_inline_diagnostics(false, window, cx);
20285            }
20286
20287            if self.git_blame_inline_enabled != inline_blame_enabled {
20288                self.toggle_git_blame_inline_internal(false, window, cx);
20289            }
20290
20291            let minimap_settings = EditorSettings::get_global(cx).minimap;
20292            if self.minimap_visibility != MinimapVisibility::Disabled {
20293                if self.minimap_visibility.settings_visibility()
20294                    != minimap_settings.minimap_enabled()
20295                {
20296                    self.set_minimap_visibility(
20297                        MinimapVisibility::for_mode(self.mode(), cx),
20298                        window,
20299                        cx,
20300                    );
20301                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20302                    minimap_entity.update(cx, |minimap_editor, cx| {
20303                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20304                    })
20305                }
20306            }
20307        }
20308
20309        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20310            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20311        }) {
20312            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20313                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20314            }
20315            self.refresh_colors(false, None, window, cx);
20316        }
20317
20318        cx.notify();
20319    }
20320
20321    pub fn set_searchable(&mut self, searchable: bool) {
20322        self.searchable = searchable;
20323    }
20324
20325    pub fn searchable(&self) -> bool {
20326        self.searchable
20327    }
20328
20329    fn open_proposed_changes_editor(
20330        &mut self,
20331        _: &OpenProposedChangesEditor,
20332        window: &mut Window,
20333        cx: &mut Context<Self>,
20334    ) {
20335        let Some(workspace) = self.workspace() else {
20336            cx.propagate();
20337            return;
20338        };
20339
20340        let selections = self.selections.all::<usize>(cx);
20341        let multi_buffer = self.buffer.read(cx);
20342        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20343        let mut new_selections_by_buffer = HashMap::default();
20344        for selection in selections {
20345            for (buffer, range, _) in
20346                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20347            {
20348                let mut range = range.to_point(buffer);
20349                range.start.column = 0;
20350                range.end.column = buffer.line_len(range.end.row);
20351                new_selections_by_buffer
20352                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20353                    .or_insert(Vec::new())
20354                    .push(range)
20355            }
20356        }
20357
20358        let proposed_changes_buffers = new_selections_by_buffer
20359            .into_iter()
20360            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20361            .collect::<Vec<_>>();
20362        let proposed_changes_editor = cx.new(|cx| {
20363            ProposedChangesEditor::new(
20364                "Proposed changes",
20365                proposed_changes_buffers,
20366                self.project.clone(),
20367                window,
20368                cx,
20369            )
20370        });
20371
20372        window.defer(cx, move |window, cx| {
20373            workspace.update(cx, |workspace, cx| {
20374                workspace.active_pane().update(cx, |pane, cx| {
20375                    pane.add_item(
20376                        Box::new(proposed_changes_editor),
20377                        true,
20378                        true,
20379                        None,
20380                        window,
20381                        cx,
20382                    );
20383                });
20384            });
20385        });
20386    }
20387
20388    pub fn open_excerpts_in_split(
20389        &mut self,
20390        _: &OpenExcerptsSplit,
20391        window: &mut Window,
20392        cx: &mut Context<Self>,
20393    ) {
20394        self.open_excerpts_common(None, true, window, cx)
20395    }
20396
20397    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20398        self.open_excerpts_common(None, false, window, cx)
20399    }
20400
20401    fn open_excerpts_common(
20402        &mut self,
20403        jump_data: Option<JumpData>,
20404        split: bool,
20405        window: &mut Window,
20406        cx: &mut Context<Self>,
20407    ) {
20408        let Some(workspace) = self.workspace() else {
20409            cx.propagate();
20410            return;
20411        };
20412
20413        if self.buffer.read(cx).is_singleton() {
20414            cx.propagate();
20415            return;
20416        }
20417
20418        let mut new_selections_by_buffer = HashMap::default();
20419        match &jump_data {
20420            Some(JumpData::MultiBufferPoint {
20421                excerpt_id,
20422                position,
20423                anchor,
20424                line_offset_from_top,
20425            }) => {
20426                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20427                if let Some(buffer) = multi_buffer_snapshot
20428                    .buffer_id_for_excerpt(*excerpt_id)
20429                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20430                {
20431                    let buffer_snapshot = buffer.read(cx).snapshot();
20432                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20433                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20434                    } else {
20435                        buffer_snapshot.clip_point(*position, Bias::Left)
20436                    };
20437                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20438                    new_selections_by_buffer.insert(
20439                        buffer,
20440                        (
20441                            vec![jump_to_offset..jump_to_offset],
20442                            Some(*line_offset_from_top),
20443                        ),
20444                    );
20445                }
20446            }
20447            Some(JumpData::MultiBufferRow {
20448                row,
20449                line_offset_from_top,
20450            }) => {
20451                let point = MultiBufferPoint::new(row.0, 0);
20452                if let Some((buffer, buffer_point, _)) =
20453                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20454                {
20455                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20456                    new_selections_by_buffer
20457                        .entry(buffer)
20458                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20459                        .0
20460                        .push(buffer_offset..buffer_offset)
20461                }
20462            }
20463            None => {
20464                let selections = self.selections.all::<usize>(cx);
20465                let multi_buffer = self.buffer.read(cx);
20466                for selection in selections {
20467                    for (snapshot, range, _, anchor) in multi_buffer
20468                        .snapshot(cx)
20469                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20470                    {
20471                        if let Some(anchor) = anchor {
20472                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20473                            else {
20474                                continue;
20475                            };
20476                            let offset = text::ToOffset::to_offset(
20477                                &anchor.text_anchor,
20478                                &buffer_handle.read(cx).snapshot(),
20479                            );
20480                            let range = offset..offset;
20481                            new_selections_by_buffer
20482                                .entry(buffer_handle)
20483                                .or_insert((Vec::new(), None))
20484                                .0
20485                                .push(range)
20486                        } else {
20487                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20488                            else {
20489                                continue;
20490                            };
20491                            new_selections_by_buffer
20492                                .entry(buffer_handle)
20493                                .or_insert((Vec::new(), None))
20494                                .0
20495                                .push(range)
20496                        }
20497                    }
20498                }
20499            }
20500        }
20501
20502        new_selections_by_buffer
20503            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20504
20505        if new_selections_by_buffer.is_empty() {
20506            return;
20507        }
20508
20509        // We defer the pane interaction because we ourselves are a workspace item
20510        // and activating a new item causes the pane to call a method on us reentrantly,
20511        // which panics if we're on the stack.
20512        window.defer(cx, move |window, cx| {
20513            workspace.update(cx, |workspace, cx| {
20514                let pane = if split {
20515                    workspace.adjacent_pane(window, cx)
20516                } else {
20517                    workspace.active_pane().clone()
20518                };
20519
20520                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20521                    let editor = buffer
20522                        .read(cx)
20523                        .file()
20524                        .is_none()
20525                        .then(|| {
20526                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20527                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20528                            // Instead, we try to activate the existing editor in the pane first.
20529                            let (editor, pane_item_index) =
20530                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20531                                    let editor = item.downcast::<Editor>()?;
20532                                    let singleton_buffer =
20533                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20534                                    if singleton_buffer == buffer {
20535                                        Some((editor, i))
20536                                    } else {
20537                                        None
20538                                    }
20539                                })?;
20540                            pane.update(cx, |pane, cx| {
20541                                pane.activate_item(pane_item_index, true, true, window, cx)
20542                            });
20543                            Some(editor)
20544                        })
20545                        .flatten()
20546                        .unwrap_or_else(|| {
20547                            workspace.open_project_item::<Self>(
20548                                pane.clone(),
20549                                buffer,
20550                                true,
20551                                true,
20552                                window,
20553                                cx,
20554                            )
20555                        });
20556
20557                    editor.update(cx, |editor, cx| {
20558                        let autoscroll = match scroll_offset {
20559                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20560                            None => Autoscroll::newest(),
20561                        };
20562                        let nav_history = editor.nav_history.take();
20563                        editor.change_selections(
20564                            SelectionEffects::scroll(autoscroll),
20565                            window,
20566                            cx,
20567                            |s| {
20568                                s.select_ranges(ranges);
20569                            },
20570                        );
20571                        editor.nav_history = nav_history;
20572                    });
20573                }
20574            })
20575        });
20576    }
20577
20578    // For now, don't allow opening excerpts in buffers that aren't backed by
20579    // regular project files.
20580    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20581        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20582    }
20583
20584    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20585        let snapshot = self.buffer.read(cx).read(cx);
20586        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20587        Some(
20588            ranges
20589                .iter()
20590                .map(move |range| {
20591                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20592                })
20593                .collect(),
20594        )
20595    }
20596
20597    fn selection_replacement_ranges(
20598        &self,
20599        range: Range<OffsetUtf16>,
20600        cx: &mut App,
20601    ) -> Vec<Range<OffsetUtf16>> {
20602        let selections = self.selections.all::<OffsetUtf16>(cx);
20603        let newest_selection = selections
20604            .iter()
20605            .max_by_key(|selection| selection.id)
20606            .unwrap();
20607        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20608        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20609        let snapshot = self.buffer.read(cx).read(cx);
20610        selections
20611            .into_iter()
20612            .map(|mut selection| {
20613                selection.start.0 =
20614                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20615                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20616                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20617                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20618            })
20619            .collect()
20620    }
20621
20622    fn report_editor_event(
20623        &self,
20624        reported_event: ReportEditorEvent,
20625        file_extension: Option<String>,
20626        cx: &App,
20627    ) {
20628        if cfg!(any(test, feature = "test-support")) {
20629            return;
20630        }
20631
20632        let Some(project) = &self.project else { return };
20633
20634        // If None, we are in a file without an extension
20635        let file = self
20636            .buffer
20637            .read(cx)
20638            .as_singleton()
20639            .and_then(|b| b.read(cx).file());
20640        let file_extension = file_extension.or(file
20641            .as_ref()
20642            .and_then(|file| Path::new(file.file_name(cx)).extension())
20643            .and_then(|e| e.to_str())
20644            .map(|a| a.to_string()));
20645
20646        let vim_mode = vim_enabled(cx);
20647
20648        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20649        let copilot_enabled = edit_predictions_provider
20650            == language::language_settings::EditPredictionProvider::Copilot;
20651        let copilot_enabled_for_language = self
20652            .buffer
20653            .read(cx)
20654            .language_settings(cx)
20655            .show_edit_predictions;
20656
20657        let project = project.read(cx);
20658        let event_type = reported_event.event_type();
20659
20660        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20661            telemetry::event!(
20662                event_type,
20663                type = if auto_saved {"autosave"} else {"manual"},
20664                file_extension,
20665                vim_mode,
20666                copilot_enabled,
20667                copilot_enabled_for_language,
20668                edit_predictions_provider,
20669                is_via_ssh = project.is_via_ssh(),
20670            );
20671        } else {
20672            telemetry::event!(
20673                event_type,
20674                file_extension,
20675                vim_mode,
20676                copilot_enabled,
20677                copilot_enabled_for_language,
20678                edit_predictions_provider,
20679                is_via_ssh = project.is_via_ssh(),
20680            );
20681        };
20682    }
20683
20684    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20685    /// with each line being an array of {text, highlight} objects.
20686    fn copy_highlight_json(
20687        &mut self,
20688        _: &CopyHighlightJson,
20689        window: &mut Window,
20690        cx: &mut Context<Self>,
20691    ) {
20692        #[derive(Serialize)]
20693        struct Chunk<'a> {
20694            text: String,
20695            highlight: Option<&'a str>,
20696        }
20697
20698        let snapshot = self.buffer.read(cx).snapshot(cx);
20699        let range = self
20700            .selected_text_range(false, window, cx)
20701            .and_then(|selection| {
20702                if selection.range.is_empty() {
20703                    None
20704                } else {
20705                    Some(selection.range)
20706                }
20707            })
20708            .unwrap_or_else(|| 0..snapshot.len());
20709
20710        let chunks = snapshot.chunks(range, true);
20711        let mut lines = Vec::new();
20712        let mut line: VecDeque<Chunk> = VecDeque::new();
20713
20714        let Some(style) = self.style.as_ref() else {
20715            return;
20716        };
20717
20718        for chunk in chunks {
20719            let highlight = chunk
20720                .syntax_highlight_id
20721                .and_then(|id| id.name(&style.syntax));
20722            let mut chunk_lines = chunk.text.split('\n').peekable();
20723            while let Some(text) = chunk_lines.next() {
20724                let mut merged_with_last_token = false;
20725                if let Some(last_token) = line.back_mut()
20726                    && last_token.highlight == highlight
20727                {
20728                    last_token.text.push_str(text);
20729                    merged_with_last_token = true;
20730                }
20731
20732                if !merged_with_last_token {
20733                    line.push_back(Chunk {
20734                        text: text.into(),
20735                        highlight,
20736                    });
20737                }
20738
20739                if chunk_lines.peek().is_some() {
20740                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20741                        line.pop_front();
20742                    }
20743                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20744                        line.pop_back();
20745                    }
20746
20747                    lines.push(mem::take(&mut line));
20748                }
20749            }
20750        }
20751
20752        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20753            return;
20754        };
20755        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20756    }
20757
20758    pub fn open_context_menu(
20759        &mut self,
20760        _: &OpenContextMenu,
20761        window: &mut Window,
20762        cx: &mut Context<Self>,
20763    ) {
20764        self.request_autoscroll(Autoscroll::newest(), cx);
20765        let position = self.selections.newest_display(cx).start;
20766        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20767    }
20768
20769    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20770        &self.inlay_hint_cache
20771    }
20772
20773    pub fn replay_insert_event(
20774        &mut self,
20775        text: &str,
20776        relative_utf16_range: Option<Range<isize>>,
20777        window: &mut Window,
20778        cx: &mut Context<Self>,
20779    ) {
20780        if !self.input_enabled {
20781            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20782            return;
20783        }
20784        if let Some(relative_utf16_range) = relative_utf16_range {
20785            let selections = self.selections.all::<OffsetUtf16>(cx);
20786            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20787                let new_ranges = selections.into_iter().map(|range| {
20788                    let start = OffsetUtf16(
20789                        range
20790                            .head()
20791                            .0
20792                            .saturating_add_signed(relative_utf16_range.start),
20793                    );
20794                    let end = OffsetUtf16(
20795                        range
20796                            .head()
20797                            .0
20798                            .saturating_add_signed(relative_utf16_range.end),
20799                    );
20800                    start..end
20801                });
20802                s.select_ranges(new_ranges);
20803            });
20804        }
20805
20806        self.handle_input(text, window, cx);
20807    }
20808
20809    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20810        let Some(provider) = self.semantics_provider.as_ref() else {
20811            return false;
20812        };
20813
20814        let mut supports = false;
20815        self.buffer().update(cx, |this, cx| {
20816            this.for_each_buffer(|buffer| {
20817                supports |= provider.supports_inlay_hints(buffer, cx);
20818            });
20819        });
20820
20821        supports
20822    }
20823
20824    pub fn is_focused(&self, window: &Window) -> bool {
20825        self.focus_handle.is_focused(window)
20826    }
20827
20828    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20829        cx.emit(EditorEvent::Focused);
20830
20831        if let Some(descendant) = self
20832            .last_focused_descendant
20833            .take()
20834            .and_then(|descendant| descendant.upgrade())
20835        {
20836            window.focus(&descendant);
20837        } else {
20838            if let Some(blame) = self.blame.as_ref() {
20839                blame.update(cx, GitBlame::focus)
20840            }
20841
20842            self.blink_manager.update(cx, BlinkManager::enable);
20843            self.show_cursor_names(window, cx);
20844            self.buffer.update(cx, |buffer, cx| {
20845                buffer.finalize_last_transaction(cx);
20846                if self.leader_id.is_none() {
20847                    buffer.set_active_selections(
20848                        &self.selections.disjoint_anchors(),
20849                        self.selections.line_mode,
20850                        self.cursor_shape,
20851                        cx,
20852                    );
20853                }
20854            });
20855        }
20856    }
20857
20858    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20859        cx.emit(EditorEvent::FocusedIn)
20860    }
20861
20862    fn handle_focus_out(
20863        &mut self,
20864        event: FocusOutEvent,
20865        _window: &mut Window,
20866        cx: &mut Context<Self>,
20867    ) {
20868        if event.blurred != self.focus_handle {
20869            self.last_focused_descendant = Some(event.blurred);
20870        }
20871        self.selection_drag_state = SelectionDragState::None;
20872        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20873    }
20874
20875    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20876        self.blink_manager.update(cx, BlinkManager::disable);
20877        self.buffer
20878            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20879
20880        if let Some(blame) = self.blame.as_ref() {
20881            blame.update(cx, GitBlame::blur)
20882        }
20883        if !self.hover_state.focused(window, cx) {
20884            hide_hover(self, cx);
20885        }
20886        if !self
20887            .context_menu
20888            .borrow()
20889            .as_ref()
20890            .is_some_and(|context_menu| context_menu.focused(window, cx))
20891        {
20892            self.hide_context_menu(window, cx);
20893        }
20894        self.discard_edit_prediction(false, cx);
20895        cx.emit(EditorEvent::Blurred);
20896        cx.notify();
20897    }
20898
20899    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20900        let mut pending: String = window
20901            .pending_input_keystrokes()
20902            .into_iter()
20903            .flatten()
20904            .filter_map(|keystroke| {
20905                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20906                    keystroke.key_char.clone()
20907                } else {
20908                    None
20909                }
20910            })
20911            .collect();
20912
20913        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20914            pending = "".to_string();
20915        }
20916
20917        let existing_pending = self
20918            .text_highlights::<PendingInput>(cx)
20919            .map(|(_, ranges)| ranges.to_vec());
20920        if existing_pending.is_none() && pending.is_empty() {
20921            return;
20922        }
20923        let transaction =
20924            self.transact(window, cx, |this, window, cx| {
20925                let selections = this.selections.all::<usize>(cx);
20926                let edits = selections
20927                    .iter()
20928                    .map(|selection| (selection.end..selection.end, pending.clone()));
20929                this.edit(edits, cx);
20930                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20931                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20932                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20933                    }));
20934                });
20935                if let Some(existing_ranges) = existing_pending {
20936                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20937                    this.edit(edits, cx);
20938                }
20939            });
20940
20941        let snapshot = self.snapshot(window, cx);
20942        let ranges = self
20943            .selections
20944            .all::<usize>(cx)
20945            .into_iter()
20946            .map(|selection| {
20947                snapshot.buffer_snapshot.anchor_after(selection.end)
20948                    ..snapshot
20949                        .buffer_snapshot
20950                        .anchor_before(selection.end + pending.len())
20951            })
20952            .collect();
20953
20954        if pending.is_empty() {
20955            self.clear_highlights::<PendingInput>(cx);
20956        } else {
20957            self.highlight_text::<PendingInput>(
20958                ranges,
20959                HighlightStyle {
20960                    underline: Some(UnderlineStyle {
20961                        thickness: px(1.),
20962                        color: None,
20963                        wavy: false,
20964                    }),
20965                    ..Default::default()
20966                },
20967                cx,
20968            );
20969        }
20970
20971        self.ime_transaction = self.ime_transaction.or(transaction);
20972        if let Some(transaction) = self.ime_transaction {
20973            self.buffer.update(cx, |buffer, cx| {
20974                buffer.group_until_transaction(transaction, cx);
20975            });
20976        }
20977
20978        if self.text_highlights::<PendingInput>(cx).is_none() {
20979            self.ime_transaction.take();
20980        }
20981    }
20982
20983    pub fn register_action_renderer(
20984        &mut self,
20985        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20986    ) -> Subscription {
20987        let id = self.next_editor_action_id.post_inc();
20988        self.editor_actions
20989            .borrow_mut()
20990            .insert(id, Box::new(listener));
20991
20992        let editor_actions = self.editor_actions.clone();
20993        Subscription::new(move || {
20994            editor_actions.borrow_mut().remove(&id);
20995        })
20996    }
20997
20998    pub fn register_action<A: Action>(
20999        &mut self,
21000        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21001    ) -> Subscription {
21002        let id = self.next_editor_action_id.post_inc();
21003        let listener = Arc::new(listener);
21004        self.editor_actions.borrow_mut().insert(
21005            id,
21006            Box::new(move |_, window, _| {
21007                let listener = listener.clone();
21008                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21009                    let action = action.downcast_ref().unwrap();
21010                    if phase == DispatchPhase::Bubble {
21011                        listener(action, window, cx)
21012                    }
21013                })
21014            }),
21015        );
21016
21017        let editor_actions = self.editor_actions.clone();
21018        Subscription::new(move || {
21019            editor_actions.borrow_mut().remove(&id);
21020        })
21021    }
21022
21023    pub fn file_header_size(&self) -> u32 {
21024        FILE_HEADER_HEIGHT
21025    }
21026
21027    pub fn restore(
21028        &mut self,
21029        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21030        window: &mut Window,
21031        cx: &mut Context<Self>,
21032    ) {
21033        let workspace = self.workspace();
21034        let project = self.project();
21035        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21036            let mut tasks = Vec::new();
21037            for (buffer_id, changes) in revert_changes {
21038                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21039                    buffer.update(cx, |buffer, cx| {
21040                        buffer.edit(
21041                            changes
21042                                .into_iter()
21043                                .map(|(range, text)| (range, text.to_string())),
21044                            None,
21045                            cx,
21046                        );
21047                    });
21048
21049                    if let Some(project) =
21050                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21051                    {
21052                        project.update(cx, |project, cx| {
21053                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21054                        })
21055                    }
21056                }
21057            }
21058            tasks
21059        });
21060        cx.spawn_in(window, async move |_, cx| {
21061            for (buffer, task) in save_tasks {
21062                let result = task.await;
21063                if result.is_err() {
21064                    let Some(path) = buffer
21065                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21066                        .ok()
21067                    else {
21068                        continue;
21069                    };
21070                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21071                        let Some(task) = cx
21072                            .update_window_entity(workspace, |workspace, window, cx| {
21073                                workspace
21074                                    .open_path_preview(path, None, false, false, false, window, cx)
21075                            })
21076                            .ok()
21077                        else {
21078                            continue;
21079                        };
21080                        task.await.log_err();
21081                    }
21082                }
21083            }
21084        })
21085        .detach();
21086        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21087            selections.refresh()
21088        });
21089    }
21090
21091    pub fn to_pixel_point(
21092        &self,
21093        source: multi_buffer::Anchor,
21094        editor_snapshot: &EditorSnapshot,
21095        window: &mut Window,
21096    ) -> Option<gpui::Point<Pixels>> {
21097        let source_point = source.to_display_point(editor_snapshot);
21098        self.display_to_pixel_point(source_point, editor_snapshot, window)
21099    }
21100
21101    pub fn display_to_pixel_point(
21102        &self,
21103        source: DisplayPoint,
21104        editor_snapshot: &EditorSnapshot,
21105        window: &mut Window,
21106    ) -> Option<gpui::Point<Pixels>> {
21107        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21108        let text_layout_details = self.text_layout_details(window);
21109        let scroll_top = text_layout_details
21110            .scroll_anchor
21111            .scroll_position(editor_snapshot)
21112            .y;
21113
21114        if source.row().as_f32() < scroll_top.floor() {
21115            return None;
21116        }
21117        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21118        let source_y = line_height * (source.row().as_f32() - scroll_top);
21119        Some(gpui::Point::new(source_x, source_y))
21120    }
21121
21122    pub fn has_visible_completions_menu(&self) -> bool {
21123        !self.edit_prediction_preview_is_active()
21124            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21125                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21126            })
21127    }
21128
21129    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21130        if self.mode.is_minimap() {
21131            return;
21132        }
21133        self.addons
21134            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21135    }
21136
21137    pub fn unregister_addon<T: Addon>(&mut self) {
21138        self.addons.remove(&std::any::TypeId::of::<T>());
21139    }
21140
21141    pub fn addon<T: Addon>(&self) -> Option<&T> {
21142        let type_id = std::any::TypeId::of::<T>();
21143        self.addons
21144            .get(&type_id)
21145            .and_then(|item| item.to_any().downcast_ref::<T>())
21146    }
21147
21148    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21149        let type_id = std::any::TypeId::of::<T>();
21150        self.addons
21151            .get_mut(&type_id)
21152            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21153    }
21154
21155    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21156        let text_layout_details = self.text_layout_details(window);
21157        let style = &text_layout_details.editor_style;
21158        let font_id = window.text_system().resolve_font(&style.text.font());
21159        let font_size = style.text.font_size.to_pixels(window.rem_size());
21160        let line_height = style.text.line_height_in_pixels(window.rem_size());
21161        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21162        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21163
21164        CharacterDimensions {
21165            em_width,
21166            em_advance,
21167            line_height,
21168        }
21169    }
21170
21171    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21172        self.load_diff_task.clone()
21173    }
21174
21175    fn read_metadata_from_db(
21176        &mut self,
21177        item_id: u64,
21178        workspace_id: WorkspaceId,
21179        window: &mut Window,
21180        cx: &mut Context<Editor>,
21181    ) {
21182        if self.is_singleton(cx)
21183            && !self.mode.is_minimap()
21184            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21185        {
21186            let buffer_snapshot = OnceCell::new();
21187
21188            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21189                && !folds.is_empty()
21190            {
21191                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21192                self.fold_ranges(
21193                    folds
21194                        .into_iter()
21195                        .map(|(start, end)| {
21196                            snapshot.clip_offset(start, Bias::Left)
21197                                ..snapshot.clip_offset(end, Bias::Right)
21198                        })
21199                        .collect(),
21200                    false,
21201                    window,
21202                    cx,
21203                );
21204            }
21205
21206            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21207                && !selections.is_empty()
21208            {
21209                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21210                // skip adding the initial selection to selection history
21211                self.selection_history.mode = SelectionHistoryMode::Skipping;
21212                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21213                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21214                        snapshot.clip_offset(start, Bias::Left)
21215                            ..snapshot.clip_offset(end, Bias::Right)
21216                    }));
21217                });
21218                self.selection_history.mode = SelectionHistoryMode::Normal;
21219            };
21220        }
21221
21222        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21223    }
21224
21225    fn update_lsp_data(
21226        &mut self,
21227        ignore_cache: bool,
21228        for_buffer: Option<BufferId>,
21229        window: &mut Window,
21230        cx: &mut Context<'_, Self>,
21231    ) {
21232        self.pull_diagnostics(for_buffer, window, cx);
21233        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21234    }
21235}
21236
21237fn vim_enabled(cx: &App) -> bool {
21238    cx.global::<SettingsStore>()
21239        .raw_user_settings()
21240        .get("vim_mode")
21241        == Some(&serde_json::Value::Bool(true))
21242}
21243
21244fn process_completion_for_edit(
21245    completion: &Completion,
21246    intent: CompletionIntent,
21247    buffer: &Entity<Buffer>,
21248    cursor_position: &text::Anchor,
21249    cx: &mut Context<Editor>,
21250) -> CompletionEdit {
21251    let buffer = buffer.read(cx);
21252    let buffer_snapshot = buffer.snapshot();
21253    let (snippet, new_text) = if completion.is_snippet() {
21254        // Workaround for typescript language server issues so that methods don't expand within
21255        // strings and functions with type expressions. The previous point is used because the query
21256        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21257        let mut snippet_source = completion.new_text.clone();
21258        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21259        previous_point.column = previous_point.column.saturating_sub(1);
21260        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21261            && scope.prefers_label_for_snippet_in_completion()
21262            && let Some(label) = completion.label()
21263            && matches!(
21264                completion.kind(),
21265                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21266            )
21267        {
21268            snippet_source = label;
21269        }
21270        match Snippet::parse(&snippet_source).log_err() {
21271            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21272            None => (None, completion.new_text.clone()),
21273        }
21274    } else {
21275        (None, completion.new_text.clone())
21276    };
21277
21278    let mut range_to_replace = {
21279        let replace_range = &completion.replace_range;
21280        if let CompletionSource::Lsp {
21281            insert_range: Some(insert_range),
21282            ..
21283        } = &completion.source
21284        {
21285            debug_assert_eq!(
21286                insert_range.start, replace_range.start,
21287                "insert_range and replace_range should start at the same position"
21288            );
21289            debug_assert!(
21290                insert_range
21291                    .start
21292                    .cmp(cursor_position, &buffer_snapshot)
21293                    .is_le(),
21294                "insert_range should start before or at cursor position"
21295            );
21296            debug_assert!(
21297                replace_range
21298                    .start
21299                    .cmp(cursor_position, &buffer_snapshot)
21300                    .is_le(),
21301                "replace_range should start before or at cursor position"
21302            );
21303
21304            let should_replace = match intent {
21305                CompletionIntent::CompleteWithInsert => false,
21306                CompletionIntent::CompleteWithReplace => true,
21307                CompletionIntent::Complete | CompletionIntent::Compose => {
21308                    let insert_mode =
21309                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21310                            .completions
21311                            .lsp_insert_mode;
21312                    match insert_mode {
21313                        LspInsertMode::Insert => false,
21314                        LspInsertMode::Replace => true,
21315                        LspInsertMode::ReplaceSubsequence => {
21316                            let mut text_to_replace = buffer.chars_for_range(
21317                                buffer.anchor_before(replace_range.start)
21318                                    ..buffer.anchor_after(replace_range.end),
21319                            );
21320                            let mut current_needle = text_to_replace.next();
21321                            for haystack_ch in completion.label.text.chars() {
21322                                if let Some(needle_ch) = current_needle
21323                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21324                                {
21325                                    current_needle = text_to_replace.next();
21326                                }
21327                            }
21328                            current_needle.is_none()
21329                        }
21330                        LspInsertMode::ReplaceSuffix => {
21331                            if replace_range
21332                                .end
21333                                .cmp(cursor_position, &buffer_snapshot)
21334                                .is_gt()
21335                            {
21336                                let range_after_cursor = *cursor_position..replace_range.end;
21337                                let text_after_cursor = buffer
21338                                    .text_for_range(
21339                                        buffer.anchor_before(range_after_cursor.start)
21340                                            ..buffer.anchor_after(range_after_cursor.end),
21341                                    )
21342                                    .collect::<String>()
21343                                    .to_ascii_lowercase();
21344                                completion
21345                                    .label
21346                                    .text
21347                                    .to_ascii_lowercase()
21348                                    .ends_with(&text_after_cursor)
21349                            } else {
21350                                true
21351                            }
21352                        }
21353                    }
21354                }
21355            };
21356
21357            if should_replace {
21358                replace_range.clone()
21359            } else {
21360                insert_range.clone()
21361            }
21362        } else {
21363            replace_range.clone()
21364        }
21365    };
21366
21367    if range_to_replace
21368        .end
21369        .cmp(cursor_position, &buffer_snapshot)
21370        .is_lt()
21371    {
21372        range_to_replace.end = *cursor_position;
21373    }
21374
21375    CompletionEdit {
21376        new_text,
21377        replace_range: range_to_replace.to_offset(buffer),
21378        snippet,
21379    }
21380}
21381
21382struct CompletionEdit {
21383    new_text: String,
21384    replace_range: Range<usize>,
21385    snippet: Option<Snippet>,
21386}
21387
21388fn insert_extra_newline_brackets(
21389    buffer: &MultiBufferSnapshot,
21390    range: Range<usize>,
21391    language: &language::LanguageScope,
21392) -> bool {
21393    let leading_whitespace_len = buffer
21394        .reversed_chars_at(range.start)
21395        .take_while(|c| c.is_whitespace() && *c != '\n')
21396        .map(|c| c.len_utf8())
21397        .sum::<usize>();
21398    let trailing_whitespace_len = buffer
21399        .chars_at(range.end)
21400        .take_while(|c| c.is_whitespace() && *c != '\n')
21401        .map(|c| c.len_utf8())
21402        .sum::<usize>();
21403    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21404
21405    language.brackets().any(|(pair, enabled)| {
21406        let pair_start = pair.start.trim_end();
21407        let pair_end = pair.end.trim_start();
21408
21409        enabled
21410            && pair.newline
21411            && buffer.contains_str_at(range.end, pair_end)
21412            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21413    })
21414}
21415
21416fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21417    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21418        [(buffer, range, _)] => (*buffer, range.clone()),
21419        _ => return false,
21420    };
21421    let pair = {
21422        let mut result: Option<BracketMatch> = None;
21423
21424        for pair in buffer
21425            .all_bracket_ranges(range.clone())
21426            .filter(move |pair| {
21427                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21428            })
21429        {
21430            let len = pair.close_range.end - pair.open_range.start;
21431
21432            if let Some(existing) = &result {
21433                let existing_len = existing.close_range.end - existing.open_range.start;
21434                if len > existing_len {
21435                    continue;
21436                }
21437            }
21438
21439            result = Some(pair);
21440        }
21441
21442        result
21443    };
21444    let Some(pair) = pair else {
21445        return false;
21446    };
21447    pair.newline_only
21448        && buffer
21449            .chars_for_range(pair.open_range.end..range.start)
21450            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21451            .all(|c| c.is_whitespace() && c != '\n')
21452}
21453
21454fn update_uncommitted_diff_for_buffer(
21455    editor: Entity<Editor>,
21456    project: &Entity<Project>,
21457    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21458    buffer: Entity<MultiBuffer>,
21459    cx: &mut App,
21460) -> Task<()> {
21461    let mut tasks = Vec::new();
21462    project.update(cx, |project, cx| {
21463        for buffer in buffers {
21464            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21465                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21466            }
21467        }
21468    });
21469    cx.spawn(async move |cx| {
21470        let diffs = future::join_all(tasks).await;
21471        if editor
21472            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21473            .unwrap_or(false)
21474        {
21475            return;
21476        }
21477
21478        buffer
21479            .update(cx, |buffer, cx| {
21480                for diff in diffs.into_iter().flatten() {
21481                    buffer.add_diff(diff, cx);
21482                }
21483            })
21484            .ok();
21485    })
21486}
21487
21488fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21489    let tab_size = tab_size.get() as usize;
21490    let mut width = offset;
21491
21492    for ch in text.chars() {
21493        width += if ch == '\t' {
21494            tab_size - (width % tab_size)
21495        } else {
21496            1
21497        };
21498    }
21499
21500    width - offset
21501}
21502
21503#[cfg(test)]
21504mod tests {
21505    use super::*;
21506
21507    #[test]
21508    fn test_string_size_with_expanded_tabs() {
21509        let nz = |val| NonZeroU32::new(val).unwrap();
21510        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21511        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21512        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21513        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21514        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21515        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21516        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21517        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21518    }
21519}
21520
21521/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21522struct WordBreakingTokenizer<'a> {
21523    input: &'a str,
21524}
21525
21526impl<'a> WordBreakingTokenizer<'a> {
21527    fn new(input: &'a str) -> Self {
21528        Self { input }
21529    }
21530}
21531
21532fn is_char_ideographic(ch: char) -> bool {
21533    use unicode_script::Script::*;
21534    use unicode_script::UnicodeScript;
21535    matches!(ch.script(), Han | Tangut | Yi)
21536}
21537
21538fn is_grapheme_ideographic(text: &str) -> bool {
21539    text.chars().any(is_char_ideographic)
21540}
21541
21542fn is_grapheme_whitespace(text: &str) -> bool {
21543    text.chars().any(|x| x.is_whitespace())
21544}
21545
21546fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21547    text.chars()
21548        .next()
21549        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21550}
21551
21552#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21553enum WordBreakToken<'a> {
21554    Word { token: &'a str, grapheme_len: usize },
21555    InlineWhitespace { token: &'a str, grapheme_len: usize },
21556    Newline,
21557}
21558
21559impl<'a> Iterator for WordBreakingTokenizer<'a> {
21560    /// Yields a span, the count of graphemes in the token, and whether it was
21561    /// whitespace. Note that it also breaks at word boundaries.
21562    type Item = WordBreakToken<'a>;
21563
21564    fn next(&mut self) -> Option<Self::Item> {
21565        use unicode_segmentation::UnicodeSegmentation;
21566        if self.input.is_empty() {
21567            return None;
21568        }
21569
21570        let mut iter = self.input.graphemes(true).peekable();
21571        let mut offset = 0;
21572        let mut grapheme_len = 0;
21573        if let Some(first_grapheme) = iter.next() {
21574            let is_newline = first_grapheme == "\n";
21575            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21576            offset += first_grapheme.len();
21577            grapheme_len += 1;
21578            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21579                if let Some(grapheme) = iter.peek().copied()
21580                    && should_stay_with_preceding_ideograph(grapheme)
21581                {
21582                    offset += grapheme.len();
21583                    grapheme_len += 1;
21584                }
21585            } else {
21586                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21587                let mut next_word_bound = words.peek().copied();
21588                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21589                    next_word_bound = words.next();
21590                }
21591                while let Some(grapheme) = iter.peek().copied() {
21592                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21593                        break;
21594                    };
21595                    if is_grapheme_whitespace(grapheme) != is_whitespace
21596                        || (grapheme == "\n") != is_newline
21597                    {
21598                        break;
21599                    };
21600                    offset += grapheme.len();
21601                    grapheme_len += 1;
21602                    iter.next();
21603                }
21604            }
21605            let token = &self.input[..offset];
21606            self.input = &self.input[offset..];
21607            if token == "\n" {
21608                Some(WordBreakToken::Newline)
21609            } else if is_whitespace {
21610                Some(WordBreakToken::InlineWhitespace {
21611                    token,
21612                    grapheme_len,
21613                })
21614            } else {
21615                Some(WordBreakToken::Word {
21616                    token,
21617                    grapheme_len,
21618                })
21619            }
21620        } else {
21621            None
21622        }
21623    }
21624}
21625
21626#[test]
21627fn test_word_breaking_tokenizer() {
21628    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21629        ("", &[]),
21630        ("  ", &[whitespace("  ", 2)]),
21631        ("Ʒ", &[word("Ʒ", 1)]),
21632        ("Ǽ", &[word("Ǽ", 1)]),
21633        ("", &[word("", 1)]),
21634        ("⋑⋑", &[word("⋑⋑", 2)]),
21635        (
21636            "原理,进而",
21637            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21638        ),
21639        (
21640            "hello world",
21641            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21642        ),
21643        (
21644            "hello, world",
21645            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21646        ),
21647        (
21648            "  hello world",
21649            &[
21650                whitespace("  ", 2),
21651                word("hello", 5),
21652                whitespace(" ", 1),
21653                word("world", 5),
21654            ],
21655        ),
21656        (
21657            "这是什么 \n 钢笔",
21658            &[
21659                word("", 1),
21660                word("", 1),
21661                word("", 1),
21662                word("", 1),
21663                whitespace(" ", 1),
21664                newline(),
21665                whitespace(" ", 1),
21666                word("", 1),
21667                word("", 1),
21668            ],
21669        ),
21670        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21671    ];
21672
21673    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21674        WordBreakToken::Word {
21675            token,
21676            grapheme_len,
21677        }
21678    }
21679
21680    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21681        WordBreakToken::InlineWhitespace {
21682            token,
21683            grapheme_len,
21684        }
21685    }
21686
21687    fn newline() -> WordBreakToken<'static> {
21688        WordBreakToken::Newline
21689    }
21690
21691    for (input, result) in tests {
21692        assert_eq!(
21693            WordBreakingTokenizer::new(input)
21694                .collect::<Vec<_>>()
21695                .as_slice(),
21696            *result,
21697        );
21698    }
21699}
21700
21701fn wrap_with_prefix(
21702    first_line_prefix: String,
21703    subsequent_lines_prefix: String,
21704    unwrapped_text: String,
21705    wrap_column: usize,
21706    tab_size: NonZeroU32,
21707    preserve_existing_whitespace: bool,
21708) -> String {
21709    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21710    let subsequent_lines_prefix_len =
21711        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21712    let mut wrapped_text = String::new();
21713    let mut current_line = first_line_prefix;
21714    let mut is_first_line = true;
21715
21716    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21717    let mut current_line_len = first_line_prefix_len;
21718    let mut in_whitespace = false;
21719    for token in tokenizer {
21720        let have_preceding_whitespace = in_whitespace;
21721        match token {
21722            WordBreakToken::Word {
21723                token,
21724                grapheme_len,
21725            } => {
21726                in_whitespace = false;
21727                let current_prefix_len = if is_first_line {
21728                    first_line_prefix_len
21729                } else {
21730                    subsequent_lines_prefix_len
21731                };
21732                if current_line_len + grapheme_len > wrap_column
21733                    && current_line_len != current_prefix_len
21734                {
21735                    wrapped_text.push_str(current_line.trim_end());
21736                    wrapped_text.push('\n');
21737                    is_first_line = false;
21738                    current_line = subsequent_lines_prefix.clone();
21739                    current_line_len = subsequent_lines_prefix_len;
21740                }
21741                current_line.push_str(token);
21742                current_line_len += grapheme_len;
21743            }
21744            WordBreakToken::InlineWhitespace {
21745                mut token,
21746                mut grapheme_len,
21747            } => {
21748                in_whitespace = true;
21749                if have_preceding_whitespace && !preserve_existing_whitespace {
21750                    continue;
21751                }
21752                if !preserve_existing_whitespace {
21753                    token = " ";
21754                    grapheme_len = 1;
21755                }
21756                let current_prefix_len = if is_first_line {
21757                    first_line_prefix_len
21758                } else {
21759                    subsequent_lines_prefix_len
21760                };
21761                if current_line_len + grapheme_len > wrap_column {
21762                    wrapped_text.push_str(current_line.trim_end());
21763                    wrapped_text.push('\n');
21764                    is_first_line = false;
21765                    current_line = subsequent_lines_prefix.clone();
21766                    current_line_len = subsequent_lines_prefix_len;
21767                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21768                    current_line.push_str(token);
21769                    current_line_len += grapheme_len;
21770                }
21771            }
21772            WordBreakToken::Newline => {
21773                in_whitespace = true;
21774                let current_prefix_len = if is_first_line {
21775                    first_line_prefix_len
21776                } else {
21777                    subsequent_lines_prefix_len
21778                };
21779                if preserve_existing_whitespace {
21780                    wrapped_text.push_str(current_line.trim_end());
21781                    wrapped_text.push('\n');
21782                    is_first_line = false;
21783                    current_line = subsequent_lines_prefix.clone();
21784                    current_line_len = subsequent_lines_prefix_len;
21785                } else if have_preceding_whitespace {
21786                    continue;
21787                } else if current_line_len + 1 > wrap_column
21788                    && current_line_len != current_prefix_len
21789                {
21790                    wrapped_text.push_str(current_line.trim_end());
21791                    wrapped_text.push('\n');
21792                    is_first_line = false;
21793                    current_line = subsequent_lines_prefix.clone();
21794                    current_line_len = subsequent_lines_prefix_len;
21795                } else if current_line_len != current_prefix_len {
21796                    current_line.push(' ');
21797                    current_line_len += 1;
21798                }
21799            }
21800        }
21801    }
21802
21803    if !current_line.is_empty() {
21804        wrapped_text.push_str(&current_line);
21805    }
21806    wrapped_text
21807}
21808
21809#[test]
21810fn test_wrap_with_prefix() {
21811    assert_eq!(
21812        wrap_with_prefix(
21813            "# ".to_string(),
21814            "# ".to_string(),
21815            "abcdefg".to_string(),
21816            4,
21817            NonZeroU32::new(4).unwrap(),
21818            false,
21819        ),
21820        "# abcdefg"
21821    );
21822    assert_eq!(
21823        wrap_with_prefix(
21824            "".to_string(),
21825            "".to_string(),
21826            "\thello world".to_string(),
21827            8,
21828            NonZeroU32::new(4).unwrap(),
21829            false,
21830        ),
21831        "hello\nworld"
21832    );
21833    assert_eq!(
21834        wrap_with_prefix(
21835            "// ".to_string(),
21836            "// ".to_string(),
21837            "xx \nyy zz aa bb cc".to_string(),
21838            12,
21839            NonZeroU32::new(4).unwrap(),
21840            false,
21841        ),
21842        "// xx yy zz\n// aa bb cc"
21843    );
21844    assert_eq!(
21845        wrap_with_prefix(
21846            String::new(),
21847            String::new(),
21848            "这是什么 \n 钢笔".to_string(),
21849            3,
21850            NonZeroU32::new(4).unwrap(),
21851            false,
21852        ),
21853        "这是什\n么 钢\n"
21854    );
21855}
21856
21857pub trait CollaborationHub {
21858    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21859    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21860    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21861}
21862
21863impl CollaborationHub for Entity<Project> {
21864    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21865        self.read(cx).collaborators()
21866    }
21867
21868    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21869        self.read(cx).user_store().read(cx).participant_indices()
21870    }
21871
21872    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21873        let this = self.read(cx);
21874        let user_ids = this.collaborators().values().map(|c| c.user_id);
21875        this.user_store().read(cx).participant_names(user_ids, cx)
21876    }
21877}
21878
21879pub trait SemanticsProvider {
21880    fn hover(
21881        &self,
21882        buffer: &Entity<Buffer>,
21883        position: text::Anchor,
21884        cx: &mut App,
21885    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21886
21887    fn inline_values(
21888        &self,
21889        buffer_handle: Entity<Buffer>,
21890        range: Range<text::Anchor>,
21891        cx: &mut App,
21892    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21893
21894    fn inlay_hints(
21895        &self,
21896        buffer_handle: Entity<Buffer>,
21897        range: Range<text::Anchor>,
21898        cx: &mut App,
21899    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21900
21901    fn resolve_inlay_hint(
21902        &self,
21903        hint: InlayHint,
21904        buffer_handle: Entity<Buffer>,
21905        server_id: LanguageServerId,
21906        cx: &mut App,
21907    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21908
21909    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21910
21911    fn document_highlights(
21912        &self,
21913        buffer: &Entity<Buffer>,
21914        position: text::Anchor,
21915        cx: &mut App,
21916    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21917
21918    fn definitions(
21919        &self,
21920        buffer: &Entity<Buffer>,
21921        position: text::Anchor,
21922        kind: GotoDefinitionKind,
21923        cx: &mut App,
21924    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21925
21926    fn range_for_rename(
21927        &self,
21928        buffer: &Entity<Buffer>,
21929        position: text::Anchor,
21930        cx: &mut App,
21931    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21932
21933    fn perform_rename(
21934        &self,
21935        buffer: &Entity<Buffer>,
21936        position: text::Anchor,
21937        new_name: String,
21938        cx: &mut App,
21939    ) -> Option<Task<Result<ProjectTransaction>>>;
21940}
21941
21942pub trait CompletionProvider {
21943    fn completions(
21944        &self,
21945        excerpt_id: ExcerptId,
21946        buffer: &Entity<Buffer>,
21947        buffer_position: text::Anchor,
21948        trigger: CompletionContext,
21949        window: &mut Window,
21950        cx: &mut Context<Editor>,
21951    ) -> Task<Result<Vec<CompletionResponse>>>;
21952
21953    fn resolve_completions(
21954        &self,
21955        _buffer: Entity<Buffer>,
21956        _completion_indices: Vec<usize>,
21957        _completions: Rc<RefCell<Box<[Completion]>>>,
21958        _cx: &mut Context<Editor>,
21959    ) -> Task<Result<bool>> {
21960        Task::ready(Ok(false))
21961    }
21962
21963    fn apply_additional_edits_for_completion(
21964        &self,
21965        _buffer: Entity<Buffer>,
21966        _completions: Rc<RefCell<Box<[Completion]>>>,
21967        _completion_index: usize,
21968        _push_to_history: bool,
21969        _cx: &mut Context<Editor>,
21970    ) -> Task<Result<Option<language::Transaction>>> {
21971        Task::ready(Ok(None))
21972    }
21973
21974    fn is_completion_trigger(
21975        &self,
21976        buffer: &Entity<Buffer>,
21977        position: language::Anchor,
21978        text: &str,
21979        trigger_in_words: bool,
21980        menu_is_open: bool,
21981        cx: &mut Context<Editor>,
21982    ) -> bool;
21983
21984    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21985
21986    fn sort_completions(&self) -> bool {
21987        true
21988    }
21989
21990    fn filter_completions(&self) -> bool {
21991        true
21992    }
21993}
21994
21995pub trait CodeActionProvider {
21996    fn id(&self) -> Arc<str>;
21997
21998    fn code_actions(
21999        &self,
22000        buffer: &Entity<Buffer>,
22001        range: Range<text::Anchor>,
22002        window: &mut Window,
22003        cx: &mut App,
22004    ) -> Task<Result<Vec<CodeAction>>>;
22005
22006    fn apply_code_action(
22007        &self,
22008        buffer_handle: Entity<Buffer>,
22009        action: CodeAction,
22010        excerpt_id: ExcerptId,
22011        push_to_history: bool,
22012        window: &mut Window,
22013        cx: &mut App,
22014    ) -> Task<Result<ProjectTransaction>>;
22015}
22016
22017impl CodeActionProvider for Entity<Project> {
22018    fn id(&self) -> Arc<str> {
22019        "project".into()
22020    }
22021
22022    fn code_actions(
22023        &self,
22024        buffer: &Entity<Buffer>,
22025        range: Range<text::Anchor>,
22026        _window: &mut Window,
22027        cx: &mut App,
22028    ) -> Task<Result<Vec<CodeAction>>> {
22029        self.update(cx, |project, cx| {
22030            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22031            let code_actions = project.code_actions(buffer, range, None, cx);
22032            cx.background_spawn(async move {
22033                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22034                Ok(code_lens_actions
22035                    .context("code lens fetch")?
22036                    .into_iter()
22037                    .flatten()
22038                    .chain(
22039                        code_actions
22040                            .context("code action fetch")?
22041                            .into_iter()
22042                            .flatten(),
22043                    )
22044                    .collect())
22045            })
22046        })
22047    }
22048
22049    fn apply_code_action(
22050        &self,
22051        buffer_handle: Entity<Buffer>,
22052        action: CodeAction,
22053        _excerpt_id: ExcerptId,
22054        push_to_history: bool,
22055        _window: &mut Window,
22056        cx: &mut App,
22057    ) -> Task<Result<ProjectTransaction>> {
22058        self.update(cx, |project, cx| {
22059            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22060        })
22061    }
22062}
22063
22064fn snippet_completions(
22065    project: &Project,
22066    buffer: &Entity<Buffer>,
22067    buffer_position: text::Anchor,
22068    cx: &mut App,
22069) -> Task<Result<CompletionResponse>> {
22070    let languages = buffer.read(cx).languages_at(buffer_position);
22071    let snippet_store = project.snippets().read(cx);
22072
22073    let scopes: Vec<_> = languages
22074        .iter()
22075        .filter_map(|language| {
22076            let language_name = language.lsp_id();
22077            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22078
22079            if snippets.is_empty() {
22080                None
22081            } else {
22082                Some((language.default_scope(), snippets))
22083            }
22084        })
22085        .collect();
22086
22087    if scopes.is_empty() {
22088        return Task::ready(Ok(CompletionResponse {
22089            completions: vec![],
22090            is_incomplete: false,
22091        }));
22092    }
22093
22094    let snapshot = buffer.read(cx).text_snapshot();
22095    let chars: String = snapshot
22096        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22097        .collect();
22098    let executor = cx.background_executor().clone();
22099
22100    cx.background_spawn(async move {
22101        let mut is_incomplete = false;
22102        let mut completions: Vec<Completion> = Vec::new();
22103        for (scope, snippets) in scopes.into_iter() {
22104            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22105            let mut last_word = chars
22106                .chars()
22107                .take_while(|c| classifier.is_word(*c))
22108                .collect::<String>();
22109            last_word = last_word.chars().rev().collect();
22110
22111            if last_word.is_empty() {
22112                return Ok(CompletionResponse {
22113                    completions: vec![],
22114                    is_incomplete: true,
22115                });
22116            }
22117
22118            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22119            let to_lsp = |point: &text::Anchor| {
22120                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22121                point_to_lsp(end)
22122            };
22123            let lsp_end = to_lsp(&buffer_position);
22124
22125            let candidates = snippets
22126                .iter()
22127                .enumerate()
22128                .flat_map(|(ix, snippet)| {
22129                    snippet
22130                        .prefix
22131                        .iter()
22132                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22133                })
22134                .collect::<Vec<StringMatchCandidate>>();
22135
22136            const MAX_RESULTS: usize = 100;
22137            let mut matches = fuzzy::match_strings(
22138                &candidates,
22139                &last_word,
22140                last_word.chars().any(|c| c.is_uppercase()),
22141                true,
22142                MAX_RESULTS,
22143                &Default::default(),
22144                executor.clone(),
22145            )
22146            .await;
22147
22148            if matches.len() >= MAX_RESULTS {
22149                is_incomplete = true;
22150            }
22151
22152            // Remove all candidates where the query's start does not match the start of any word in the candidate
22153            if let Some(query_start) = last_word.chars().next() {
22154                matches.retain(|string_match| {
22155                    split_words(&string_match.string).any(|word| {
22156                        // Check that the first codepoint of the word as lowercase matches the first
22157                        // codepoint of the query as lowercase
22158                        word.chars()
22159                            .flat_map(|codepoint| codepoint.to_lowercase())
22160                            .zip(query_start.to_lowercase())
22161                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22162                    })
22163                });
22164            }
22165
22166            let matched_strings = matches
22167                .into_iter()
22168                .map(|m| m.string)
22169                .collect::<HashSet<_>>();
22170
22171            completions.extend(snippets.iter().filter_map(|snippet| {
22172                let matching_prefix = snippet
22173                    .prefix
22174                    .iter()
22175                    .find(|prefix| matched_strings.contains(*prefix))?;
22176                let start = as_offset - last_word.len();
22177                let start = snapshot.anchor_before(start);
22178                let range = start..buffer_position;
22179                let lsp_start = to_lsp(&start);
22180                let lsp_range = lsp::Range {
22181                    start: lsp_start,
22182                    end: lsp_end,
22183                };
22184                Some(Completion {
22185                    replace_range: range,
22186                    new_text: snippet.body.clone(),
22187                    source: CompletionSource::Lsp {
22188                        insert_range: None,
22189                        server_id: LanguageServerId(usize::MAX),
22190                        resolved: true,
22191                        lsp_completion: Box::new(lsp::CompletionItem {
22192                            label: snippet.prefix.first().unwrap().clone(),
22193                            kind: Some(CompletionItemKind::SNIPPET),
22194                            label_details: snippet.description.as_ref().map(|description| {
22195                                lsp::CompletionItemLabelDetails {
22196                                    detail: Some(description.clone()),
22197                                    description: None,
22198                                }
22199                            }),
22200                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22201                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22202                                lsp::InsertReplaceEdit {
22203                                    new_text: snippet.body.clone(),
22204                                    insert: lsp_range,
22205                                    replace: lsp_range,
22206                                },
22207                            )),
22208                            filter_text: Some(snippet.body.clone()),
22209                            sort_text: Some(char::MAX.to_string()),
22210                            ..lsp::CompletionItem::default()
22211                        }),
22212                        lsp_defaults: None,
22213                    },
22214                    label: CodeLabel {
22215                        text: matching_prefix.clone(),
22216                        runs: Vec::new(),
22217                        filter_range: 0..matching_prefix.len(),
22218                    },
22219                    icon_path: None,
22220                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22221                        single_line: snippet.name.clone().into(),
22222                        plain_text: snippet
22223                            .description
22224                            .clone()
22225                            .map(|description| description.into()),
22226                    }),
22227                    insert_text_mode: None,
22228                    confirm: None,
22229                })
22230            }))
22231        }
22232
22233        Ok(CompletionResponse {
22234            completions,
22235            is_incomplete,
22236        })
22237    })
22238}
22239
22240impl CompletionProvider for Entity<Project> {
22241    fn completions(
22242        &self,
22243        _excerpt_id: ExcerptId,
22244        buffer: &Entity<Buffer>,
22245        buffer_position: text::Anchor,
22246        options: CompletionContext,
22247        _window: &mut Window,
22248        cx: &mut Context<Editor>,
22249    ) -> Task<Result<Vec<CompletionResponse>>> {
22250        self.update(cx, |project, cx| {
22251            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22252            let project_completions = project.completions(buffer, buffer_position, options, cx);
22253            cx.background_spawn(async move {
22254                let mut responses = project_completions.await?;
22255                let snippets = snippets.await?;
22256                if !snippets.completions.is_empty() {
22257                    responses.push(snippets);
22258                }
22259                Ok(responses)
22260            })
22261        })
22262    }
22263
22264    fn resolve_completions(
22265        &self,
22266        buffer: Entity<Buffer>,
22267        completion_indices: Vec<usize>,
22268        completions: Rc<RefCell<Box<[Completion]>>>,
22269        cx: &mut Context<Editor>,
22270    ) -> Task<Result<bool>> {
22271        self.update(cx, |project, cx| {
22272            project.lsp_store().update(cx, |lsp_store, cx| {
22273                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22274            })
22275        })
22276    }
22277
22278    fn apply_additional_edits_for_completion(
22279        &self,
22280        buffer: Entity<Buffer>,
22281        completions: Rc<RefCell<Box<[Completion]>>>,
22282        completion_index: usize,
22283        push_to_history: bool,
22284        cx: &mut Context<Editor>,
22285    ) -> Task<Result<Option<language::Transaction>>> {
22286        self.update(cx, |project, cx| {
22287            project.lsp_store().update(cx, |lsp_store, cx| {
22288                lsp_store.apply_additional_edits_for_completion(
22289                    buffer,
22290                    completions,
22291                    completion_index,
22292                    push_to_history,
22293                    cx,
22294                )
22295            })
22296        })
22297    }
22298
22299    fn is_completion_trigger(
22300        &self,
22301        buffer: &Entity<Buffer>,
22302        position: language::Anchor,
22303        text: &str,
22304        trigger_in_words: bool,
22305        menu_is_open: bool,
22306        cx: &mut Context<Editor>,
22307    ) -> bool {
22308        let mut chars = text.chars();
22309        let char = if let Some(char) = chars.next() {
22310            char
22311        } else {
22312            return false;
22313        };
22314        if chars.next().is_some() {
22315            return false;
22316        }
22317
22318        let buffer = buffer.read(cx);
22319        let snapshot = buffer.snapshot();
22320        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22321            return false;
22322        }
22323        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22324        if trigger_in_words && classifier.is_word(char) {
22325            return true;
22326        }
22327
22328        buffer.completion_triggers().contains(text)
22329    }
22330}
22331
22332impl SemanticsProvider for Entity<Project> {
22333    fn hover(
22334        &self,
22335        buffer: &Entity<Buffer>,
22336        position: text::Anchor,
22337        cx: &mut App,
22338    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22339        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22340    }
22341
22342    fn document_highlights(
22343        &self,
22344        buffer: &Entity<Buffer>,
22345        position: text::Anchor,
22346        cx: &mut App,
22347    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22348        Some(self.update(cx, |project, cx| {
22349            project.document_highlights(buffer, position, cx)
22350        }))
22351    }
22352
22353    fn definitions(
22354        &self,
22355        buffer: &Entity<Buffer>,
22356        position: text::Anchor,
22357        kind: GotoDefinitionKind,
22358        cx: &mut App,
22359    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22360        Some(self.update(cx, |project, cx| match kind {
22361            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22362            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22363            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22364            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22365        }))
22366    }
22367
22368    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22369        self.update(cx, |project, cx| {
22370            if project
22371                .active_debug_session(cx)
22372                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22373            {
22374                return true;
22375            }
22376
22377            buffer.update(cx, |buffer, cx| {
22378                project.any_language_server_supports_inlay_hints(buffer, cx)
22379            })
22380        })
22381    }
22382
22383    fn inline_values(
22384        &self,
22385        buffer_handle: Entity<Buffer>,
22386        range: Range<text::Anchor>,
22387        cx: &mut App,
22388    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22389        self.update(cx, |project, cx| {
22390            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22391
22392            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22393        })
22394    }
22395
22396    fn inlay_hints(
22397        &self,
22398        buffer_handle: Entity<Buffer>,
22399        range: Range<text::Anchor>,
22400        cx: &mut App,
22401    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22402        Some(self.update(cx, |project, cx| {
22403            project.inlay_hints(buffer_handle, range, cx)
22404        }))
22405    }
22406
22407    fn resolve_inlay_hint(
22408        &self,
22409        hint: InlayHint,
22410        buffer_handle: Entity<Buffer>,
22411        server_id: LanguageServerId,
22412        cx: &mut App,
22413    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22414        Some(self.update(cx, |project, cx| {
22415            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22416        }))
22417    }
22418
22419    fn range_for_rename(
22420        &self,
22421        buffer: &Entity<Buffer>,
22422        position: text::Anchor,
22423        cx: &mut App,
22424    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22425        Some(self.update(cx, |project, cx| {
22426            let buffer = buffer.clone();
22427            let task = project.prepare_rename(buffer.clone(), position, cx);
22428            cx.spawn(async move |_, cx| {
22429                Ok(match task.await? {
22430                    PrepareRenameResponse::Success(range) => Some(range),
22431                    PrepareRenameResponse::InvalidPosition => None,
22432                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22433                        // Fallback on using TreeSitter info to determine identifier range
22434                        buffer.read_with(cx, |buffer, _| {
22435                            let snapshot = buffer.snapshot();
22436                            let (range, kind) = snapshot.surrounding_word(position, false);
22437                            if kind != Some(CharKind::Word) {
22438                                return None;
22439                            }
22440                            Some(
22441                                snapshot.anchor_before(range.start)
22442                                    ..snapshot.anchor_after(range.end),
22443                            )
22444                        })?
22445                    }
22446                })
22447            })
22448        }))
22449    }
22450
22451    fn perform_rename(
22452        &self,
22453        buffer: &Entity<Buffer>,
22454        position: text::Anchor,
22455        new_name: String,
22456        cx: &mut App,
22457    ) -> Option<Task<Result<ProjectTransaction>>> {
22458        Some(self.update(cx, |project, cx| {
22459            project.perform_rename(buffer.clone(), position, new_name, cx)
22460        }))
22461    }
22462}
22463
22464fn inlay_hint_settings(
22465    location: Anchor,
22466    snapshot: &MultiBufferSnapshot,
22467    cx: &mut Context<Editor>,
22468) -> InlayHintSettings {
22469    let file = snapshot.file_at(location);
22470    let language = snapshot.language_at(location).map(|l| l.name());
22471    language_settings(language, file, cx).inlay_hints
22472}
22473
22474fn consume_contiguous_rows(
22475    contiguous_row_selections: &mut Vec<Selection<Point>>,
22476    selection: &Selection<Point>,
22477    display_map: &DisplaySnapshot,
22478    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22479) -> (MultiBufferRow, MultiBufferRow) {
22480    contiguous_row_selections.push(selection.clone());
22481    let start_row = starting_row(selection, display_map);
22482    let mut end_row = ending_row(selection, display_map);
22483
22484    while let Some(next_selection) = selections.peek() {
22485        if next_selection.start.row <= end_row.0 {
22486            end_row = ending_row(next_selection, display_map);
22487            contiguous_row_selections.push(selections.next().unwrap().clone());
22488        } else {
22489            break;
22490        }
22491    }
22492    (start_row, end_row)
22493}
22494
22495fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22496    if selection.start.column > 0 {
22497        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22498    } else {
22499        MultiBufferRow(selection.start.row)
22500    }
22501}
22502
22503fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22504    if next_selection.end.column > 0 || next_selection.is_empty() {
22505        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22506    } else {
22507        MultiBufferRow(next_selection.end.row)
22508    }
22509}
22510
22511impl EditorSnapshot {
22512    pub fn remote_selections_in_range<'a>(
22513        &'a self,
22514        range: &'a Range<Anchor>,
22515        collaboration_hub: &dyn CollaborationHub,
22516        cx: &'a App,
22517    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22518        let participant_names = collaboration_hub.user_names(cx);
22519        let participant_indices = collaboration_hub.user_participant_indices(cx);
22520        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22521        let collaborators_by_replica_id = collaborators_by_peer_id
22522            .values()
22523            .map(|collaborator| (collaborator.replica_id, collaborator))
22524            .collect::<HashMap<_, _>>();
22525        self.buffer_snapshot
22526            .selections_in_range(range, false)
22527            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22528                if replica_id == AGENT_REPLICA_ID {
22529                    Some(RemoteSelection {
22530                        replica_id,
22531                        selection,
22532                        cursor_shape,
22533                        line_mode,
22534                        collaborator_id: CollaboratorId::Agent,
22535                        user_name: Some("Agent".into()),
22536                        color: cx.theme().players().agent(),
22537                    })
22538                } else {
22539                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22540                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22541                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22542                    Some(RemoteSelection {
22543                        replica_id,
22544                        selection,
22545                        cursor_shape,
22546                        line_mode,
22547                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22548                        user_name,
22549                        color: if let Some(index) = participant_index {
22550                            cx.theme().players().color_for_participant(index.0)
22551                        } else {
22552                            cx.theme().players().absent()
22553                        },
22554                    })
22555                }
22556            })
22557    }
22558
22559    pub fn hunks_for_ranges(
22560        &self,
22561        ranges: impl IntoIterator<Item = Range<Point>>,
22562    ) -> Vec<MultiBufferDiffHunk> {
22563        let mut hunks = Vec::new();
22564        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22565            HashMap::default();
22566        for query_range in ranges {
22567            let query_rows =
22568                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22569            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22570                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22571            ) {
22572                // Include deleted hunks that are adjacent to the query range, because
22573                // otherwise they would be missed.
22574                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22575                if hunk.status().is_deleted() {
22576                    intersects_range |= hunk.row_range.start == query_rows.end;
22577                    intersects_range |= hunk.row_range.end == query_rows.start;
22578                }
22579                if intersects_range {
22580                    if !processed_buffer_rows
22581                        .entry(hunk.buffer_id)
22582                        .or_default()
22583                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22584                    {
22585                        continue;
22586                    }
22587                    hunks.push(hunk);
22588                }
22589            }
22590        }
22591
22592        hunks
22593    }
22594
22595    fn display_diff_hunks_for_rows<'a>(
22596        &'a self,
22597        display_rows: Range<DisplayRow>,
22598        folded_buffers: &'a HashSet<BufferId>,
22599    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22600        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22601        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22602
22603        self.buffer_snapshot
22604            .diff_hunks_in_range(buffer_start..buffer_end)
22605            .filter_map(|hunk| {
22606                if folded_buffers.contains(&hunk.buffer_id) {
22607                    return None;
22608                }
22609
22610                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22611                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22612
22613                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22614                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22615
22616                let display_hunk = if hunk_display_start.column() != 0 {
22617                    DisplayDiffHunk::Folded {
22618                        display_row: hunk_display_start.row(),
22619                    }
22620                } else {
22621                    let mut end_row = hunk_display_end.row();
22622                    if hunk_display_end.column() > 0 {
22623                        end_row.0 += 1;
22624                    }
22625                    let is_created_file = hunk.is_created_file();
22626                    DisplayDiffHunk::Unfolded {
22627                        status: hunk.status(),
22628                        diff_base_byte_range: hunk.diff_base_byte_range,
22629                        display_row_range: hunk_display_start.row()..end_row,
22630                        multi_buffer_range: Anchor::range_in_buffer(
22631                            hunk.excerpt_id,
22632                            hunk.buffer_id,
22633                            hunk.buffer_range,
22634                        ),
22635                        is_created_file,
22636                    }
22637                };
22638
22639                Some(display_hunk)
22640            })
22641    }
22642
22643    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22644        self.display_snapshot.buffer_snapshot.language_at(position)
22645    }
22646
22647    pub fn is_focused(&self) -> bool {
22648        self.is_focused
22649    }
22650
22651    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22652        self.placeholder_text.as_ref()
22653    }
22654
22655    pub fn scroll_position(&self) -> gpui::Point<f32> {
22656        self.scroll_anchor.scroll_position(&self.display_snapshot)
22657    }
22658
22659    fn gutter_dimensions(
22660        &self,
22661        font_id: FontId,
22662        font_size: Pixels,
22663        max_line_number_width: Pixels,
22664        cx: &App,
22665    ) -> Option<GutterDimensions> {
22666        if !self.show_gutter {
22667            return None;
22668        }
22669
22670        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22671        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22672
22673        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22674            matches!(
22675                ProjectSettings::get_global(cx).git.git_gutter,
22676                Some(GitGutterSetting::TrackedFiles)
22677            )
22678        });
22679        let gutter_settings = EditorSettings::get_global(cx).gutter;
22680        let show_line_numbers = self
22681            .show_line_numbers
22682            .unwrap_or(gutter_settings.line_numbers);
22683        let line_gutter_width = if show_line_numbers {
22684            // Avoid flicker-like gutter resizes when the line number gains another digit by
22685            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22686            let min_width_for_number_on_gutter =
22687                ch_advance * gutter_settings.min_line_number_digits as f32;
22688            max_line_number_width.max(min_width_for_number_on_gutter)
22689        } else {
22690            0.0.into()
22691        };
22692
22693        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22694        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22695
22696        let git_blame_entries_width =
22697            self.git_blame_gutter_max_author_length
22698                .map(|max_author_length| {
22699                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22700                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22701
22702                    /// The number of characters to dedicate to gaps and margins.
22703                    const SPACING_WIDTH: usize = 4;
22704
22705                    let max_char_count = max_author_length.min(renderer.max_author_length())
22706                        + ::git::SHORT_SHA_LENGTH
22707                        + MAX_RELATIVE_TIMESTAMP.len()
22708                        + SPACING_WIDTH;
22709
22710                    ch_advance * max_char_count
22711                });
22712
22713        let is_singleton = self.buffer_snapshot.is_singleton();
22714
22715        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22716        left_padding += if !is_singleton {
22717            ch_width * 4.0
22718        } else if show_runnables || show_breakpoints {
22719            ch_width * 3.0
22720        } else if show_git_gutter && show_line_numbers {
22721            ch_width * 2.0
22722        } else if show_git_gutter || show_line_numbers {
22723            ch_width
22724        } else {
22725            px(0.)
22726        };
22727
22728        let shows_folds = is_singleton && gutter_settings.folds;
22729
22730        let right_padding = if shows_folds && show_line_numbers {
22731            ch_width * 4.0
22732        } else if shows_folds || (!is_singleton && show_line_numbers) {
22733            ch_width * 3.0
22734        } else if show_line_numbers {
22735            ch_width
22736        } else {
22737            px(0.)
22738        };
22739
22740        Some(GutterDimensions {
22741            left_padding,
22742            right_padding,
22743            width: line_gutter_width + left_padding + right_padding,
22744            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22745            git_blame_entries_width,
22746        })
22747    }
22748
22749    pub fn render_crease_toggle(
22750        &self,
22751        buffer_row: MultiBufferRow,
22752        row_contains_cursor: bool,
22753        editor: Entity<Editor>,
22754        window: &mut Window,
22755        cx: &mut App,
22756    ) -> Option<AnyElement> {
22757        let folded = self.is_line_folded(buffer_row);
22758        let mut is_foldable = false;
22759
22760        if let Some(crease) = self
22761            .crease_snapshot
22762            .query_row(buffer_row, &self.buffer_snapshot)
22763        {
22764            is_foldable = true;
22765            match crease {
22766                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22767                    if let Some(render_toggle) = render_toggle {
22768                        let toggle_callback =
22769                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22770                                if folded {
22771                                    editor.update(cx, |editor, cx| {
22772                                        editor.fold_at(buffer_row, window, cx)
22773                                    });
22774                                } else {
22775                                    editor.update(cx, |editor, cx| {
22776                                        editor.unfold_at(buffer_row, window, cx)
22777                                    });
22778                                }
22779                            });
22780                        return Some((render_toggle)(
22781                            buffer_row,
22782                            folded,
22783                            toggle_callback,
22784                            window,
22785                            cx,
22786                        ));
22787                    }
22788                }
22789            }
22790        }
22791
22792        is_foldable |= self.starts_indent(buffer_row);
22793
22794        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22795            Some(
22796                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22797                    .toggle_state(folded)
22798                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22799                        if folded {
22800                            this.unfold_at(buffer_row, window, cx);
22801                        } else {
22802                            this.fold_at(buffer_row, window, cx);
22803                        }
22804                    }))
22805                    .into_any_element(),
22806            )
22807        } else {
22808            None
22809        }
22810    }
22811
22812    pub fn render_crease_trailer(
22813        &self,
22814        buffer_row: MultiBufferRow,
22815        window: &mut Window,
22816        cx: &mut App,
22817    ) -> Option<AnyElement> {
22818        let folded = self.is_line_folded(buffer_row);
22819        if let Crease::Inline { render_trailer, .. } = self
22820            .crease_snapshot
22821            .query_row(buffer_row, &self.buffer_snapshot)?
22822        {
22823            let render_trailer = render_trailer.as_ref()?;
22824            Some(render_trailer(buffer_row, folded, window, cx))
22825        } else {
22826            None
22827        }
22828    }
22829}
22830
22831impl Deref for EditorSnapshot {
22832    type Target = DisplaySnapshot;
22833
22834    fn deref(&self) -> &Self::Target {
22835        &self.display_snapshot
22836    }
22837}
22838
22839#[derive(Clone, Debug, PartialEq, Eq)]
22840pub enum EditorEvent {
22841    InputIgnored {
22842        text: Arc<str>,
22843    },
22844    InputHandled {
22845        utf16_range_to_replace: Option<Range<isize>>,
22846        text: Arc<str>,
22847    },
22848    ExcerptsAdded {
22849        buffer: Entity<Buffer>,
22850        predecessor: ExcerptId,
22851        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22852    },
22853    ExcerptsRemoved {
22854        ids: Vec<ExcerptId>,
22855        removed_buffer_ids: Vec<BufferId>,
22856    },
22857    BufferFoldToggled {
22858        ids: Vec<ExcerptId>,
22859        folded: bool,
22860    },
22861    ExcerptsEdited {
22862        ids: Vec<ExcerptId>,
22863    },
22864    ExcerptsExpanded {
22865        ids: Vec<ExcerptId>,
22866    },
22867    BufferEdited,
22868    Edited {
22869        transaction_id: clock::Lamport,
22870    },
22871    Reparsed(BufferId),
22872    Focused,
22873    FocusedIn,
22874    Blurred,
22875    DirtyChanged,
22876    Saved,
22877    TitleChanged,
22878    DiffBaseChanged,
22879    SelectionsChanged {
22880        local: bool,
22881    },
22882    ScrollPositionChanged {
22883        local: bool,
22884        autoscroll: bool,
22885    },
22886    Closed,
22887    TransactionUndone {
22888        transaction_id: clock::Lamport,
22889    },
22890    TransactionBegun {
22891        transaction_id: clock::Lamport,
22892    },
22893    Reloaded,
22894    CursorShapeChanged,
22895    BreadcrumbsChanged,
22896    PushedToNavHistory {
22897        anchor: Anchor,
22898        is_deactivate: bool,
22899    },
22900}
22901
22902impl EventEmitter<EditorEvent> for Editor {}
22903
22904impl Focusable for Editor {
22905    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22906        self.focus_handle.clone()
22907    }
22908}
22909
22910impl Render for Editor {
22911    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22912        let settings = ThemeSettings::get_global(cx);
22913
22914        let mut text_style = match self.mode {
22915            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22916                color: cx.theme().colors().editor_foreground,
22917                font_family: settings.ui_font.family.clone(),
22918                font_features: settings.ui_font.features.clone(),
22919                font_fallbacks: settings.ui_font.fallbacks.clone(),
22920                font_size: rems(0.875).into(),
22921                font_weight: settings.ui_font.weight,
22922                line_height: relative(settings.buffer_line_height.value()),
22923                ..Default::default()
22924            },
22925            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22926                color: cx.theme().colors().editor_foreground,
22927                font_family: settings.buffer_font.family.clone(),
22928                font_features: settings.buffer_font.features.clone(),
22929                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22930                font_size: settings.buffer_font_size(cx).into(),
22931                font_weight: settings.buffer_font.weight,
22932                line_height: relative(settings.buffer_line_height.value()),
22933                ..Default::default()
22934            },
22935        };
22936        if let Some(text_style_refinement) = &self.text_style_refinement {
22937            text_style.refine(text_style_refinement)
22938        }
22939
22940        let background = match self.mode {
22941            EditorMode::SingleLine => cx.theme().system().transparent,
22942            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22943            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22944            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22945        };
22946
22947        EditorElement::new(
22948            &cx.entity(),
22949            EditorStyle {
22950                background,
22951                border: cx.theme().colors().border,
22952                local_player: cx.theme().players().local(),
22953                text: text_style,
22954                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22955                syntax: cx.theme().syntax().clone(),
22956                status: cx.theme().status().clone(),
22957                inlay_hints_style: make_inlay_hints_style(cx),
22958                edit_prediction_styles: make_suggestion_styles(cx),
22959                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22960                show_underlines: self.diagnostics_enabled(),
22961            },
22962        )
22963    }
22964}
22965
22966impl EntityInputHandler for Editor {
22967    fn text_for_range(
22968        &mut self,
22969        range_utf16: Range<usize>,
22970        adjusted_range: &mut Option<Range<usize>>,
22971        _: &mut Window,
22972        cx: &mut Context<Self>,
22973    ) -> Option<String> {
22974        let snapshot = self.buffer.read(cx).read(cx);
22975        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22976        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22977        if (start.0..end.0) != range_utf16 {
22978            adjusted_range.replace(start.0..end.0);
22979        }
22980        Some(snapshot.text_for_range(start..end).collect())
22981    }
22982
22983    fn selected_text_range(
22984        &mut self,
22985        ignore_disabled_input: bool,
22986        _: &mut Window,
22987        cx: &mut Context<Self>,
22988    ) -> Option<UTF16Selection> {
22989        // Prevent the IME menu from appearing when holding down an alphabetic key
22990        // while input is disabled.
22991        if !ignore_disabled_input && !self.input_enabled {
22992            return None;
22993        }
22994
22995        let selection = self.selections.newest::<OffsetUtf16>(cx);
22996        let range = selection.range();
22997
22998        Some(UTF16Selection {
22999            range: range.start.0..range.end.0,
23000            reversed: selection.reversed,
23001        })
23002    }
23003
23004    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23005        let snapshot = self.buffer.read(cx).read(cx);
23006        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23007        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23008    }
23009
23010    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23011        self.clear_highlights::<InputComposition>(cx);
23012        self.ime_transaction.take();
23013    }
23014
23015    fn replace_text_in_range(
23016        &mut self,
23017        range_utf16: Option<Range<usize>>,
23018        text: &str,
23019        window: &mut Window,
23020        cx: &mut Context<Self>,
23021    ) {
23022        if !self.input_enabled {
23023            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23024            return;
23025        }
23026
23027        self.transact(window, cx, |this, window, cx| {
23028            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23029                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23030                Some(this.selection_replacement_ranges(range_utf16, cx))
23031            } else {
23032                this.marked_text_ranges(cx)
23033            };
23034
23035            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23036                let newest_selection_id = this.selections.newest_anchor().id;
23037                this.selections
23038                    .all::<OffsetUtf16>(cx)
23039                    .iter()
23040                    .zip(ranges_to_replace.iter())
23041                    .find_map(|(selection, range)| {
23042                        if selection.id == newest_selection_id {
23043                            Some(
23044                                (range.start.0 as isize - selection.head().0 as isize)
23045                                    ..(range.end.0 as isize - selection.head().0 as isize),
23046                            )
23047                        } else {
23048                            None
23049                        }
23050                    })
23051            });
23052
23053            cx.emit(EditorEvent::InputHandled {
23054                utf16_range_to_replace: range_to_replace,
23055                text: text.into(),
23056            });
23057
23058            if let Some(new_selected_ranges) = new_selected_ranges {
23059                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23060                    selections.select_ranges(new_selected_ranges)
23061                });
23062                this.backspace(&Default::default(), window, cx);
23063            }
23064
23065            this.handle_input(text, window, cx);
23066        });
23067
23068        if let Some(transaction) = self.ime_transaction {
23069            self.buffer.update(cx, |buffer, cx| {
23070                buffer.group_until_transaction(transaction, cx);
23071            });
23072        }
23073
23074        self.unmark_text(window, cx);
23075    }
23076
23077    fn replace_and_mark_text_in_range(
23078        &mut self,
23079        range_utf16: Option<Range<usize>>,
23080        text: &str,
23081        new_selected_range_utf16: Option<Range<usize>>,
23082        window: &mut Window,
23083        cx: &mut Context<Self>,
23084    ) {
23085        if !self.input_enabled {
23086            return;
23087        }
23088
23089        let transaction = self.transact(window, cx, |this, window, cx| {
23090            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23091                let snapshot = this.buffer.read(cx).read(cx);
23092                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23093                    for marked_range in &mut marked_ranges {
23094                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23095                        marked_range.start.0 += relative_range_utf16.start;
23096                        marked_range.start =
23097                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23098                        marked_range.end =
23099                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23100                    }
23101                }
23102                Some(marked_ranges)
23103            } else if let Some(range_utf16) = range_utf16 {
23104                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23105                Some(this.selection_replacement_ranges(range_utf16, cx))
23106            } else {
23107                None
23108            };
23109
23110            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23111                let newest_selection_id = this.selections.newest_anchor().id;
23112                this.selections
23113                    .all::<OffsetUtf16>(cx)
23114                    .iter()
23115                    .zip(ranges_to_replace.iter())
23116                    .find_map(|(selection, range)| {
23117                        if selection.id == newest_selection_id {
23118                            Some(
23119                                (range.start.0 as isize - selection.head().0 as isize)
23120                                    ..(range.end.0 as isize - selection.head().0 as isize),
23121                            )
23122                        } else {
23123                            None
23124                        }
23125                    })
23126            });
23127
23128            cx.emit(EditorEvent::InputHandled {
23129                utf16_range_to_replace: range_to_replace,
23130                text: text.into(),
23131            });
23132
23133            if let Some(ranges) = ranges_to_replace {
23134                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23135                    s.select_ranges(ranges)
23136                });
23137            }
23138
23139            let marked_ranges = {
23140                let snapshot = this.buffer.read(cx).read(cx);
23141                this.selections
23142                    .disjoint_anchors()
23143                    .iter()
23144                    .map(|selection| {
23145                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23146                    })
23147                    .collect::<Vec<_>>()
23148            };
23149
23150            if text.is_empty() {
23151                this.unmark_text(window, cx);
23152            } else {
23153                this.highlight_text::<InputComposition>(
23154                    marked_ranges.clone(),
23155                    HighlightStyle {
23156                        underline: Some(UnderlineStyle {
23157                            thickness: px(1.),
23158                            color: None,
23159                            wavy: false,
23160                        }),
23161                        ..Default::default()
23162                    },
23163                    cx,
23164                );
23165            }
23166
23167            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23168            let use_autoclose = this.use_autoclose;
23169            let use_auto_surround = this.use_auto_surround;
23170            this.set_use_autoclose(false);
23171            this.set_use_auto_surround(false);
23172            this.handle_input(text, window, cx);
23173            this.set_use_autoclose(use_autoclose);
23174            this.set_use_auto_surround(use_auto_surround);
23175
23176            if let Some(new_selected_range) = new_selected_range_utf16 {
23177                let snapshot = this.buffer.read(cx).read(cx);
23178                let new_selected_ranges = marked_ranges
23179                    .into_iter()
23180                    .map(|marked_range| {
23181                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23182                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23183                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23184                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23185                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23186                    })
23187                    .collect::<Vec<_>>();
23188
23189                drop(snapshot);
23190                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23191                    selections.select_ranges(new_selected_ranges)
23192                });
23193            }
23194        });
23195
23196        self.ime_transaction = self.ime_transaction.or(transaction);
23197        if let Some(transaction) = self.ime_transaction {
23198            self.buffer.update(cx, |buffer, cx| {
23199                buffer.group_until_transaction(transaction, cx);
23200            });
23201        }
23202
23203        if self.text_highlights::<InputComposition>(cx).is_none() {
23204            self.ime_transaction.take();
23205        }
23206    }
23207
23208    fn bounds_for_range(
23209        &mut self,
23210        range_utf16: Range<usize>,
23211        element_bounds: gpui::Bounds<Pixels>,
23212        window: &mut Window,
23213        cx: &mut Context<Self>,
23214    ) -> Option<gpui::Bounds<Pixels>> {
23215        let text_layout_details = self.text_layout_details(window);
23216        let CharacterDimensions {
23217            em_width,
23218            em_advance,
23219            line_height,
23220        } = self.character_dimensions(window);
23221
23222        let snapshot = self.snapshot(window, cx);
23223        let scroll_position = snapshot.scroll_position();
23224        let scroll_left = scroll_position.x * em_advance;
23225
23226        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23227        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23228            + self.gutter_dimensions.full_width();
23229        let y = line_height * (start.row().as_f32() - scroll_position.y);
23230
23231        Some(Bounds {
23232            origin: element_bounds.origin + point(x, y),
23233            size: size(em_width, line_height),
23234        })
23235    }
23236
23237    fn character_index_for_point(
23238        &mut self,
23239        point: gpui::Point<Pixels>,
23240        _window: &mut Window,
23241        _cx: &mut Context<Self>,
23242    ) -> Option<usize> {
23243        let position_map = self.last_position_map.as_ref()?;
23244        if !position_map.text_hitbox.contains(&point) {
23245            return None;
23246        }
23247        let display_point = position_map.point_for_position(point).previous_valid;
23248        let anchor = position_map
23249            .snapshot
23250            .display_point_to_anchor(display_point, Bias::Left);
23251        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23252        Some(utf16_offset.0)
23253    }
23254}
23255
23256trait SelectionExt {
23257    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23258    fn spanned_rows(
23259        &self,
23260        include_end_if_at_line_start: bool,
23261        map: &DisplaySnapshot,
23262    ) -> Range<MultiBufferRow>;
23263}
23264
23265impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23266    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23267        let start = self
23268            .start
23269            .to_point(&map.buffer_snapshot)
23270            .to_display_point(map);
23271        let end = self
23272            .end
23273            .to_point(&map.buffer_snapshot)
23274            .to_display_point(map);
23275        if self.reversed {
23276            end..start
23277        } else {
23278            start..end
23279        }
23280    }
23281
23282    fn spanned_rows(
23283        &self,
23284        include_end_if_at_line_start: bool,
23285        map: &DisplaySnapshot,
23286    ) -> Range<MultiBufferRow> {
23287        let start = self.start.to_point(&map.buffer_snapshot);
23288        let mut end = self.end.to_point(&map.buffer_snapshot);
23289        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23290            end.row -= 1;
23291        }
23292
23293        let buffer_start = map.prev_line_boundary(start).0;
23294        let buffer_end = map.next_line_boundary(end).0;
23295        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23296    }
23297}
23298
23299impl<T: InvalidationRegion> InvalidationStack<T> {
23300    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23301    where
23302        S: Clone + ToOffset,
23303    {
23304        while let Some(region) = self.last() {
23305            let all_selections_inside_invalidation_ranges =
23306                if selections.len() == region.ranges().len() {
23307                    selections
23308                        .iter()
23309                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23310                        .all(|(selection, invalidation_range)| {
23311                            let head = selection.head().to_offset(buffer);
23312                            invalidation_range.start <= head && invalidation_range.end >= head
23313                        })
23314                } else {
23315                    false
23316                };
23317
23318            if all_selections_inside_invalidation_ranges {
23319                break;
23320            } else {
23321                self.pop();
23322            }
23323        }
23324    }
23325}
23326
23327impl<T> Default for InvalidationStack<T> {
23328    fn default() -> Self {
23329        Self(Default::default())
23330    }
23331}
23332
23333impl<T> Deref for InvalidationStack<T> {
23334    type Target = Vec<T>;
23335
23336    fn deref(&self) -> &Self::Target {
23337        &self.0
23338    }
23339}
23340
23341impl<T> DerefMut for InvalidationStack<T> {
23342    fn deref_mut(&mut self) -> &mut Self::Target {
23343        &mut self.0
23344    }
23345}
23346
23347impl InvalidationRegion for SnippetState {
23348    fn ranges(&self) -> &[Range<Anchor>] {
23349        &self.ranges[self.active_index]
23350    }
23351}
23352
23353fn edit_prediction_edit_text(
23354    current_snapshot: &BufferSnapshot,
23355    edits: &[(Range<Anchor>, String)],
23356    edit_preview: &EditPreview,
23357    include_deletions: bool,
23358    cx: &App,
23359) -> HighlightedText {
23360    let edits = edits
23361        .iter()
23362        .map(|(anchor, text)| {
23363            (
23364                anchor.start.text_anchor..anchor.end.text_anchor,
23365                text.clone(),
23366            )
23367        })
23368        .collect::<Vec<_>>();
23369
23370    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23371}
23372
23373fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23374    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23375    // Just show the raw edit text with basic styling
23376    let mut text = String::new();
23377    let mut highlights = Vec::new();
23378
23379    let insertion_highlight_style = HighlightStyle {
23380        color: Some(cx.theme().colors().text),
23381        ..Default::default()
23382    };
23383
23384    for (_, edit_text) in edits {
23385        let start_offset = text.len();
23386        text.push_str(edit_text);
23387        let end_offset = text.len();
23388
23389        if start_offset < end_offset {
23390            highlights.push((start_offset..end_offset, insertion_highlight_style));
23391        }
23392    }
23393
23394    HighlightedText {
23395        text: text.into(),
23396        highlights,
23397    }
23398}
23399
23400pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23401    match severity {
23402        lsp::DiagnosticSeverity::ERROR => colors.error,
23403        lsp::DiagnosticSeverity::WARNING => colors.warning,
23404        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23405        lsp::DiagnosticSeverity::HINT => colors.info,
23406        _ => colors.ignored,
23407    }
23408}
23409
23410pub fn styled_runs_for_code_label<'a>(
23411    label: &'a CodeLabel,
23412    syntax_theme: &'a theme::SyntaxTheme,
23413) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23414    let fade_out = HighlightStyle {
23415        fade_out: Some(0.35),
23416        ..Default::default()
23417    };
23418
23419    let mut prev_end = label.filter_range.end;
23420    label
23421        .runs
23422        .iter()
23423        .enumerate()
23424        .flat_map(move |(ix, (range, highlight_id))| {
23425            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23426                style
23427            } else {
23428                return Default::default();
23429            };
23430            let mut muted_style = style;
23431            muted_style.highlight(fade_out);
23432
23433            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23434            if range.start >= label.filter_range.end {
23435                if range.start > prev_end {
23436                    runs.push((prev_end..range.start, fade_out));
23437                }
23438                runs.push((range.clone(), muted_style));
23439            } else if range.end <= label.filter_range.end {
23440                runs.push((range.clone(), style));
23441            } else {
23442                runs.push((range.start..label.filter_range.end, style));
23443                runs.push((label.filter_range.end..range.end, muted_style));
23444            }
23445            prev_end = cmp::max(prev_end, range.end);
23446
23447            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23448                runs.push((prev_end..label.text.len(), fade_out));
23449            }
23450
23451            runs
23452        })
23453}
23454
23455pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23456    let mut prev_index = 0;
23457    let mut prev_codepoint: Option<char> = None;
23458    text.char_indices()
23459        .chain([(text.len(), '\0')])
23460        .filter_map(move |(index, codepoint)| {
23461            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23462            let is_boundary = index == text.len()
23463                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23464                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23465            if is_boundary {
23466                let chunk = &text[prev_index..index];
23467                prev_index = index;
23468                Some(chunk)
23469            } else {
23470                None
23471            }
23472        })
23473}
23474
23475pub trait RangeToAnchorExt: Sized {
23476    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23477
23478    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23479        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23480        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23481    }
23482}
23483
23484impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23485    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23486        let start_offset = self.start.to_offset(snapshot);
23487        let end_offset = self.end.to_offset(snapshot);
23488        if start_offset == end_offset {
23489            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23490        } else {
23491            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23492        }
23493    }
23494}
23495
23496pub trait RowExt {
23497    fn as_f32(&self) -> f32;
23498
23499    fn next_row(&self) -> Self;
23500
23501    fn previous_row(&self) -> Self;
23502
23503    fn minus(&self, other: Self) -> u32;
23504}
23505
23506impl RowExt for DisplayRow {
23507    fn as_f32(&self) -> f32 {
23508        self.0 as f32
23509    }
23510
23511    fn next_row(&self) -> Self {
23512        Self(self.0 + 1)
23513    }
23514
23515    fn previous_row(&self) -> Self {
23516        Self(self.0.saturating_sub(1))
23517    }
23518
23519    fn minus(&self, other: Self) -> u32 {
23520        self.0 - other.0
23521    }
23522}
23523
23524impl RowExt for MultiBufferRow {
23525    fn as_f32(&self) -> f32 {
23526        self.0 as f32
23527    }
23528
23529    fn next_row(&self) -> Self {
23530        Self(self.0 + 1)
23531    }
23532
23533    fn previous_row(&self) -> Self {
23534        Self(self.0.saturating_sub(1))
23535    }
23536
23537    fn minus(&self, other: Self) -> u32 {
23538        self.0 - other.0
23539    }
23540}
23541
23542trait RowRangeExt {
23543    type Row;
23544
23545    fn len(&self) -> usize;
23546
23547    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23548}
23549
23550impl RowRangeExt for Range<MultiBufferRow> {
23551    type Row = MultiBufferRow;
23552
23553    fn len(&self) -> usize {
23554        (self.end.0 - self.start.0) as usize
23555    }
23556
23557    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23558        (self.start.0..self.end.0).map(MultiBufferRow)
23559    }
23560}
23561
23562impl RowRangeExt for Range<DisplayRow> {
23563    type Row = DisplayRow;
23564
23565    fn len(&self) -> usize {
23566        (self.end.0 - self.start.0) as usize
23567    }
23568
23569    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23570        (self.start.0..self.end.0).map(DisplayRow)
23571    }
23572}
23573
23574/// If select range has more than one line, we
23575/// just point the cursor to range.start.
23576fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23577    if range.start.row == range.end.row {
23578        range
23579    } else {
23580        range.start..range.start
23581    }
23582}
23583pub struct KillRing(ClipboardItem);
23584impl Global for KillRing {}
23585
23586const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23587
23588enum BreakpointPromptEditAction {
23589    Log,
23590    Condition,
23591    HitCondition,
23592}
23593
23594struct BreakpointPromptEditor {
23595    pub(crate) prompt: Entity<Editor>,
23596    editor: WeakEntity<Editor>,
23597    breakpoint_anchor: Anchor,
23598    breakpoint: Breakpoint,
23599    edit_action: BreakpointPromptEditAction,
23600    block_ids: HashSet<CustomBlockId>,
23601    editor_margins: Arc<Mutex<EditorMargins>>,
23602    _subscriptions: Vec<Subscription>,
23603}
23604
23605impl BreakpointPromptEditor {
23606    const MAX_LINES: u8 = 4;
23607
23608    fn new(
23609        editor: WeakEntity<Editor>,
23610        breakpoint_anchor: Anchor,
23611        breakpoint: Breakpoint,
23612        edit_action: BreakpointPromptEditAction,
23613        window: &mut Window,
23614        cx: &mut Context<Self>,
23615    ) -> Self {
23616        let base_text = match edit_action {
23617            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23618            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23619            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23620        }
23621        .map(|msg| msg.to_string())
23622        .unwrap_or_default();
23623
23624        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23625        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23626
23627        let prompt = cx.new(|cx| {
23628            let mut prompt = Editor::new(
23629                EditorMode::AutoHeight {
23630                    min_lines: 1,
23631                    max_lines: Some(Self::MAX_LINES as usize),
23632                },
23633                buffer,
23634                None,
23635                window,
23636                cx,
23637            );
23638            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23639            prompt.set_show_cursor_when_unfocused(false, cx);
23640            prompt.set_placeholder_text(
23641                match edit_action {
23642                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23643                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23644                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23645                },
23646                cx,
23647            );
23648
23649            prompt
23650        });
23651
23652        Self {
23653            prompt,
23654            editor,
23655            breakpoint_anchor,
23656            breakpoint,
23657            edit_action,
23658            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23659            block_ids: Default::default(),
23660            _subscriptions: vec![],
23661        }
23662    }
23663
23664    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23665        self.block_ids.extend(block_ids)
23666    }
23667
23668    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23669        if let Some(editor) = self.editor.upgrade() {
23670            let message = self
23671                .prompt
23672                .read(cx)
23673                .buffer
23674                .read(cx)
23675                .as_singleton()
23676                .expect("A multi buffer in breakpoint prompt isn't possible")
23677                .read(cx)
23678                .as_rope()
23679                .to_string();
23680
23681            editor.update(cx, |editor, cx| {
23682                editor.edit_breakpoint_at_anchor(
23683                    self.breakpoint_anchor,
23684                    self.breakpoint.clone(),
23685                    match self.edit_action {
23686                        BreakpointPromptEditAction::Log => {
23687                            BreakpointEditAction::EditLogMessage(message.into())
23688                        }
23689                        BreakpointPromptEditAction::Condition => {
23690                            BreakpointEditAction::EditCondition(message.into())
23691                        }
23692                        BreakpointPromptEditAction::HitCondition => {
23693                            BreakpointEditAction::EditHitCondition(message.into())
23694                        }
23695                    },
23696                    cx,
23697                );
23698
23699                editor.remove_blocks(self.block_ids.clone(), None, cx);
23700                cx.focus_self(window);
23701            });
23702        }
23703    }
23704
23705    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23706        self.editor
23707            .update(cx, |editor, cx| {
23708                editor.remove_blocks(self.block_ids.clone(), None, cx);
23709                window.focus(&editor.focus_handle);
23710            })
23711            .log_err();
23712    }
23713
23714    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23715        let settings = ThemeSettings::get_global(cx);
23716        let text_style = TextStyle {
23717            color: if self.prompt.read(cx).read_only(cx) {
23718                cx.theme().colors().text_disabled
23719            } else {
23720                cx.theme().colors().text
23721            },
23722            font_family: settings.buffer_font.family.clone(),
23723            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23724            font_size: settings.buffer_font_size(cx).into(),
23725            font_weight: settings.buffer_font.weight,
23726            line_height: relative(settings.buffer_line_height.value()),
23727            ..Default::default()
23728        };
23729        EditorElement::new(
23730            &self.prompt,
23731            EditorStyle {
23732                background: cx.theme().colors().editor_background,
23733                local_player: cx.theme().players().local(),
23734                text: text_style,
23735                ..Default::default()
23736            },
23737        )
23738    }
23739}
23740
23741impl Render for BreakpointPromptEditor {
23742    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23743        let editor_margins = *self.editor_margins.lock();
23744        let gutter_dimensions = editor_margins.gutter;
23745        h_flex()
23746            .key_context("Editor")
23747            .bg(cx.theme().colors().editor_background)
23748            .border_y_1()
23749            .border_color(cx.theme().status().info_border)
23750            .size_full()
23751            .py(window.line_height() / 2.5)
23752            .on_action(cx.listener(Self::confirm))
23753            .on_action(cx.listener(Self::cancel))
23754            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23755            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23756    }
23757}
23758
23759impl Focusable for BreakpointPromptEditor {
23760    fn focus_handle(&self, cx: &App) -> FocusHandle {
23761        self.prompt.focus_handle(cx)
23762    }
23763}
23764
23765fn all_edits_insertions_or_deletions(
23766    edits: &Vec<(Range<Anchor>, String)>,
23767    snapshot: &MultiBufferSnapshot,
23768) -> bool {
23769    let mut all_insertions = true;
23770    let mut all_deletions = true;
23771
23772    for (range, new_text) in edits.iter() {
23773        let range_is_empty = range.to_offset(snapshot).is_empty();
23774        let text_is_empty = new_text.is_empty();
23775
23776        if range_is_empty != text_is_empty {
23777            if range_is_empty {
23778                all_deletions = false;
23779            } else {
23780                all_insertions = false;
23781            }
23782        } else {
23783            return false;
23784        }
23785
23786        if !all_insertions && !all_deletions {
23787            return false;
23788        }
23789    }
23790    all_insertions || all_deletions
23791}
23792
23793struct MissingEditPredictionKeybindingTooltip;
23794
23795impl Render for MissingEditPredictionKeybindingTooltip {
23796    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23797        ui::tooltip_container(window, cx, |container, _, cx| {
23798            container
23799                .flex_shrink_0()
23800                .max_w_80()
23801                .min_h(rems_from_px(124.))
23802                .justify_between()
23803                .child(
23804                    v_flex()
23805                        .flex_1()
23806                        .text_ui_sm(cx)
23807                        .child(Label::new("Conflict with Accept Keybinding"))
23808                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23809                )
23810                .child(
23811                    h_flex()
23812                        .pb_1()
23813                        .gap_1()
23814                        .items_end()
23815                        .w_full()
23816                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23817                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23818                        }))
23819                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23820                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23821                        })),
23822                )
23823        })
23824    }
23825}
23826
23827#[derive(Debug, Clone, Copy, PartialEq)]
23828pub struct LineHighlight {
23829    pub background: Background,
23830    pub border: Option<gpui::Hsla>,
23831    pub include_gutter: bool,
23832    pub type_id: Option<TypeId>,
23833}
23834
23835struct LineManipulationResult {
23836    pub new_text: String,
23837    pub line_count_before: usize,
23838    pub line_count_after: usize,
23839}
23840
23841fn render_diff_hunk_controls(
23842    row: u32,
23843    status: &DiffHunkStatus,
23844    hunk_range: Range<Anchor>,
23845    is_created_file: bool,
23846    line_height: Pixels,
23847    editor: &Entity<Editor>,
23848    _window: &mut Window,
23849    cx: &mut App,
23850) -> AnyElement {
23851    h_flex()
23852        .h(line_height)
23853        .mr_1()
23854        .gap_1()
23855        .px_0p5()
23856        .pb_1()
23857        .border_x_1()
23858        .border_b_1()
23859        .border_color(cx.theme().colors().border_variant)
23860        .rounded_b_lg()
23861        .bg(cx.theme().colors().editor_background)
23862        .gap_1()
23863        .block_mouse_except_scroll()
23864        .shadow_md()
23865        .child(if status.has_secondary_hunk() {
23866            Button::new(("stage", row as u64), "Stage")
23867                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23868                .tooltip({
23869                    let focus_handle = editor.focus_handle(cx);
23870                    move |window, cx| {
23871                        Tooltip::for_action_in(
23872                            "Stage Hunk",
23873                            &::git::ToggleStaged,
23874                            &focus_handle,
23875                            window,
23876                            cx,
23877                        )
23878                    }
23879                })
23880                .on_click({
23881                    let editor = editor.clone();
23882                    move |_event, _window, cx| {
23883                        editor.update(cx, |editor, cx| {
23884                            editor.stage_or_unstage_diff_hunks(
23885                                true,
23886                                vec![hunk_range.start..hunk_range.start],
23887                                cx,
23888                            );
23889                        });
23890                    }
23891                })
23892        } else {
23893            Button::new(("unstage", row as u64), "Unstage")
23894                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23895                .tooltip({
23896                    let focus_handle = editor.focus_handle(cx);
23897                    move |window, cx| {
23898                        Tooltip::for_action_in(
23899                            "Unstage Hunk",
23900                            &::git::ToggleStaged,
23901                            &focus_handle,
23902                            window,
23903                            cx,
23904                        )
23905                    }
23906                })
23907                .on_click({
23908                    let editor = editor.clone();
23909                    move |_event, _window, cx| {
23910                        editor.update(cx, |editor, cx| {
23911                            editor.stage_or_unstage_diff_hunks(
23912                                false,
23913                                vec![hunk_range.start..hunk_range.start],
23914                                cx,
23915                            );
23916                        });
23917                    }
23918                })
23919        })
23920        .child(
23921            Button::new(("restore", row as u64), "Restore")
23922                .tooltip({
23923                    let focus_handle = editor.focus_handle(cx);
23924                    move |window, cx| {
23925                        Tooltip::for_action_in(
23926                            "Restore Hunk",
23927                            &::git::Restore,
23928                            &focus_handle,
23929                            window,
23930                            cx,
23931                        )
23932                    }
23933                })
23934                .on_click({
23935                    let editor = editor.clone();
23936                    move |_event, window, cx| {
23937                        editor.update(cx, |editor, cx| {
23938                            let snapshot = editor.snapshot(window, cx);
23939                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23940                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23941                        });
23942                    }
23943                })
23944                .disabled(is_created_file),
23945        )
23946        .when(
23947            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23948            |el| {
23949                el.child(
23950                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23951                        .shape(IconButtonShape::Square)
23952                        .icon_size(IconSize::Small)
23953                        // .disabled(!has_multiple_hunks)
23954                        .tooltip({
23955                            let focus_handle = editor.focus_handle(cx);
23956                            move |window, cx| {
23957                                Tooltip::for_action_in(
23958                                    "Next Hunk",
23959                                    &GoToHunk,
23960                                    &focus_handle,
23961                                    window,
23962                                    cx,
23963                                )
23964                            }
23965                        })
23966                        .on_click({
23967                            let editor = editor.clone();
23968                            move |_event, window, cx| {
23969                                editor.update(cx, |editor, cx| {
23970                                    let snapshot = editor.snapshot(window, cx);
23971                                    let position =
23972                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23973                                    editor.go_to_hunk_before_or_after_position(
23974                                        &snapshot,
23975                                        position,
23976                                        Direction::Next,
23977                                        window,
23978                                        cx,
23979                                    );
23980                                    editor.expand_selected_diff_hunks(cx);
23981                                });
23982                            }
23983                        }),
23984                )
23985                .child(
23986                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23987                        .shape(IconButtonShape::Square)
23988                        .icon_size(IconSize::Small)
23989                        // .disabled(!has_multiple_hunks)
23990                        .tooltip({
23991                            let focus_handle = editor.focus_handle(cx);
23992                            move |window, cx| {
23993                                Tooltip::for_action_in(
23994                                    "Previous Hunk",
23995                                    &GoToPreviousHunk,
23996                                    &focus_handle,
23997                                    window,
23998                                    cx,
23999                                )
24000                            }
24001                        })
24002                        .on_click({
24003                            let editor = editor.clone();
24004                            move |_event, window, cx| {
24005                                editor.update(cx, |editor, cx| {
24006                                    let snapshot = editor.snapshot(window, cx);
24007                                    let point =
24008                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24009                                    editor.go_to_hunk_before_or_after_position(
24010                                        &snapshot,
24011                                        point,
24012                                        Direction::Prev,
24013                                        window,
24014                                        cx,
24015                                    );
24016                                    editor.expand_selected_diff_hunks(cx);
24017                                });
24018                            }
24019                        }),
24020                )
24021            },
24022        )
24023        .into_any_element()
24024}