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                },
 1905            ));
 1906            if let Some(task_inventory) = project
 1907                .read(cx)
 1908                .task_store()
 1909                .read(cx)
 1910                .task_inventory()
 1911                .cloned()
 1912            {
 1913                project_subscriptions.push(cx.observe_in(
 1914                    &task_inventory,
 1915                    window,
 1916                    |editor, _, window, cx| {
 1917                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1918                    },
 1919                ));
 1920            };
 1921
 1922            project_subscriptions.push(cx.subscribe_in(
 1923                &project.read(cx).breakpoint_store(),
 1924                window,
 1925                |editor, _, event, window, cx| match event {
 1926                    BreakpointStoreEvent::ClearDebugLines => {
 1927                        editor.clear_row_highlights::<ActiveDebugLine>();
 1928                        editor.refresh_inline_values(cx);
 1929                    }
 1930                    BreakpointStoreEvent::SetDebugLine => {
 1931                        if editor.go_to_active_debug_line(window, cx) {
 1932                            cx.stop_propagation();
 1933                        }
 1934
 1935                        editor.refresh_inline_values(cx);
 1936                    }
 1937                    _ => {}
 1938                },
 1939            ));
 1940            let git_store = project.read(cx).git_store().clone();
 1941            let project = project.clone();
 1942            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1943                if let GitStoreEvent::RepositoryUpdated(
 1944                    _,
 1945                    RepositoryEvent::Updated {
 1946                        new_instance: true, ..
 1947                    },
 1948                    _,
 1949                ) = event
 1950                {
 1951                    this.load_diff_task = Some(
 1952                        update_uncommitted_diff_for_buffer(
 1953                            cx.entity(),
 1954                            &project,
 1955                            this.buffer.read(cx).all_buffers(),
 1956                            this.buffer.clone(),
 1957                            cx,
 1958                        )
 1959                        .shared(),
 1960                    );
 1961                }
 1962            }));
 1963        }
 1964
 1965        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1966
 1967        let inlay_hint_settings =
 1968            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1969        let focus_handle = cx.focus_handle();
 1970        if !is_minimap {
 1971            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1972                .detach();
 1973            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1974                .detach();
 1975            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1976                .detach();
 1977            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1978                .detach();
 1979            cx.observe_pending_input(window, Self::observe_pending_input)
 1980                .detach();
 1981        }
 1982
 1983        let show_indent_guides =
 1984            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 1985                Some(false)
 1986            } else {
 1987                None
 1988            };
 1989
 1990        let breakpoint_store = match (&mode, project.as_ref()) {
 1991            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1992            _ => None,
 1993        };
 1994
 1995        let mut code_action_providers = Vec::new();
 1996        let mut load_uncommitted_diff = None;
 1997        if let Some(project) = project.clone() {
 1998            load_uncommitted_diff = Some(
 1999                update_uncommitted_diff_for_buffer(
 2000                    cx.entity(),
 2001                    &project,
 2002                    buffer.read(cx).all_buffers(),
 2003                    buffer.clone(),
 2004                    cx,
 2005                )
 2006                .shared(),
 2007            );
 2008            code_action_providers.push(Rc::new(project) as Rc<_>);
 2009        }
 2010
 2011        let mut editor = Self {
 2012            focus_handle,
 2013            show_cursor_when_unfocused: false,
 2014            last_focused_descendant: None,
 2015            buffer: buffer.clone(),
 2016            display_map: display_map.clone(),
 2017            selections,
 2018            scroll_manager: ScrollManager::new(cx),
 2019            columnar_selection_state: None,
 2020            add_selections_state: None,
 2021            select_next_state: None,
 2022            select_prev_state: None,
 2023            selection_history: SelectionHistory::default(),
 2024            defer_selection_effects: false,
 2025            deferred_selection_effects_state: None,
 2026            autoclose_regions: Vec::new(),
 2027            snippet_stack: InvalidationStack::default(),
 2028            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2029            ime_transaction: None,
 2030            active_diagnostics: ActiveDiagnostic::None,
 2031            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2032            inline_diagnostics_update: Task::ready(()),
 2033            inline_diagnostics: Vec::new(),
 2034            soft_wrap_mode_override,
 2035            diagnostics_max_severity,
 2036            hard_wrap: None,
 2037            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2038            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2039            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2040            project,
 2041            blink_manager: blink_manager.clone(),
 2042            show_local_selections: true,
 2043            show_scrollbars: ScrollbarAxes {
 2044                horizontal: full_mode,
 2045                vertical: full_mode,
 2046            },
 2047            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2048            offset_content: !matches!(mode, EditorMode::SingleLine),
 2049            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2050            show_gutter: full_mode,
 2051            show_line_numbers: (!full_mode).then_some(false),
 2052            use_relative_line_numbers: None,
 2053            disable_expand_excerpt_buttons: !full_mode,
 2054            show_git_diff_gutter: None,
 2055            show_code_actions: None,
 2056            show_runnables: None,
 2057            show_breakpoints: None,
 2058            show_wrap_guides: None,
 2059            show_indent_guides,
 2060            placeholder_text: None,
 2061            highlight_order: 0,
 2062            highlighted_rows: HashMap::default(),
 2063            background_highlights: TreeMap::default(),
 2064            gutter_highlights: TreeMap::default(),
 2065            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2066            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2067            nav_history: None,
 2068            context_menu: RefCell::new(None),
 2069            context_menu_options: None,
 2070            mouse_context_menu: None,
 2071            completion_tasks: Vec::new(),
 2072            inline_blame_popover: None,
 2073            inline_blame_popover_show_task: None,
 2074            signature_help_state: SignatureHelpState::default(),
 2075            auto_signature_help: None,
 2076            find_all_references_task_sources: Vec::new(),
 2077            next_completion_id: 0,
 2078            next_inlay_id: 0,
 2079            code_action_providers,
 2080            available_code_actions: None,
 2081            code_actions_task: None,
 2082            quick_selection_highlight_task: None,
 2083            debounced_selection_highlight_task: None,
 2084            document_highlights_task: None,
 2085            linked_editing_range_task: None,
 2086            pending_rename: None,
 2087            searchable: !is_minimap,
 2088            cursor_shape: EditorSettings::get_global(cx)
 2089                .cursor_shape
 2090                .unwrap_or_default(),
 2091            current_line_highlight: None,
 2092            autoindent_mode: Some(AutoindentMode::EachLine),
 2093            collapse_matches: false,
 2094            workspace: None,
 2095            input_enabled: !is_minimap,
 2096            use_modal_editing: full_mode,
 2097            read_only: is_minimap,
 2098            use_autoclose: true,
 2099            use_auto_surround: true,
 2100            auto_replace_emoji_shortcode: false,
 2101            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2102            leader_id: None,
 2103            remote_id: None,
 2104            hover_state: HoverState::default(),
 2105            pending_mouse_down: None,
 2106            hovered_link_state: None,
 2107            edit_prediction_provider: None,
 2108            active_edit_prediction: None,
 2109            stale_edit_prediction_in_menu: None,
 2110            edit_prediction_preview: EditPredictionPreview::Inactive {
 2111                released_too_fast: false,
 2112            },
 2113            inline_diagnostics_enabled: full_mode,
 2114            diagnostics_enabled: full_mode,
 2115            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2116            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2117            gutter_hovered: false,
 2118            pixel_position_of_newest_cursor: None,
 2119            last_bounds: None,
 2120            last_position_map: None,
 2121            expect_bounds_change: None,
 2122            gutter_dimensions: GutterDimensions::default(),
 2123            style: None,
 2124            show_cursor_names: false,
 2125            hovered_cursors: HashMap::default(),
 2126            next_editor_action_id: EditorActionId::default(),
 2127            editor_actions: Rc::default(),
 2128            edit_predictions_hidden_for_vim_mode: false,
 2129            show_edit_predictions_override: None,
 2130            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2131            edit_prediction_settings: EditPredictionSettings::Disabled,
 2132            edit_prediction_indent_conflict: false,
 2133            edit_prediction_requires_modifier_in_indent_conflict: true,
 2134            custom_context_menu: None,
 2135            show_git_blame_gutter: false,
 2136            show_git_blame_inline: false,
 2137            show_selection_menu: None,
 2138            show_git_blame_inline_delay_task: None,
 2139            git_blame_inline_enabled: full_mode
 2140                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2141            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2142            serialize_dirty_buffers: !is_minimap
 2143                && ProjectSettings::get_global(cx)
 2144                    .session
 2145                    .restore_unsaved_buffers,
 2146            blame: None,
 2147            blame_subscription: None,
 2148            tasks: BTreeMap::default(),
 2149
 2150            breakpoint_store,
 2151            gutter_breakpoint_indicator: (None, None),
 2152            hovered_diff_hunk_row: None,
 2153            _subscriptions: (!is_minimap)
 2154                .then(|| {
 2155                    vec![
 2156                        cx.observe(&buffer, Self::on_buffer_changed),
 2157                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2158                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2159                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2160                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2161                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2162                        cx.observe_window_activation(window, |editor, window, cx| {
 2163                            let active = window.is_window_active();
 2164                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2165                                if active {
 2166                                    blink_manager.enable(cx);
 2167                                } else {
 2168                                    blink_manager.disable(cx);
 2169                                }
 2170                            });
 2171                            if active {
 2172                                editor.show_mouse_cursor(cx);
 2173                            }
 2174                        }),
 2175                    ]
 2176                })
 2177                .unwrap_or_default(),
 2178            tasks_update_task: None,
 2179            pull_diagnostics_task: Task::ready(()),
 2180            colors: None,
 2181            next_color_inlay_id: 0,
 2182            linked_edit_ranges: Default::default(),
 2183            in_project_search: false,
 2184            previous_search_ranges: None,
 2185            breadcrumb_header: None,
 2186            focused_block: None,
 2187            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2188            addons: HashMap::default(),
 2189            registered_buffers: HashMap::default(),
 2190            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2191            selection_mark_mode: false,
 2192            toggle_fold_multiple_buffers: Task::ready(()),
 2193            serialize_selections: Task::ready(()),
 2194            serialize_folds: Task::ready(()),
 2195            text_style_refinement: None,
 2196            load_diff_task: load_uncommitted_diff,
 2197            temporary_diff_override: false,
 2198            mouse_cursor_hidden: false,
 2199            minimap: None,
 2200            hide_mouse_mode: EditorSettings::get_global(cx)
 2201                .hide_mouse
 2202                .unwrap_or_default(),
 2203            change_list: ChangeList::new(),
 2204            mode,
 2205            selection_drag_state: SelectionDragState::None,
 2206            folding_newlines: Task::ready(()),
 2207        };
 2208
 2209        if is_minimap {
 2210            return editor;
 2211        }
 2212
 2213        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2214            editor
 2215                ._subscriptions
 2216                .push(cx.observe(breakpoints, |_, _, cx| {
 2217                    cx.notify();
 2218                }));
 2219        }
 2220        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2221        editor._subscriptions.extend(project_subscriptions);
 2222
 2223        editor._subscriptions.push(cx.subscribe_in(
 2224            &cx.entity(),
 2225            window,
 2226            |editor, _, e: &EditorEvent, window, cx| match e {
 2227                EditorEvent::ScrollPositionChanged { local, .. } => {
 2228                    if *local {
 2229                        let new_anchor = editor.scroll_manager.anchor();
 2230                        let snapshot = editor.snapshot(window, cx);
 2231                        editor.update_restoration_data(cx, move |data| {
 2232                            data.scroll_position = (
 2233                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2234                                new_anchor.offset,
 2235                            );
 2236                        });
 2237                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2238                        editor.inline_blame_popover.take();
 2239                    }
 2240                }
 2241                EditorEvent::Edited { .. } => {
 2242                    if !vim_enabled(cx) {
 2243                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2244                        let pop_state = editor
 2245                            .change_list
 2246                            .last()
 2247                            .map(|previous| {
 2248                                previous.len() == selections.len()
 2249                                    && previous.iter().enumerate().all(|(ix, p)| {
 2250                                        p.to_display_point(&map).row()
 2251                                            == selections[ix].head().row()
 2252                                    })
 2253                            })
 2254                            .unwrap_or(false);
 2255                        let new_positions = selections
 2256                            .into_iter()
 2257                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2258                            .collect();
 2259                        editor
 2260                            .change_list
 2261                            .push_to_change_list(pop_state, new_positions);
 2262                    }
 2263                }
 2264                _ => (),
 2265            },
 2266        ));
 2267
 2268        if let Some(dap_store) = editor
 2269            .project
 2270            .as_ref()
 2271            .map(|project| project.read(cx).dap_store())
 2272        {
 2273            let weak_editor = cx.weak_entity();
 2274
 2275            editor
 2276                ._subscriptions
 2277                .push(
 2278                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2279                        let session_entity = cx.entity();
 2280                        weak_editor
 2281                            .update(cx, |editor, cx| {
 2282                                editor._subscriptions.push(
 2283                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2284                                );
 2285                            })
 2286                            .ok();
 2287                    }),
 2288                );
 2289
 2290            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2291                editor
 2292                    ._subscriptions
 2293                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2294            }
 2295        }
 2296
 2297        // skip adding the initial selection to selection history
 2298        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2299        editor.end_selection(window, cx);
 2300        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2301
 2302        editor.scroll_manager.show_scrollbars(window, cx);
 2303        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2304
 2305        if full_mode {
 2306            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2307            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2308
 2309            if editor.git_blame_inline_enabled {
 2310                editor.start_git_blame_inline(false, window, cx);
 2311            }
 2312
 2313            editor.go_to_active_debug_line(window, cx);
 2314
 2315            if let Some(buffer) = buffer.read(cx).as_singleton()
 2316                && let Some(project) = editor.project()
 2317            {
 2318                let handle = project.update(cx, |project, cx| {
 2319                    project.register_buffer_with_language_servers(&buffer, cx)
 2320                });
 2321                editor
 2322                    .registered_buffers
 2323                    .insert(buffer.read(cx).remote_id(), handle);
 2324            }
 2325
 2326            editor.minimap =
 2327                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2328            editor.colors = Some(LspColorData::new(cx));
 2329            editor.update_lsp_data(false, None, window, cx);
 2330        }
 2331
 2332        if editor.mode.is_full() {
 2333            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2334        }
 2335
 2336        editor
 2337    }
 2338
 2339    pub fn deploy_mouse_context_menu(
 2340        &mut self,
 2341        position: gpui::Point<Pixels>,
 2342        context_menu: Entity<ContextMenu>,
 2343        window: &mut Window,
 2344        cx: &mut Context<Self>,
 2345    ) {
 2346        self.mouse_context_menu = Some(MouseContextMenu::new(
 2347            self,
 2348            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2349            context_menu,
 2350            window,
 2351            cx,
 2352        ));
 2353    }
 2354
 2355    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2356        self.mouse_context_menu
 2357            .as_ref()
 2358            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2359    }
 2360
 2361    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2362        if self
 2363            .selections
 2364            .pending
 2365            .as_ref()
 2366            .is_some_and(|pending_selection| {
 2367                let snapshot = self.buffer().read(cx).snapshot(cx);
 2368                pending_selection
 2369                    .selection
 2370                    .range()
 2371                    .includes(range, &snapshot)
 2372            })
 2373        {
 2374            return true;
 2375        }
 2376
 2377        self.selections
 2378            .disjoint_in_range::<usize>(range.clone(), cx)
 2379            .into_iter()
 2380            .any(|selection| {
 2381                // This is needed to cover a corner case, if we just check for an existing
 2382                // selection in the fold range, having a cursor at the start of the fold
 2383                // marks it as selected. Non-empty selections don't cause this.
 2384                let length = selection.end - selection.start;
 2385                length > 0
 2386            })
 2387    }
 2388
 2389    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2390        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2391    }
 2392
 2393    fn key_context_internal(
 2394        &self,
 2395        has_active_edit_prediction: bool,
 2396        window: &Window,
 2397        cx: &App,
 2398    ) -> KeyContext {
 2399        let mut key_context = KeyContext::new_with_defaults();
 2400        key_context.add("Editor");
 2401        let mode = match self.mode {
 2402            EditorMode::SingleLine => "single_line",
 2403            EditorMode::AutoHeight { .. } => "auto_height",
 2404            EditorMode::Minimap { .. } => "minimap",
 2405            EditorMode::Full { .. } => "full",
 2406        };
 2407
 2408        if EditorSettings::jupyter_enabled(cx) {
 2409            key_context.add("jupyter");
 2410        }
 2411
 2412        key_context.set("mode", mode);
 2413        if self.pending_rename.is_some() {
 2414            key_context.add("renaming");
 2415        }
 2416
 2417        match self.context_menu.borrow().as_ref() {
 2418            Some(CodeContextMenu::Completions(menu)) => {
 2419                if menu.visible() {
 2420                    key_context.add("menu");
 2421                    key_context.add("showing_completions");
 2422                }
 2423            }
 2424            Some(CodeContextMenu::CodeActions(menu)) => {
 2425                if menu.visible() {
 2426                    key_context.add("menu");
 2427                    key_context.add("showing_code_actions")
 2428                }
 2429            }
 2430            None => {}
 2431        }
 2432
 2433        if self.signature_help_state.has_multiple_signatures() {
 2434            key_context.add("showing_signature_help");
 2435        }
 2436
 2437        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2438        if !self.focus_handle(cx).contains_focused(window, cx)
 2439            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2440        {
 2441            for addon in self.addons.values() {
 2442                addon.extend_key_context(&mut key_context, cx)
 2443            }
 2444        }
 2445
 2446        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2447            if let Some(extension) = singleton_buffer
 2448                .read(cx)
 2449                .file()
 2450                .and_then(|file| file.path().extension()?.to_str())
 2451            {
 2452                key_context.set("extension", extension.to_string());
 2453            }
 2454        } else {
 2455            key_context.add("multibuffer");
 2456        }
 2457
 2458        if has_active_edit_prediction {
 2459            if self.edit_prediction_in_conflict() {
 2460                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2461            } else {
 2462                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2463                key_context.add("copilot_suggestion");
 2464            }
 2465        }
 2466
 2467        if self.selection_mark_mode {
 2468            key_context.add("selection_mode");
 2469        }
 2470
 2471        key_context
 2472    }
 2473
 2474    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2475        if self.mouse_cursor_hidden {
 2476            self.mouse_cursor_hidden = false;
 2477            cx.notify();
 2478        }
 2479    }
 2480
 2481    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2482        let hide_mouse_cursor = match origin {
 2483            HideMouseCursorOrigin::TypingAction => {
 2484                matches!(
 2485                    self.hide_mouse_mode,
 2486                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2487                )
 2488            }
 2489            HideMouseCursorOrigin::MovementAction => {
 2490                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2491            }
 2492        };
 2493        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2494            self.mouse_cursor_hidden = hide_mouse_cursor;
 2495            cx.notify();
 2496        }
 2497    }
 2498
 2499    pub fn edit_prediction_in_conflict(&self) -> bool {
 2500        if !self.show_edit_predictions_in_menu() {
 2501            return false;
 2502        }
 2503
 2504        let showing_completions = self
 2505            .context_menu
 2506            .borrow()
 2507            .as_ref()
 2508            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2509
 2510        showing_completions
 2511            || self.edit_prediction_requires_modifier()
 2512            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2513            // bindings to insert tab characters.
 2514            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2515    }
 2516
 2517    pub fn accept_edit_prediction_keybind(
 2518        &self,
 2519        accept_partial: bool,
 2520        window: &Window,
 2521        cx: &App,
 2522    ) -> AcceptEditPredictionBinding {
 2523        let key_context = self.key_context_internal(true, window, cx);
 2524        let in_conflict = self.edit_prediction_in_conflict();
 2525
 2526        let bindings = if accept_partial {
 2527            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2528        } else {
 2529            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2530        };
 2531
 2532        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2533        // just the first one.
 2534        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2535            !in_conflict
 2536                || binding
 2537                    .keystrokes()
 2538                    .first()
 2539                    .is_some_and(|keystroke| keystroke.modifiers.modified())
 2540        }))
 2541    }
 2542
 2543    pub fn new_file(
 2544        workspace: &mut Workspace,
 2545        _: &workspace::NewFile,
 2546        window: &mut Window,
 2547        cx: &mut Context<Workspace>,
 2548    ) {
 2549        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2550            "Failed to create buffer",
 2551            window,
 2552            cx,
 2553            |e, _, _| match e.error_code() {
 2554                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2555                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2556                e.error_tag("required").unwrap_or("the latest version")
 2557            )),
 2558                _ => None,
 2559            },
 2560        );
 2561    }
 2562
 2563    pub fn new_in_workspace(
 2564        workspace: &mut Workspace,
 2565        window: &mut Window,
 2566        cx: &mut Context<Workspace>,
 2567    ) -> Task<Result<Entity<Editor>>> {
 2568        let project = workspace.project().clone();
 2569        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2570
 2571        cx.spawn_in(window, async move |workspace, cx| {
 2572            let buffer = create.await?;
 2573            workspace.update_in(cx, |workspace, window, cx| {
 2574                let editor =
 2575                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2576                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2577                editor
 2578            })
 2579        })
 2580    }
 2581
 2582    fn new_file_vertical(
 2583        workspace: &mut Workspace,
 2584        _: &workspace::NewFileSplitVertical,
 2585        window: &mut Window,
 2586        cx: &mut Context<Workspace>,
 2587    ) {
 2588        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2589    }
 2590
 2591    fn new_file_horizontal(
 2592        workspace: &mut Workspace,
 2593        _: &workspace::NewFileSplitHorizontal,
 2594        window: &mut Window,
 2595        cx: &mut Context<Workspace>,
 2596    ) {
 2597        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2598    }
 2599
 2600    fn new_file_in_direction(
 2601        workspace: &mut Workspace,
 2602        direction: SplitDirection,
 2603        window: &mut Window,
 2604        cx: &mut Context<Workspace>,
 2605    ) {
 2606        let project = workspace.project().clone();
 2607        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2608
 2609        cx.spawn_in(window, async move |workspace, cx| {
 2610            let buffer = create.await?;
 2611            workspace.update_in(cx, move |workspace, window, cx| {
 2612                workspace.split_item(
 2613                    direction,
 2614                    Box::new(
 2615                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2616                    ),
 2617                    window,
 2618                    cx,
 2619                )
 2620            })?;
 2621            anyhow::Ok(())
 2622        })
 2623        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2624            match e.error_code() {
 2625                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2626                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2627                e.error_tag("required").unwrap_or("the latest version")
 2628            )),
 2629                _ => None,
 2630            }
 2631        });
 2632    }
 2633
 2634    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2635        self.leader_id
 2636    }
 2637
 2638    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2639        &self.buffer
 2640    }
 2641
 2642    pub fn project(&self) -> Option<&Entity<Project>> {
 2643        self.project.as_ref()
 2644    }
 2645
 2646    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2647        self.workspace.as_ref()?.0.upgrade()
 2648    }
 2649
 2650    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2651        self.buffer().read(cx).title(cx)
 2652    }
 2653
 2654    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2655        let git_blame_gutter_max_author_length = self
 2656            .render_git_blame_gutter(cx)
 2657            .then(|| {
 2658                if let Some(blame) = self.blame.as_ref() {
 2659                    let max_author_length =
 2660                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2661                    Some(max_author_length)
 2662                } else {
 2663                    None
 2664                }
 2665            })
 2666            .flatten();
 2667
 2668        EditorSnapshot {
 2669            mode: self.mode.clone(),
 2670            show_gutter: self.show_gutter,
 2671            show_line_numbers: self.show_line_numbers,
 2672            show_git_diff_gutter: self.show_git_diff_gutter,
 2673            show_code_actions: self.show_code_actions,
 2674            show_runnables: self.show_runnables,
 2675            show_breakpoints: self.show_breakpoints,
 2676            git_blame_gutter_max_author_length,
 2677            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2678            scroll_anchor: self.scroll_manager.anchor(),
 2679            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2680            placeholder_text: self.placeholder_text.clone(),
 2681            is_focused: self.focus_handle.is_focused(window),
 2682            current_line_highlight: self
 2683                .current_line_highlight
 2684                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2685            gutter_hovered: self.gutter_hovered,
 2686        }
 2687    }
 2688
 2689    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2690        self.buffer.read(cx).language_at(point, cx)
 2691    }
 2692
 2693    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2694        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2695    }
 2696
 2697    pub fn active_excerpt(
 2698        &self,
 2699        cx: &App,
 2700    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2701        self.buffer
 2702            .read(cx)
 2703            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2704    }
 2705
 2706    pub fn mode(&self) -> &EditorMode {
 2707        &self.mode
 2708    }
 2709
 2710    pub fn set_mode(&mut self, mode: EditorMode) {
 2711        self.mode = mode;
 2712    }
 2713
 2714    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2715        self.collaboration_hub.as_deref()
 2716    }
 2717
 2718    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2719        self.collaboration_hub = Some(hub);
 2720    }
 2721
 2722    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2723        self.in_project_search = in_project_search;
 2724    }
 2725
 2726    pub fn set_custom_context_menu(
 2727        &mut self,
 2728        f: impl 'static
 2729        + Fn(
 2730            &mut Self,
 2731            DisplayPoint,
 2732            &mut Window,
 2733            &mut Context<Self>,
 2734        ) -> Option<Entity<ui::ContextMenu>>,
 2735    ) {
 2736        self.custom_context_menu = Some(Box::new(f))
 2737    }
 2738
 2739    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2740        self.completion_provider = provider;
 2741    }
 2742
 2743    #[cfg(any(test, feature = "test-support"))]
 2744    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2745        self.completion_provider.clone()
 2746    }
 2747
 2748    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2749        self.semantics_provider.clone()
 2750    }
 2751
 2752    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2753        self.semantics_provider = provider;
 2754    }
 2755
 2756    pub fn set_edit_prediction_provider<T>(
 2757        &mut self,
 2758        provider: Option<Entity<T>>,
 2759        window: &mut Window,
 2760        cx: &mut Context<Self>,
 2761    ) where
 2762        T: EditPredictionProvider,
 2763    {
 2764        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2765            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2766                if this.focus_handle.is_focused(window) {
 2767                    this.update_visible_edit_prediction(window, cx);
 2768                }
 2769            }),
 2770            provider: Arc::new(provider),
 2771        });
 2772        self.update_edit_prediction_settings(cx);
 2773        self.refresh_edit_prediction(false, false, window, cx);
 2774    }
 2775
 2776    pub fn placeholder_text(&self) -> Option<&str> {
 2777        self.placeholder_text.as_deref()
 2778    }
 2779
 2780    pub fn set_placeholder_text(
 2781        &mut self,
 2782        placeholder_text: impl Into<Arc<str>>,
 2783        cx: &mut Context<Self>,
 2784    ) {
 2785        let placeholder_text = Some(placeholder_text.into());
 2786        if self.placeholder_text != placeholder_text {
 2787            self.placeholder_text = placeholder_text;
 2788            cx.notify();
 2789        }
 2790    }
 2791
 2792    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2793        self.cursor_shape = cursor_shape;
 2794
 2795        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2796        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2797
 2798        cx.notify();
 2799    }
 2800
 2801    pub fn set_current_line_highlight(
 2802        &mut self,
 2803        current_line_highlight: Option<CurrentLineHighlight>,
 2804    ) {
 2805        self.current_line_highlight = current_line_highlight;
 2806    }
 2807
 2808    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2809        self.collapse_matches = collapse_matches;
 2810    }
 2811
 2812    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2813        let buffers = self.buffer.read(cx).all_buffers();
 2814        let Some(project) = self.project.as_ref() else {
 2815            return;
 2816        };
 2817        project.update(cx, |project, cx| {
 2818            for buffer in buffers {
 2819                self.registered_buffers
 2820                    .entry(buffer.read(cx).remote_id())
 2821                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2822            }
 2823        })
 2824    }
 2825
 2826    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2827        if self.collapse_matches {
 2828            return range.start..range.start;
 2829        }
 2830        range.clone()
 2831    }
 2832
 2833    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2834        if self.display_map.read(cx).clip_at_line_ends != clip {
 2835            self.display_map
 2836                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2837        }
 2838    }
 2839
 2840    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2841        self.input_enabled = input_enabled;
 2842    }
 2843
 2844    pub fn set_edit_predictions_hidden_for_vim_mode(
 2845        &mut self,
 2846        hidden: bool,
 2847        window: &mut Window,
 2848        cx: &mut Context<Self>,
 2849    ) {
 2850        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2851            self.edit_predictions_hidden_for_vim_mode = hidden;
 2852            if hidden {
 2853                self.update_visible_edit_prediction(window, cx);
 2854            } else {
 2855                self.refresh_edit_prediction(true, false, window, cx);
 2856            }
 2857        }
 2858    }
 2859
 2860    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2861        self.menu_edit_predictions_policy = value;
 2862    }
 2863
 2864    pub fn set_autoindent(&mut self, autoindent: bool) {
 2865        if autoindent {
 2866            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2867        } else {
 2868            self.autoindent_mode = None;
 2869        }
 2870    }
 2871
 2872    pub fn read_only(&self, cx: &App) -> bool {
 2873        self.read_only || self.buffer.read(cx).read_only()
 2874    }
 2875
 2876    pub fn set_read_only(&mut self, read_only: bool) {
 2877        self.read_only = read_only;
 2878    }
 2879
 2880    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2881        self.use_autoclose = autoclose;
 2882    }
 2883
 2884    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2885        self.use_auto_surround = auto_surround;
 2886    }
 2887
 2888    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2889        self.auto_replace_emoji_shortcode = auto_replace;
 2890    }
 2891
 2892    pub fn toggle_edit_predictions(
 2893        &mut self,
 2894        _: &ToggleEditPrediction,
 2895        window: &mut Window,
 2896        cx: &mut Context<Self>,
 2897    ) {
 2898        if self.show_edit_predictions_override.is_some() {
 2899            self.set_show_edit_predictions(None, window, cx);
 2900        } else {
 2901            let show_edit_predictions = !self.edit_predictions_enabled();
 2902            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2903        }
 2904    }
 2905
 2906    pub fn set_show_edit_predictions(
 2907        &mut self,
 2908        show_edit_predictions: Option<bool>,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911    ) {
 2912        self.show_edit_predictions_override = show_edit_predictions;
 2913        self.update_edit_prediction_settings(cx);
 2914
 2915        if let Some(false) = show_edit_predictions {
 2916            self.discard_edit_prediction(false, cx);
 2917        } else {
 2918            self.refresh_edit_prediction(false, true, window, cx);
 2919        }
 2920    }
 2921
 2922    fn edit_predictions_disabled_in_scope(
 2923        &self,
 2924        buffer: &Entity<Buffer>,
 2925        buffer_position: language::Anchor,
 2926        cx: &App,
 2927    ) -> bool {
 2928        let snapshot = buffer.read(cx).snapshot();
 2929        let settings = snapshot.settings_at(buffer_position, cx);
 2930
 2931        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2932            return false;
 2933        };
 2934
 2935        scope.override_name().is_some_and(|scope_name| {
 2936            settings
 2937                .edit_predictions_disabled_in
 2938                .iter()
 2939                .any(|s| s == scope_name)
 2940        })
 2941    }
 2942
 2943    pub fn set_use_modal_editing(&mut self, to: bool) {
 2944        self.use_modal_editing = to;
 2945    }
 2946
 2947    pub fn use_modal_editing(&self) -> bool {
 2948        self.use_modal_editing
 2949    }
 2950
 2951    fn selections_did_change(
 2952        &mut self,
 2953        local: bool,
 2954        old_cursor_position: &Anchor,
 2955        effects: SelectionEffects,
 2956        window: &mut Window,
 2957        cx: &mut Context<Self>,
 2958    ) {
 2959        window.invalidate_character_coordinates();
 2960
 2961        // Copy selections to primary selection buffer
 2962        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2963        if local {
 2964            let selections = self.selections.all::<usize>(cx);
 2965            let buffer_handle = self.buffer.read(cx).read(cx);
 2966
 2967            let mut text = String::new();
 2968            for (index, selection) in selections.iter().enumerate() {
 2969                let text_for_selection = buffer_handle
 2970                    .text_for_range(selection.start..selection.end)
 2971                    .collect::<String>();
 2972
 2973                text.push_str(&text_for_selection);
 2974                if index != selections.len() - 1 {
 2975                    text.push('\n');
 2976                }
 2977            }
 2978
 2979            if !text.is_empty() {
 2980                cx.write_to_primary(ClipboardItem::new_string(text));
 2981            }
 2982        }
 2983
 2984        let selection_anchors = self.selections.disjoint_anchors();
 2985
 2986        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2987            self.buffer.update(cx, |buffer, cx| {
 2988                buffer.set_active_selections(
 2989                    &selection_anchors,
 2990                    self.selections.line_mode,
 2991                    self.cursor_shape,
 2992                    cx,
 2993                )
 2994            });
 2995        }
 2996        let display_map = self
 2997            .display_map
 2998            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2999        let buffer = &display_map.buffer_snapshot;
 3000        if self.selections.count() == 1 {
 3001            self.add_selections_state = None;
 3002        }
 3003        self.select_next_state = None;
 3004        self.select_prev_state = None;
 3005        self.select_syntax_node_history.try_clear();
 3006        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3007        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3008        self.take_rename(false, window, cx);
 3009
 3010        let newest_selection = self.selections.newest_anchor();
 3011        let new_cursor_position = newest_selection.head();
 3012        let selection_start = newest_selection.start;
 3013
 3014        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3015            self.push_to_nav_history(
 3016                *old_cursor_position,
 3017                Some(new_cursor_position.to_point(buffer)),
 3018                false,
 3019                effects.nav_history == Some(true),
 3020                cx,
 3021            );
 3022        }
 3023
 3024        if local {
 3025            if let Some(buffer_id) = new_cursor_position.buffer_id
 3026                && !self.registered_buffers.contains_key(&buffer_id)
 3027                && let Some(project) = self.project.as_ref()
 3028            {
 3029                project.update(cx, |project, cx| {
 3030                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3031                        return;
 3032                    };
 3033                    self.registered_buffers.insert(
 3034                        buffer_id,
 3035                        project.register_buffer_with_language_servers(&buffer, cx),
 3036                    );
 3037                })
 3038            }
 3039
 3040            let mut context_menu = self.context_menu.borrow_mut();
 3041            let completion_menu = match context_menu.as_ref() {
 3042                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3043                Some(CodeContextMenu::CodeActions(_)) => {
 3044                    *context_menu = None;
 3045                    None
 3046                }
 3047                None => None,
 3048            };
 3049            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3050            drop(context_menu);
 3051
 3052            if effects.completions
 3053                && let Some(completion_position) = completion_position
 3054            {
 3055                let start_offset = selection_start.to_offset(buffer);
 3056                let position_matches = start_offset == completion_position.to_offset(buffer);
 3057                let continue_showing = if position_matches {
 3058                    if self.snippet_stack.is_empty() {
 3059                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3060                    } else {
 3061                        // Snippet choices can be shown even when the cursor is in whitespace.
 3062                        // Dismissing the menu with actions like backspace is handled by
 3063                        // invalidation regions.
 3064                        true
 3065                    }
 3066                } else {
 3067                    false
 3068                };
 3069
 3070                if continue_showing {
 3071                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3072                } else {
 3073                    self.hide_context_menu(window, cx);
 3074                }
 3075            }
 3076
 3077            hide_hover(self, cx);
 3078
 3079            if old_cursor_position.to_display_point(&display_map).row()
 3080                != new_cursor_position.to_display_point(&display_map).row()
 3081            {
 3082                self.available_code_actions.take();
 3083            }
 3084            self.refresh_code_actions(window, cx);
 3085            self.refresh_document_highlights(cx);
 3086            self.refresh_selected_text_highlights(false, window, cx);
 3087            refresh_matching_bracket_highlights(self, window, cx);
 3088            self.update_visible_edit_prediction(window, cx);
 3089            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3090            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3091            self.inline_blame_popover.take();
 3092            if self.git_blame_inline_enabled {
 3093                self.start_inline_blame_timer(window, cx);
 3094            }
 3095        }
 3096
 3097        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3098        cx.emit(EditorEvent::SelectionsChanged { local });
 3099
 3100        let selections = &self.selections.disjoint;
 3101        if selections.len() == 1 {
 3102            cx.emit(SearchEvent::ActiveMatchChanged)
 3103        }
 3104        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3105            let inmemory_selections = selections
 3106                .iter()
 3107                .map(|s| {
 3108                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3109                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3110                })
 3111                .collect();
 3112            self.update_restoration_data(cx, |data| {
 3113                data.selections = inmemory_selections;
 3114            });
 3115
 3116            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3117                && let Some(workspace_id) =
 3118                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3119            {
 3120                let snapshot = self.buffer().read(cx).snapshot(cx);
 3121                let selections = selections.clone();
 3122                let background_executor = cx.background_executor().clone();
 3123                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3124                self.serialize_selections = cx.background_spawn(async move {
 3125                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3126                            let db_selections = selections
 3127                                .iter()
 3128                                .map(|selection| {
 3129                                    (
 3130                                        selection.start.to_offset(&snapshot),
 3131                                        selection.end.to_offset(&snapshot),
 3132                                    )
 3133                                })
 3134                                .collect();
 3135
 3136                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3137                                .await
 3138                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3139                                .log_err();
 3140                        });
 3141            }
 3142        }
 3143
 3144        cx.notify();
 3145    }
 3146
 3147    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3148        use text::ToOffset as _;
 3149        use text::ToPoint as _;
 3150
 3151        if self.mode.is_minimap()
 3152            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3153        {
 3154            return;
 3155        }
 3156
 3157        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3158            return;
 3159        };
 3160
 3161        let snapshot = singleton.read(cx).snapshot();
 3162        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3163            let display_snapshot = display_map.snapshot(cx);
 3164
 3165            display_snapshot
 3166                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3167                .map(|fold| {
 3168                    fold.range.start.text_anchor.to_point(&snapshot)
 3169                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3170                })
 3171                .collect()
 3172        });
 3173        self.update_restoration_data(cx, |data| {
 3174            data.folds = inmemory_folds;
 3175        });
 3176
 3177        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3178            return;
 3179        };
 3180        let background_executor = cx.background_executor().clone();
 3181        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3182        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3183            display_map
 3184                .snapshot(cx)
 3185                .folds_in_range(0..snapshot.len())
 3186                .map(|fold| {
 3187                    (
 3188                        fold.range.start.text_anchor.to_offset(&snapshot),
 3189                        fold.range.end.text_anchor.to_offset(&snapshot),
 3190                    )
 3191                })
 3192                .collect()
 3193        });
 3194        self.serialize_folds = cx.background_spawn(async move {
 3195            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3196            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3197                .await
 3198                .with_context(|| {
 3199                    format!(
 3200                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3201                    )
 3202                })
 3203                .log_err();
 3204        });
 3205    }
 3206
 3207    pub fn sync_selections(
 3208        &mut self,
 3209        other: Entity<Editor>,
 3210        cx: &mut Context<Self>,
 3211    ) -> gpui::Subscription {
 3212        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3213        self.selections.change_with(cx, |selections| {
 3214            selections.select_anchors(other_selections);
 3215        });
 3216
 3217        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3218            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3219                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3220                if other_selections.is_empty() {
 3221                    return;
 3222                }
 3223                this.selections.change_with(cx, |selections| {
 3224                    selections.select_anchors(other_selections);
 3225                });
 3226            }
 3227        });
 3228
 3229        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3230            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3231                let these_selections = this.selections.disjoint.to_vec();
 3232                if these_selections.is_empty() {
 3233                    return;
 3234                }
 3235                other.update(cx, |other_editor, cx| {
 3236                    other_editor.selections.change_with(cx, |selections| {
 3237                        selections.select_anchors(these_selections);
 3238                    })
 3239                });
 3240            }
 3241        });
 3242
 3243        Subscription::join(other_subscription, this_subscription)
 3244    }
 3245
 3246    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3247    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3248    /// effects of selection change occur at the end of the transaction.
 3249    pub fn change_selections<R>(
 3250        &mut self,
 3251        effects: SelectionEffects,
 3252        window: &mut Window,
 3253        cx: &mut Context<Self>,
 3254        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3255    ) -> R {
 3256        if let Some(state) = &mut self.deferred_selection_effects_state {
 3257            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3258            state.effects.completions = effects.completions;
 3259            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3260            let (changed, result) = self.selections.change_with(cx, change);
 3261            state.changed |= changed;
 3262            return result;
 3263        }
 3264        let mut state = DeferredSelectionEffectsState {
 3265            changed: false,
 3266            effects,
 3267            old_cursor_position: self.selections.newest_anchor().head(),
 3268            history_entry: SelectionHistoryEntry {
 3269                selections: self.selections.disjoint_anchors(),
 3270                select_next_state: self.select_next_state.clone(),
 3271                select_prev_state: self.select_prev_state.clone(),
 3272                add_selections_state: self.add_selections_state.clone(),
 3273            },
 3274        };
 3275        let (changed, result) = self.selections.change_with(cx, change);
 3276        state.changed = state.changed || changed;
 3277        if self.defer_selection_effects {
 3278            self.deferred_selection_effects_state = Some(state);
 3279        } else {
 3280            self.apply_selection_effects(state, window, cx);
 3281        }
 3282        result
 3283    }
 3284
 3285    /// Defers the effects of selection change, so that the effects of multiple calls to
 3286    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3287    /// to selection history and the state of popovers based on selection position aren't
 3288    /// erroneously updated.
 3289    pub fn with_selection_effects_deferred<R>(
 3290        &mut self,
 3291        window: &mut Window,
 3292        cx: &mut Context<Self>,
 3293        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3294    ) -> R {
 3295        let already_deferred = self.defer_selection_effects;
 3296        self.defer_selection_effects = true;
 3297        let result = update(self, window, cx);
 3298        if !already_deferred {
 3299            self.defer_selection_effects = false;
 3300            if let Some(state) = self.deferred_selection_effects_state.take() {
 3301                self.apply_selection_effects(state, window, cx);
 3302            }
 3303        }
 3304        result
 3305    }
 3306
 3307    fn apply_selection_effects(
 3308        &mut self,
 3309        state: DeferredSelectionEffectsState,
 3310        window: &mut Window,
 3311        cx: &mut Context<Self>,
 3312    ) {
 3313        if state.changed {
 3314            self.selection_history.push(state.history_entry);
 3315
 3316            if let Some(autoscroll) = state.effects.scroll {
 3317                self.request_autoscroll(autoscroll, cx);
 3318            }
 3319
 3320            let old_cursor_position = &state.old_cursor_position;
 3321
 3322            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3323
 3324            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3325                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3326            }
 3327        }
 3328    }
 3329
 3330    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3331    where
 3332        I: IntoIterator<Item = (Range<S>, T)>,
 3333        S: ToOffset,
 3334        T: Into<Arc<str>>,
 3335    {
 3336        if self.read_only(cx) {
 3337            return;
 3338        }
 3339
 3340        self.buffer
 3341            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3342    }
 3343
 3344    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3345    where
 3346        I: IntoIterator<Item = (Range<S>, T)>,
 3347        S: ToOffset,
 3348        T: Into<Arc<str>>,
 3349    {
 3350        if self.read_only(cx) {
 3351            return;
 3352        }
 3353
 3354        self.buffer.update(cx, |buffer, cx| {
 3355            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3356        });
 3357    }
 3358
 3359    pub fn edit_with_block_indent<I, S, T>(
 3360        &mut self,
 3361        edits: I,
 3362        original_indent_columns: Vec<Option<u32>>,
 3363        cx: &mut Context<Self>,
 3364    ) where
 3365        I: IntoIterator<Item = (Range<S>, T)>,
 3366        S: ToOffset,
 3367        T: Into<Arc<str>>,
 3368    {
 3369        if self.read_only(cx) {
 3370            return;
 3371        }
 3372
 3373        self.buffer.update(cx, |buffer, cx| {
 3374            buffer.edit(
 3375                edits,
 3376                Some(AutoindentMode::Block {
 3377                    original_indent_columns,
 3378                }),
 3379                cx,
 3380            )
 3381        });
 3382    }
 3383
 3384    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3385        self.hide_context_menu(window, cx);
 3386
 3387        match phase {
 3388            SelectPhase::Begin {
 3389                position,
 3390                add,
 3391                click_count,
 3392            } => self.begin_selection(position, add, click_count, window, cx),
 3393            SelectPhase::BeginColumnar {
 3394                position,
 3395                goal_column,
 3396                reset,
 3397                mode,
 3398            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3399            SelectPhase::Extend {
 3400                position,
 3401                click_count,
 3402            } => self.extend_selection(position, click_count, window, cx),
 3403            SelectPhase::Update {
 3404                position,
 3405                goal_column,
 3406                scroll_delta,
 3407            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3408            SelectPhase::End => self.end_selection(window, cx),
 3409        }
 3410    }
 3411
 3412    fn extend_selection(
 3413        &mut self,
 3414        position: DisplayPoint,
 3415        click_count: usize,
 3416        window: &mut Window,
 3417        cx: &mut Context<Self>,
 3418    ) {
 3419        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3420        let tail = self.selections.newest::<usize>(cx).tail();
 3421        self.begin_selection(position, false, click_count, window, cx);
 3422
 3423        let position = position.to_offset(&display_map, Bias::Left);
 3424        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3425
 3426        let mut pending_selection = self
 3427            .selections
 3428            .pending_anchor()
 3429            .expect("extend_selection not called with pending selection");
 3430        if position >= tail {
 3431            pending_selection.start = tail_anchor;
 3432        } else {
 3433            pending_selection.end = tail_anchor;
 3434            pending_selection.reversed = true;
 3435        }
 3436
 3437        let mut pending_mode = self.selections.pending_mode().unwrap();
 3438        match &mut pending_mode {
 3439            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3440            _ => {}
 3441        }
 3442
 3443        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3444            SelectionEffects::scroll(Autoscroll::fit())
 3445        } else {
 3446            SelectionEffects::no_scroll()
 3447        };
 3448
 3449        self.change_selections(effects, window, cx, |s| {
 3450            s.set_pending(pending_selection, pending_mode)
 3451        });
 3452    }
 3453
 3454    fn begin_selection(
 3455        &mut self,
 3456        position: DisplayPoint,
 3457        add: bool,
 3458        click_count: usize,
 3459        window: &mut Window,
 3460        cx: &mut Context<Self>,
 3461    ) {
 3462        if !self.focus_handle.is_focused(window) {
 3463            self.last_focused_descendant = None;
 3464            window.focus(&self.focus_handle);
 3465        }
 3466
 3467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3468        let buffer = &display_map.buffer_snapshot;
 3469        let position = display_map.clip_point(position, Bias::Left);
 3470
 3471        let start;
 3472        let end;
 3473        let mode;
 3474        let mut auto_scroll;
 3475        match click_count {
 3476            1 => {
 3477                start = buffer.anchor_before(position.to_point(&display_map));
 3478                end = start;
 3479                mode = SelectMode::Character;
 3480                auto_scroll = true;
 3481            }
 3482            2 => {
 3483                let position = display_map
 3484                    .clip_point(position, Bias::Left)
 3485                    .to_offset(&display_map, Bias::Left);
 3486                let (range, _) = buffer.surrounding_word(position, false);
 3487                start = buffer.anchor_before(range.start);
 3488                end = buffer.anchor_before(range.end);
 3489                mode = SelectMode::Word(start..end);
 3490                auto_scroll = true;
 3491            }
 3492            3 => {
 3493                let position = display_map
 3494                    .clip_point(position, Bias::Left)
 3495                    .to_point(&display_map);
 3496                let line_start = display_map.prev_line_boundary(position).0;
 3497                let next_line_start = buffer.clip_point(
 3498                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3499                    Bias::Left,
 3500                );
 3501                start = buffer.anchor_before(line_start);
 3502                end = buffer.anchor_before(next_line_start);
 3503                mode = SelectMode::Line(start..end);
 3504                auto_scroll = true;
 3505            }
 3506            _ => {
 3507                start = buffer.anchor_before(0);
 3508                end = buffer.anchor_before(buffer.len());
 3509                mode = SelectMode::All;
 3510                auto_scroll = false;
 3511            }
 3512        }
 3513        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3514
 3515        let point_to_delete: Option<usize> = {
 3516            let selected_points: Vec<Selection<Point>> =
 3517                self.selections.disjoint_in_range(start..end, cx);
 3518
 3519            if !add || click_count > 1 {
 3520                None
 3521            } else if !selected_points.is_empty() {
 3522                Some(selected_points[0].id)
 3523            } else {
 3524                let clicked_point_already_selected =
 3525                    self.selections.disjoint.iter().find(|selection| {
 3526                        selection.start.to_point(buffer) == start.to_point(buffer)
 3527                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3528                    });
 3529
 3530                clicked_point_already_selected.map(|selection| selection.id)
 3531            }
 3532        };
 3533
 3534        let selections_count = self.selections.count();
 3535        let effects = if auto_scroll {
 3536            SelectionEffects::default()
 3537        } else {
 3538            SelectionEffects::no_scroll()
 3539        };
 3540
 3541        self.change_selections(effects, window, cx, |s| {
 3542            if let Some(point_to_delete) = point_to_delete {
 3543                s.delete(point_to_delete);
 3544
 3545                if selections_count == 1 {
 3546                    s.set_pending_anchor_range(start..end, mode);
 3547                }
 3548            } else {
 3549                if !add {
 3550                    s.clear_disjoint();
 3551                }
 3552
 3553                s.set_pending_anchor_range(start..end, mode);
 3554            }
 3555        });
 3556    }
 3557
 3558    fn begin_columnar_selection(
 3559        &mut self,
 3560        position: DisplayPoint,
 3561        goal_column: u32,
 3562        reset: bool,
 3563        mode: ColumnarMode,
 3564        window: &mut Window,
 3565        cx: &mut Context<Self>,
 3566    ) {
 3567        if !self.focus_handle.is_focused(window) {
 3568            self.last_focused_descendant = None;
 3569            window.focus(&self.focus_handle);
 3570        }
 3571
 3572        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3573
 3574        if reset {
 3575            let pointer_position = display_map
 3576                .buffer_snapshot
 3577                .anchor_before(position.to_point(&display_map));
 3578
 3579            self.change_selections(
 3580                SelectionEffects::scroll(Autoscroll::newest()),
 3581                window,
 3582                cx,
 3583                |s| {
 3584                    s.clear_disjoint();
 3585                    s.set_pending_anchor_range(
 3586                        pointer_position..pointer_position,
 3587                        SelectMode::Character,
 3588                    );
 3589                },
 3590            );
 3591        };
 3592
 3593        let tail = self.selections.newest::<Point>(cx).tail();
 3594        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3595        self.columnar_selection_state = match mode {
 3596            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3597                selection_tail: selection_anchor,
 3598                display_point: if reset {
 3599                    if position.column() != goal_column {
 3600                        Some(DisplayPoint::new(position.row(), goal_column))
 3601                    } else {
 3602                        None
 3603                    }
 3604                } else {
 3605                    None
 3606                },
 3607            }),
 3608            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3609                selection_tail: selection_anchor,
 3610            }),
 3611        };
 3612
 3613        if !reset {
 3614            self.select_columns(position, goal_column, &display_map, window, cx);
 3615        }
 3616    }
 3617
 3618    fn update_selection(
 3619        &mut self,
 3620        position: DisplayPoint,
 3621        goal_column: u32,
 3622        scroll_delta: gpui::Point<f32>,
 3623        window: &mut Window,
 3624        cx: &mut Context<Self>,
 3625    ) {
 3626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3627
 3628        if self.columnar_selection_state.is_some() {
 3629            self.select_columns(position, goal_column, &display_map, window, cx);
 3630        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3631            let buffer = &display_map.buffer_snapshot;
 3632            let head;
 3633            let tail;
 3634            let mode = self.selections.pending_mode().unwrap();
 3635            match &mode {
 3636                SelectMode::Character => {
 3637                    head = position.to_point(&display_map);
 3638                    tail = pending.tail().to_point(buffer);
 3639                }
 3640                SelectMode::Word(original_range) => {
 3641                    let offset = display_map
 3642                        .clip_point(position, Bias::Left)
 3643                        .to_offset(&display_map, Bias::Left);
 3644                    let original_range = original_range.to_offset(buffer);
 3645
 3646                    let head_offset = if buffer.is_inside_word(offset, false)
 3647                        || original_range.contains(&offset)
 3648                    {
 3649                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3650                        if word_range.start < original_range.start {
 3651                            word_range.start
 3652                        } else {
 3653                            word_range.end
 3654                        }
 3655                    } else {
 3656                        offset
 3657                    };
 3658
 3659                    head = head_offset.to_point(buffer);
 3660                    if head_offset <= original_range.start {
 3661                        tail = original_range.end.to_point(buffer);
 3662                    } else {
 3663                        tail = original_range.start.to_point(buffer);
 3664                    }
 3665                }
 3666                SelectMode::Line(original_range) => {
 3667                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3668
 3669                    let position = display_map
 3670                        .clip_point(position, Bias::Left)
 3671                        .to_point(&display_map);
 3672                    let line_start = display_map.prev_line_boundary(position).0;
 3673                    let next_line_start = buffer.clip_point(
 3674                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3675                        Bias::Left,
 3676                    );
 3677
 3678                    if line_start < original_range.start {
 3679                        head = line_start
 3680                    } else {
 3681                        head = next_line_start
 3682                    }
 3683
 3684                    if head <= original_range.start {
 3685                        tail = original_range.end;
 3686                    } else {
 3687                        tail = original_range.start;
 3688                    }
 3689                }
 3690                SelectMode::All => {
 3691                    return;
 3692                }
 3693            };
 3694
 3695            if head < tail {
 3696                pending.start = buffer.anchor_before(head);
 3697                pending.end = buffer.anchor_before(tail);
 3698                pending.reversed = true;
 3699            } else {
 3700                pending.start = buffer.anchor_before(tail);
 3701                pending.end = buffer.anchor_before(head);
 3702                pending.reversed = false;
 3703            }
 3704
 3705            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3706                s.set_pending(pending, mode);
 3707            });
 3708        } else {
 3709            log::error!("update_selection dispatched with no pending selection");
 3710            return;
 3711        }
 3712
 3713        self.apply_scroll_delta(scroll_delta, window, cx);
 3714        cx.notify();
 3715    }
 3716
 3717    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3718        self.columnar_selection_state.take();
 3719        if self.selections.pending_anchor().is_some() {
 3720            let selections = self.selections.all::<usize>(cx);
 3721            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3722                s.select(selections);
 3723                s.clear_pending();
 3724            });
 3725        }
 3726    }
 3727
 3728    fn select_columns(
 3729        &mut self,
 3730        head: DisplayPoint,
 3731        goal_column: u32,
 3732        display_map: &DisplaySnapshot,
 3733        window: &mut Window,
 3734        cx: &mut Context<Self>,
 3735    ) {
 3736        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3737            return;
 3738        };
 3739
 3740        let tail = match columnar_state {
 3741            ColumnarSelectionState::FromMouse {
 3742                selection_tail,
 3743                display_point,
 3744            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3745            ColumnarSelectionState::FromSelection { selection_tail } => {
 3746                selection_tail.to_display_point(display_map)
 3747            }
 3748        };
 3749
 3750        let start_row = cmp::min(tail.row(), head.row());
 3751        let end_row = cmp::max(tail.row(), head.row());
 3752        let start_column = cmp::min(tail.column(), goal_column);
 3753        let end_column = cmp::max(tail.column(), goal_column);
 3754        let reversed = start_column < tail.column();
 3755
 3756        let selection_ranges = (start_row.0..=end_row.0)
 3757            .map(DisplayRow)
 3758            .filter_map(|row| {
 3759                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3760                    || start_column <= display_map.line_len(row))
 3761                    && !display_map.is_block_line(row)
 3762                {
 3763                    let start = display_map
 3764                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3765                        .to_point(display_map);
 3766                    let end = display_map
 3767                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3768                        .to_point(display_map);
 3769                    if reversed {
 3770                        Some(end..start)
 3771                    } else {
 3772                        Some(start..end)
 3773                    }
 3774                } else {
 3775                    None
 3776                }
 3777            })
 3778            .collect::<Vec<_>>();
 3779
 3780        let ranges = match columnar_state {
 3781            ColumnarSelectionState::FromMouse { .. } => {
 3782                let mut non_empty_ranges = selection_ranges
 3783                    .iter()
 3784                    .filter(|selection_range| selection_range.start != selection_range.end)
 3785                    .peekable();
 3786                if non_empty_ranges.peek().is_some() {
 3787                    non_empty_ranges.cloned().collect()
 3788                } else {
 3789                    selection_ranges
 3790                }
 3791            }
 3792            _ => selection_ranges,
 3793        };
 3794
 3795        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3796            s.select_ranges(ranges);
 3797        });
 3798        cx.notify();
 3799    }
 3800
 3801    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3802        self.selections
 3803            .all_adjusted(cx)
 3804            .iter()
 3805            .any(|selection| !selection.is_empty())
 3806    }
 3807
 3808    pub fn has_pending_nonempty_selection(&self) -> bool {
 3809        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3810            Some(Selection { start, end, .. }) => start != end,
 3811            None => false,
 3812        };
 3813
 3814        pending_nonempty_selection
 3815            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3816    }
 3817
 3818    pub fn has_pending_selection(&self) -> bool {
 3819        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3820    }
 3821
 3822    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3823        self.selection_mark_mode = false;
 3824        self.selection_drag_state = SelectionDragState::None;
 3825
 3826        if self.clear_expanded_diff_hunks(cx) {
 3827            cx.notify();
 3828            return;
 3829        }
 3830        if self.dismiss_menus_and_popups(true, window, cx) {
 3831            return;
 3832        }
 3833
 3834        if self.mode.is_full()
 3835            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3836        {
 3837            return;
 3838        }
 3839
 3840        cx.propagate();
 3841    }
 3842
 3843    pub fn dismiss_menus_and_popups(
 3844        &mut self,
 3845        is_user_requested: bool,
 3846        window: &mut Window,
 3847        cx: &mut Context<Self>,
 3848    ) -> bool {
 3849        if self.take_rename(false, window, cx).is_some() {
 3850            return true;
 3851        }
 3852
 3853        if hide_hover(self, cx) {
 3854            return true;
 3855        }
 3856
 3857        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3858            return true;
 3859        }
 3860
 3861        if self.hide_context_menu(window, cx).is_some() {
 3862            return true;
 3863        }
 3864
 3865        if self.mouse_context_menu.take().is_some() {
 3866            return true;
 3867        }
 3868
 3869        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3870            return true;
 3871        }
 3872
 3873        if self.snippet_stack.pop().is_some() {
 3874            return true;
 3875        }
 3876
 3877        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3878            self.dismiss_diagnostics(cx);
 3879            return true;
 3880        }
 3881
 3882        false
 3883    }
 3884
 3885    fn linked_editing_ranges_for(
 3886        &self,
 3887        selection: Range<text::Anchor>,
 3888        cx: &App,
 3889    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3890        if self.linked_edit_ranges.is_empty() {
 3891            return None;
 3892        }
 3893        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3894            selection.end.buffer_id.and_then(|end_buffer_id| {
 3895                if selection.start.buffer_id != Some(end_buffer_id) {
 3896                    return None;
 3897                }
 3898                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3899                let snapshot = buffer.read(cx).snapshot();
 3900                self.linked_edit_ranges
 3901                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3902                    .map(|ranges| (ranges, snapshot, buffer))
 3903            })?;
 3904        use text::ToOffset as TO;
 3905        // find offset from the start of current range to current cursor position
 3906        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3907
 3908        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3909        let start_difference = start_offset - start_byte_offset;
 3910        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3911        let end_difference = end_offset - start_byte_offset;
 3912        // Current range has associated linked ranges.
 3913        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3914        for range in linked_ranges.iter() {
 3915            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3916            let end_offset = start_offset + end_difference;
 3917            let start_offset = start_offset + start_difference;
 3918            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3919                continue;
 3920            }
 3921            if self.selections.disjoint_anchor_ranges().any(|s| {
 3922                if s.start.buffer_id != selection.start.buffer_id
 3923                    || s.end.buffer_id != selection.end.buffer_id
 3924                {
 3925                    return false;
 3926                }
 3927                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3928                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3929            }) {
 3930                continue;
 3931            }
 3932            let start = buffer_snapshot.anchor_after(start_offset);
 3933            let end = buffer_snapshot.anchor_after(end_offset);
 3934            linked_edits
 3935                .entry(buffer.clone())
 3936                .or_default()
 3937                .push(start..end);
 3938        }
 3939        Some(linked_edits)
 3940    }
 3941
 3942    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3943        let text: Arc<str> = text.into();
 3944
 3945        if self.read_only(cx) {
 3946            return;
 3947        }
 3948
 3949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3950
 3951        let selections = self.selections.all_adjusted(cx);
 3952        let mut bracket_inserted = false;
 3953        let mut edits = Vec::new();
 3954        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3955        let mut new_selections = Vec::with_capacity(selections.len());
 3956        let mut new_autoclose_regions = Vec::new();
 3957        let snapshot = self.buffer.read(cx).read(cx);
 3958        let mut clear_linked_edit_ranges = false;
 3959
 3960        for (selection, autoclose_region) in
 3961            self.selections_with_autoclose_regions(selections, &snapshot)
 3962        {
 3963            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3964                // Determine if the inserted text matches the opening or closing
 3965                // bracket of any of this language's bracket pairs.
 3966                let mut bracket_pair = None;
 3967                let mut is_bracket_pair_start = false;
 3968                let mut is_bracket_pair_end = false;
 3969                if !text.is_empty() {
 3970                    let mut bracket_pair_matching_end = None;
 3971                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3972                    //  and they are removing the character that triggered IME popup.
 3973                    for (pair, enabled) in scope.brackets() {
 3974                        if !pair.close && !pair.surround {
 3975                            continue;
 3976                        }
 3977
 3978                        if enabled && pair.start.ends_with(text.as_ref()) {
 3979                            let prefix_len = pair.start.len() - text.len();
 3980                            let preceding_text_matches_prefix = prefix_len == 0
 3981                                || (selection.start.column >= (prefix_len as u32)
 3982                                    && snapshot.contains_str_at(
 3983                                        Point::new(
 3984                                            selection.start.row,
 3985                                            selection.start.column - (prefix_len as u32),
 3986                                        ),
 3987                                        &pair.start[..prefix_len],
 3988                                    ));
 3989                            if preceding_text_matches_prefix {
 3990                                bracket_pair = Some(pair.clone());
 3991                                is_bracket_pair_start = true;
 3992                                break;
 3993                            }
 3994                        }
 3995                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3996                        {
 3997                            // take first bracket pair matching end, but don't break in case a later bracket
 3998                            // pair matches start
 3999                            bracket_pair_matching_end = Some(pair.clone());
 4000                        }
 4001                    }
 4002                    if let Some(end) = bracket_pair_matching_end
 4003                        && bracket_pair.is_none()
 4004                    {
 4005                        bracket_pair = Some(end);
 4006                        is_bracket_pair_end = true;
 4007                    }
 4008                }
 4009
 4010                if let Some(bracket_pair) = bracket_pair {
 4011                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4012                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4013                    let auto_surround =
 4014                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4015                    if selection.is_empty() {
 4016                        if is_bracket_pair_start {
 4017                            // If the inserted text is a suffix of an opening bracket and the
 4018                            // selection is preceded by the rest of the opening bracket, then
 4019                            // insert the closing bracket.
 4020                            let following_text_allows_autoclose = snapshot
 4021                                .chars_at(selection.start)
 4022                                .next()
 4023                                .is_none_or(|c| scope.should_autoclose_before(c));
 4024
 4025                            let preceding_text_allows_autoclose = selection.start.column == 0
 4026                                || snapshot
 4027                                    .reversed_chars_at(selection.start)
 4028                                    .next()
 4029                                    .is_none_or(|c| {
 4030                                        bracket_pair.start != bracket_pair.end
 4031                                            || !snapshot
 4032                                                .char_classifier_at(selection.start)
 4033                                                .is_word(c)
 4034                                    });
 4035
 4036                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4037                                && bracket_pair.start.len() == 1
 4038                            {
 4039                                let target = bracket_pair.start.chars().next().unwrap();
 4040                                let current_line_count = snapshot
 4041                                    .reversed_chars_at(selection.start)
 4042                                    .take_while(|&c| c != '\n')
 4043                                    .filter(|&c| c == target)
 4044                                    .count();
 4045                                current_line_count % 2 == 1
 4046                            } else {
 4047                                false
 4048                            };
 4049
 4050                            if autoclose
 4051                                && bracket_pair.close
 4052                                && following_text_allows_autoclose
 4053                                && preceding_text_allows_autoclose
 4054                                && !is_closing_quote
 4055                            {
 4056                                let anchor = snapshot.anchor_before(selection.end);
 4057                                new_selections.push((selection.map(|_| anchor), text.len()));
 4058                                new_autoclose_regions.push((
 4059                                    anchor,
 4060                                    text.len(),
 4061                                    selection.id,
 4062                                    bracket_pair.clone(),
 4063                                ));
 4064                                edits.push((
 4065                                    selection.range(),
 4066                                    format!("{}{}", text, bracket_pair.end).into(),
 4067                                ));
 4068                                bracket_inserted = true;
 4069                                continue;
 4070                            }
 4071                        }
 4072
 4073                        if let Some(region) = autoclose_region {
 4074                            // If the selection is followed by an auto-inserted closing bracket,
 4075                            // then don't insert that closing bracket again; just move the selection
 4076                            // past the closing bracket.
 4077                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4078                                && text.as_ref() == region.pair.end.as_str()
 4079                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4080                            if should_skip {
 4081                                let anchor = snapshot.anchor_after(selection.end);
 4082                                new_selections
 4083                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4084                                continue;
 4085                            }
 4086                        }
 4087
 4088                        let always_treat_brackets_as_autoclosed = snapshot
 4089                            .language_settings_at(selection.start, cx)
 4090                            .always_treat_brackets_as_autoclosed;
 4091                        if always_treat_brackets_as_autoclosed
 4092                            && is_bracket_pair_end
 4093                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4094                        {
 4095                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4096                            // and the inserted text is a closing bracket and the selection is followed
 4097                            // by the closing bracket then move the selection past the closing bracket.
 4098                            let anchor = snapshot.anchor_after(selection.end);
 4099                            new_selections.push((selection.map(|_| anchor), text.len()));
 4100                            continue;
 4101                        }
 4102                    }
 4103                    // If an opening bracket is 1 character long and is typed while
 4104                    // text is selected, then surround that text with the bracket pair.
 4105                    else if auto_surround
 4106                        && bracket_pair.surround
 4107                        && is_bracket_pair_start
 4108                        && bracket_pair.start.chars().count() == 1
 4109                    {
 4110                        edits.push((selection.start..selection.start, text.clone()));
 4111                        edits.push((
 4112                            selection.end..selection.end,
 4113                            bracket_pair.end.as_str().into(),
 4114                        ));
 4115                        bracket_inserted = true;
 4116                        new_selections.push((
 4117                            Selection {
 4118                                id: selection.id,
 4119                                start: snapshot.anchor_after(selection.start),
 4120                                end: snapshot.anchor_before(selection.end),
 4121                                reversed: selection.reversed,
 4122                                goal: selection.goal,
 4123                            },
 4124                            0,
 4125                        ));
 4126                        continue;
 4127                    }
 4128                }
 4129            }
 4130
 4131            if self.auto_replace_emoji_shortcode
 4132                && selection.is_empty()
 4133                && text.as_ref().ends_with(':')
 4134                && let Some(possible_emoji_short_code) =
 4135                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4136                && !possible_emoji_short_code.is_empty()
 4137                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4138            {
 4139                let emoji_shortcode_start = Point::new(
 4140                    selection.start.row,
 4141                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4142                );
 4143
 4144                // Remove shortcode from buffer
 4145                edits.push((
 4146                    emoji_shortcode_start..selection.start,
 4147                    "".to_string().into(),
 4148                ));
 4149                new_selections.push((
 4150                    Selection {
 4151                        id: selection.id,
 4152                        start: snapshot.anchor_after(emoji_shortcode_start),
 4153                        end: snapshot.anchor_before(selection.start),
 4154                        reversed: selection.reversed,
 4155                        goal: selection.goal,
 4156                    },
 4157                    0,
 4158                ));
 4159
 4160                // Insert emoji
 4161                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4162                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4163                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4164
 4165                continue;
 4166            }
 4167
 4168            // If not handling any auto-close operation, then just replace the selected
 4169            // text with the given input and move the selection to the end of the
 4170            // newly inserted text.
 4171            let anchor = snapshot.anchor_after(selection.end);
 4172            if !self.linked_edit_ranges.is_empty() {
 4173                let start_anchor = snapshot.anchor_before(selection.start);
 4174
 4175                let is_word_char = text.chars().next().is_none_or(|char| {
 4176                    let classifier = snapshot
 4177                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4178                        .ignore_punctuation(true);
 4179                    classifier.is_word(char)
 4180                });
 4181
 4182                if is_word_char {
 4183                    if let Some(ranges) = self
 4184                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4185                    {
 4186                        for (buffer, edits) in ranges {
 4187                            linked_edits
 4188                                .entry(buffer.clone())
 4189                                .or_default()
 4190                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4191                        }
 4192                    }
 4193                } else {
 4194                    clear_linked_edit_ranges = true;
 4195                }
 4196            }
 4197
 4198            new_selections.push((selection.map(|_| anchor), 0));
 4199            edits.push((selection.start..selection.end, text.clone()));
 4200        }
 4201
 4202        drop(snapshot);
 4203
 4204        self.transact(window, cx, |this, window, cx| {
 4205            if clear_linked_edit_ranges {
 4206                this.linked_edit_ranges.clear();
 4207            }
 4208            let initial_buffer_versions =
 4209                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4210
 4211            this.buffer.update(cx, |buffer, cx| {
 4212                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4213            });
 4214            for (buffer, edits) in linked_edits {
 4215                buffer.update(cx, |buffer, cx| {
 4216                    let snapshot = buffer.snapshot();
 4217                    let edits = edits
 4218                        .into_iter()
 4219                        .map(|(range, text)| {
 4220                            use text::ToPoint as TP;
 4221                            let end_point = TP::to_point(&range.end, &snapshot);
 4222                            let start_point = TP::to_point(&range.start, &snapshot);
 4223                            (start_point..end_point, text)
 4224                        })
 4225                        .sorted_by_key(|(range, _)| range.start);
 4226                    buffer.edit(edits, None, cx);
 4227                })
 4228            }
 4229            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4230            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4231            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4232            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4233                .zip(new_selection_deltas)
 4234                .map(|(selection, delta)| Selection {
 4235                    id: selection.id,
 4236                    start: selection.start + delta,
 4237                    end: selection.end + delta,
 4238                    reversed: selection.reversed,
 4239                    goal: SelectionGoal::None,
 4240                })
 4241                .collect::<Vec<_>>();
 4242
 4243            let mut i = 0;
 4244            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4245                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4246                let start = map.buffer_snapshot.anchor_before(position);
 4247                let end = map.buffer_snapshot.anchor_after(position);
 4248                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4249                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4250                        Ordering::Less => i += 1,
 4251                        Ordering::Greater => break,
 4252                        Ordering::Equal => {
 4253                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4254                                Ordering::Less => i += 1,
 4255                                Ordering::Equal => break,
 4256                                Ordering::Greater => break,
 4257                            }
 4258                        }
 4259                    }
 4260                }
 4261                this.autoclose_regions.insert(
 4262                    i,
 4263                    AutocloseRegion {
 4264                        selection_id,
 4265                        range: start..end,
 4266                        pair,
 4267                    },
 4268                );
 4269            }
 4270
 4271            let had_active_edit_prediction = this.has_active_edit_prediction();
 4272            this.change_selections(
 4273                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4274                window,
 4275                cx,
 4276                |s| s.select(new_selections),
 4277            );
 4278
 4279            if !bracket_inserted
 4280                && let Some(on_type_format_task) =
 4281                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4282            {
 4283                on_type_format_task.detach_and_log_err(cx);
 4284            }
 4285
 4286            let editor_settings = EditorSettings::get_global(cx);
 4287            if bracket_inserted
 4288                && (editor_settings.auto_signature_help
 4289                    || editor_settings.show_signature_help_after_edits)
 4290            {
 4291                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4292            }
 4293
 4294            let trigger_in_words =
 4295                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4296            if this.hard_wrap.is_some() {
 4297                let latest: Range<Point> = this.selections.newest(cx).range();
 4298                if latest.is_empty()
 4299                    && this
 4300                        .buffer()
 4301                        .read(cx)
 4302                        .snapshot(cx)
 4303                        .line_len(MultiBufferRow(latest.start.row))
 4304                        == latest.start.column
 4305                {
 4306                    this.rewrap_impl(
 4307                        RewrapOptions {
 4308                            override_language_settings: true,
 4309                            preserve_existing_whitespace: true,
 4310                        },
 4311                        cx,
 4312                    )
 4313                }
 4314            }
 4315            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4316            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4317            this.refresh_edit_prediction(true, false, window, cx);
 4318            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4319        });
 4320    }
 4321
 4322    fn find_possible_emoji_shortcode_at_position(
 4323        snapshot: &MultiBufferSnapshot,
 4324        position: Point,
 4325    ) -> Option<String> {
 4326        let mut chars = Vec::new();
 4327        let mut found_colon = false;
 4328        for char in snapshot.reversed_chars_at(position).take(100) {
 4329            // Found a possible emoji shortcode in the middle of the buffer
 4330            if found_colon {
 4331                if char.is_whitespace() {
 4332                    chars.reverse();
 4333                    return Some(chars.iter().collect());
 4334                }
 4335                // If the previous character is not a whitespace, we are in the middle of a word
 4336                // and we only want to complete the shortcode if the word is made up of other emojis
 4337                let mut containing_word = String::new();
 4338                for ch in snapshot
 4339                    .reversed_chars_at(position)
 4340                    .skip(chars.len() + 1)
 4341                    .take(100)
 4342                {
 4343                    if ch.is_whitespace() {
 4344                        break;
 4345                    }
 4346                    containing_word.push(ch);
 4347                }
 4348                let containing_word = containing_word.chars().rev().collect::<String>();
 4349                if util::word_consists_of_emojis(containing_word.as_str()) {
 4350                    chars.reverse();
 4351                    return Some(chars.iter().collect());
 4352                }
 4353            }
 4354
 4355            if char.is_whitespace() || !char.is_ascii() {
 4356                return None;
 4357            }
 4358            if char == ':' {
 4359                found_colon = true;
 4360            } else {
 4361                chars.push(char);
 4362            }
 4363        }
 4364        // Found a possible emoji shortcode at the beginning of the buffer
 4365        chars.reverse();
 4366        Some(chars.iter().collect())
 4367    }
 4368
 4369    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4371        self.transact(window, cx, |this, window, cx| {
 4372            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4373                let selections = this.selections.all::<usize>(cx);
 4374                let multi_buffer = this.buffer.read(cx);
 4375                let buffer = multi_buffer.snapshot(cx);
 4376                selections
 4377                    .iter()
 4378                    .map(|selection| {
 4379                        let start_point = selection.start.to_point(&buffer);
 4380                        let mut existing_indent =
 4381                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4382                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4383                        let start = selection.start;
 4384                        let end = selection.end;
 4385                        let selection_is_empty = start == end;
 4386                        let language_scope = buffer.language_scope_at(start);
 4387                        let (
 4388                            comment_delimiter,
 4389                            doc_delimiter,
 4390                            insert_extra_newline,
 4391                            indent_on_newline,
 4392                            indent_on_extra_newline,
 4393                        ) = if let Some(language) = &language_scope {
 4394                            let mut insert_extra_newline =
 4395                                insert_extra_newline_brackets(&buffer, start..end, language)
 4396                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4397
 4398                            // Comment extension on newline is allowed only for cursor selections
 4399                            let comment_delimiter = maybe!({
 4400                                if !selection_is_empty {
 4401                                    return None;
 4402                                }
 4403
 4404                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4405                                    return None;
 4406                                }
 4407
 4408                                let delimiters = language.line_comment_prefixes();
 4409                                let max_len_of_delimiter =
 4410                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4411                                let (snapshot, range) =
 4412                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4413
 4414                                let num_of_whitespaces = snapshot
 4415                                    .chars_for_range(range.clone())
 4416                                    .take_while(|c| c.is_whitespace())
 4417                                    .count();
 4418                                let comment_candidate = snapshot
 4419                                    .chars_for_range(range.clone())
 4420                                    .skip(num_of_whitespaces)
 4421                                    .take(max_len_of_delimiter)
 4422                                    .collect::<String>();
 4423                                let (delimiter, trimmed_len) = delimiters
 4424                                    .iter()
 4425                                    .filter_map(|delimiter| {
 4426                                        let prefix = delimiter.trim_end();
 4427                                        if comment_candidate.starts_with(prefix) {
 4428                                            Some((delimiter, prefix.len()))
 4429                                        } else {
 4430                                            None
 4431                                        }
 4432                                    })
 4433                                    .max_by_key(|(_, len)| *len)?;
 4434
 4435                                if let Some(BlockCommentConfig {
 4436                                    start: block_start, ..
 4437                                }) = language.block_comment()
 4438                                {
 4439                                    let block_start_trimmed = block_start.trim_end();
 4440                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4441                                        let line_content = snapshot
 4442                                            .chars_for_range(range)
 4443                                            .skip(num_of_whitespaces)
 4444                                            .take(block_start_trimmed.len())
 4445                                            .collect::<String>();
 4446
 4447                                        if line_content.starts_with(block_start_trimmed) {
 4448                                            return None;
 4449                                        }
 4450                                    }
 4451                                }
 4452
 4453                                let cursor_is_placed_after_comment_marker =
 4454                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4455                                if cursor_is_placed_after_comment_marker {
 4456                                    Some(delimiter.clone())
 4457                                } else {
 4458                                    None
 4459                                }
 4460                            });
 4461
 4462                            let mut indent_on_newline = IndentSize::spaces(0);
 4463                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4464
 4465                            let doc_delimiter = maybe!({
 4466                                if !selection_is_empty {
 4467                                    return None;
 4468                                }
 4469
 4470                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4471                                    return None;
 4472                                }
 4473
 4474                                let BlockCommentConfig {
 4475                                    start: start_tag,
 4476                                    end: end_tag,
 4477                                    prefix: delimiter,
 4478                                    tab_size: len,
 4479                                } = language.documentation_comment()?;
 4480                                let is_within_block_comment = buffer
 4481                                    .language_scope_at(start_point)
 4482                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4483                                if !is_within_block_comment {
 4484                                    return None;
 4485                                }
 4486
 4487                                let (snapshot, range) =
 4488                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4489
 4490                                let num_of_whitespaces = snapshot
 4491                                    .chars_for_range(range.clone())
 4492                                    .take_while(|c| c.is_whitespace())
 4493                                    .count();
 4494
 4495                                // 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.
 4496                                let column = start_point.column;
 4497                                let cursor_is_after_start_tag = {
 4498                                    let start_tag_len = start_tag.len();
 4499                                    let start_tag_line = snapshot
 4500                                        .chars_for_range(range.clone())
 4501                                        .skip(num_of_whitespaces)
 4502                                        .take(start_tag_len)
 4503                                        .collect::<String>();
 4504                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4505                                        num_of_whitespaces + start_tag_len <= column as usize
 4506                                    } else {
 4507                                        false
 4508                                    }
 4509                                };
 4510
 4511                                let cursor_is_after_delimiter = {
 4512                                    let delimiter_trim = delimiter.trim_end();
 4513                                    let delimiter_line = snapshot
 4514                                        .chars_for_range(range.clone())
 4515                                        .skip(num_of_whitespaces)
 4516                                        .take(delimiter_trim.len())
 4517                                        .collect::<String>();
 4518                                    if delimiter_line.starts_with(delimiter_trim) {
 4519                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4520                                    } else {
 4521                                        false
 4522                                    }
 4523                                };
 4524
 4525                                let cursor_is_before_end_tag_if_exists = {
 4526                                    let mut char_position = 0u32;
 4527                                    let mut end_tag_offset = None;
 4528
 4529                                    'outer: for chunk in snapshot.text_for_range(range) {
 4530                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4531                                            let chars_before_match =
 4532                                                chunk[..byte_pos].chars().count() as u32;
 4533                                            end_tag_offset =
 4534                                                Some(char_position + chars_before_match);
 4535                                            break 'outer;
 4536                                        }
 4537                                        char_position += chunk.chars().count() as u32;
 4538                                    }
 4539
 4540                                    if let Some(end_tag_offset) = end_tag_offset {
 4541                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4542                                        if cursor_is_after_start_tag {
 4543                                            if cursor_is_before_end_tag {
 4544                                                insert_extra_newline = true;
 4545                                            }
 4546                                            let cursor_is_at_start_of_end_tag =
 4547                                                column == end_tag_offset;
 4548                                            if cursor_is_at_start_of_end_tag {
 4549                                                indent_on_extra_newline.len = *len;
 4550                                            }
 4551                                        }
 4552                                        cursor_is_before_end_tag
 4553                                    } else {
 4554                                        true
 4555                                    }
 4556                                };
 4557
 4558                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4559                                    && cursor_is_before_end_tag_if_exists
 4560                                {
 4561                                    if cursor_is_after_start_tag {
 4562                                        indent_on_newline.len = *len;
 4563                                    }
 4564                                    Some(delimiter.clone())
 4565                                } else {
 4566                                    None
 4567                                }
 4568                            });
 4569
 4570                            (
 4571                                comment_delimiter,
 4572                                doc_delimiter,
 4573                                insert_extra_newline,
 4574                                indent_on_newline,
 4575                                indent_on_extra_newline,
 4576                            )
 4577                        } else {
 4578                            (
 4579                                None,
 4580                                None,
 4581                                false,
 4582                                IndentSize::default(),
 4583                                IndentSize::default(),
 4584                            )
 4585                        };
 4586
 4587                        let prevent_auto_indent = doc_delimiter.is_some();
 4588                        let delimiter = comment_delimiter.or(doc_delimiter);
 4589
 4590                        let capacity_for_delimiter =
 4591                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4592                        let mut new_text = String::with_capacity(
 4593                            1 + capacity_for_delimiter
 4594                                + existing_indent.len as usize
 4595                                + indent_on_newline.len as usize
 4596                                + indent_on_extra_newline.len as usize,
 4597                        );
 4598                        new_text.push('\n');
 4599                        new_text.extend(existing_indent.chars());
 4600                        new_text.extend(indent_on_newline.chars());
 4601
 4602                        if let Some(delimiter) = &delimiter {
 4603                            new_text.push_str(delimiter);
 4604                        }
 4605
 4606                        if insert_extra_newline {
 4607                            new_text.push('\n');
 4608                            new_text.extend(existing_indent.chars());
 4609                            new_text.extend(indent_on_extra_newline.chars());
 4610                        }
 4611
 4612                        let anchor = buffer.anchor_after(end);
 4613                        let new_selection = selection.map(|_| anchor);
 4614                        (
 4615                            ((start..end, new_text), prevent_auto_indent),
 4616                            (insert_extra_newline, new_selection),
 4617                        )
 4618                    })
 4619                    .unzip()
 4620            };
 4621
 4622            let mut auto_indent_edits = Vec::new();
 4623            let mut edits = Vec::new();
 4624            for (edit, prevent_auto_indent) in edits_with_flags {
 4625                if prevent_auto_indent {
 4626                    edits.push(edit);
 4627                } else {
 4628                    auto_indent_edits.push(edit);
 4629                }
 4630            }
 4631            if !edits.is_empty() {
 4632                this.edit(edits, cx);
 4633            }
 4634            if !auto_indent_edits.is_empty() {
 4635                this.edit_with_autoindent(auto_indent_edits, cx);
 4636            }
 4637
 4638            let buffer = this.buffer.read(cx).snapshot(cx);
 4639            let new_selections = selection_info
 4640                .into_iter()
 4641                .map(|(extra_newline_inserted, new_selection)| {
 4642                    let mut cursor = new_selection.end.to_point(&buffer);
 4643                    if extra_newline_inserted {
 4644                        cursor.row -= 1;
 4645                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4646                    }
 4647                    new_selection.map(|_| cursor)
 4648                })
 4649                .collect();
 4650
 4651            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4652            this.refresh_edit_prediction(true, false, window, cx);
 4653        });
 4654    }
 4655
 4656    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4658
 4659        let buffer = self.buffer.read(cx);
 4660        let snapshot = buffer.snapshot(cx);
 4661
 4662        let mut edits = Vec::new();
 4663        let mut rows = Vec::new();
 4664
 4665        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4666            let cursor = selection.head();
 4667            let row = cursor.row;
 4668
 4669            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4670
 4671            let newline = "\n".to_string();
 4672            edits.push((start_of_line..start_of_line, newline));
 4673
 4674            rows.push(row + rows_inserted as u32);
 4675        }
 4676
 4677        self.transact(window, cx, |editor, window, cx| {
 4678            editor.edit(edits, cx);
 4679
 4680            editor.change_selections(Default::default(), window, cx, |s| {
 4681                let mut index = 0;
 4682                s.move_cursors_with(|map, _, _| {
 4683                    let row = rows[index];
 4684                    index += 1;
 4685
 4686                    let point = Point::new(row, 0);
 4687                    let boundary = map.next_line_boundary(point).1;
 4688                    let clipped = map.clip_point(boundary, Bias::Left);
 4689
 4690                    (clipped, SelectionGoal::None)
 4691                });
 4692            });
 4693
 4694            let mut indent_edits = Vec::new();
 4695            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4696            for row in rows {
 4697                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4698                for (row, indent) in indents {
 4699                    if indent.len == 0 {
 4700                        continue;
 4701                    }
 4702
 4703                    let text = match indent.kind {
 4704                        IndentKind::Space => " ".repeat(indent.len as usize),
 4705                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4706                    };
 4707                    let point = Point::new(row.0, 0);
 4708                    indent_edits.push((point..point, text));
 4709                }
 4710            }
 4711            editor.edit(indent_edits, cx);
 4712        });
 4713    }
 4714
 4715    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4717
 4718        let buffer = self.buffer.read(cx);
 4719        let snapshot = buffer.snapshot(cx);
 4720
 4721        let mut edits = Vec::new();
 4722        let mut rows = Vec::new();
 4723        let mut rows_inserted = 0;
 4724
 4725        for selection in self.selections.all_adjusted(cx) {
 4726            let cursor = selection.head();
 4727            let row = cursor.row;
 4728
 4729            let point = Point::new(row + 1, 0);
 4730            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4731
 4732            let newline = "\n".to_string();
 4733            edits.push((start_of_line..start_of_line, newline));
 4734
 4735            rows_inserted += 1;
 4736            rows.push(row + rows_inserted);
 4737        }
 4738
 4739        self.transact(window, cx, |editor, window, cx| {
 4740            editor.edit(edits, cx);
 4741
 4742            editor.change_selections(Default::default(), window, cx, |s| {
 4743                let mut index = 0;
 4744                s.move_cursors_with(|map, _, _| {
 4745                    let row = rows[index];
 4746                    index += 1;
 4747
 4748                    let point = Point::new(row, 0);
 4749                    let boundary = map.next_line_boundary(point).1;
 4750                    let clipped = map.clip_point(boundary, Bias::Left);
 4751
 4752                    (clipped, SelectionGoal::None)
 4753                });
 4754            });
 4755
 4756            let mut indent_edits = Vec::new();
 4757            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4758            for row in rows {
 4759                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4760                for (row, indent) in indents {
 4761                    if indent.len == 0 {
 4762                        continue;
 4763                    }
 4764
 4765                    let text = match indent.kind {
 4766                        IndentKind::Space => " ".repeat(indent.len as usize),
 4767                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4768                    };
 4769                    let point = Point::new(row.0, 0);
 4770                    indent_edits.push((point..point, text));
 4771                }
 4772            }
 4773            editor.edit(indent_edits, cx);
 4774        });
 4775    }
 4776
 4777    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4778        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4779            original_indent_columns: Vec::new(),
 4780        });
 4781        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4782    }
 4783
 4784    fn insert_with_autoindent_mode(
 4785        &mut self,
 4786        text: &str,
 4787        autoindent_mode: Option<AutoindentMode>,
 4788        window: &mut Window,
 4789        cx: &mut Context<Self>,
 4790    ) {
 4791        if self.read_only(cx) {
 4792            return;
 4793        }
 4794
 4795        let text: Arc<str> = text.into();
 4796        self.transact(window, cx, |this, window, cx| {
 4797            let old_selections = this.selections.all_adjusted(cx);
 4798            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4799                let anchors = {
 4800                    let snapshot = buffer.read(cx);
 4801                    old_selections
 4802                        .iter()
 4803                        .map(|s| {
 4804                            let anchor = snapshot.anchor_after(s.head());
 4805                            s.map(|_| anchor)
 4806                        })
 4807                        .collect::<Vec<_>>()
 4808                };
 4809                buffer.edit(
 4810                    old_selections
 4811                        .iter()
 4812                        .map(|s| (s.start..s.end, text.clone())),
 4813                    autoindent_mode,
 4814                    cx,
 4815                );
 4816                anchors
 4817            });
 4818
 4819            this.change_selections(Default::default(), window, cx, |s| {
 4820                s.select_anchors(selection_anchors);
 4821            });
 4822
 4823            cx.notify();
 4824        });
 4825    }
 4826
 4827    fn trigger_completion_on_input(
 4828        &mut self,
 4829        text: &str,
 4830        trigger_in_words: bool,
 4831        window: &mut Window,
 4832        cx: &mut Context<Self>,
 4833    ) {
 4834        let completions_source = self
 4835            .context_menu
 4836            .borrow()
 4837            .as_ref()
 4838            .and_then(|menu| match menu {
 4839                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4840                CodeContextMenu::CodeActions(_) => None,
 4841            });
 4842
 4843        match completions_source {
 4844            Some(CompletionsMenuSource::Words) => {
 4845                self.show_word_completions(&ShowWordCompletions, window, cx)
 4846            }
 4847            Some(CompletionsMenuSource::Normal)
 4848            | Some(CompletionsMenuSource::SnippetChoices)
 4849            | None
 4850                if self.is_completion_trigger(
 4851                    text,
 4852                    trigger_in_words,
 4853                    completions_source.is_some(),
 4854                    cx,
 4855                ) =>
 4856            {
 4857                self.show_completions(
 4858                    &ShowCompletions {
 4859                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4860                    },
 4861                    window,
 4862                    cx,
 4863                )
 4864            }
 4865            _ => {
 4866                self.hide_context_menu(window, cx);
 4867            }
 4868        }
 4869    }
 4870
 4871    fn is_completion_trigger(
 4872        &self,
 4873        text: &str,
 4874        trigger_in_words: bool,
 4875        menu_is_open: bool,
 4876        cx: &mut Context<Self>,
 4877    ) -> bool {
 4878        let position = self.selections.newest_anchor().head();
 4879        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4880            return false;
 4881        };
 4882
 4883        if let Some(completion_provider) = &self.completion_provider {
 4884            completion_provider.is_completion_trigger(
 4885                &buffer,
 4886                position.text_anchor,
 4887                text,
 4888                trigger_in_words,
 4889                menu_is_open,
 4890                cx,
 4891            )
 4892        } else {
 4893            false
 4894        }
 4895    }
 4896
 4897    /// If any empty selections is touching the start of its innermost containing autoclose
 4898    /// region, expand it to select the brackets.
 4899    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4900        let selections = self.selections.all::<usize>(cx);
 4901        let buffer = self.buffer.read(cx).read(cx);
 4902        let new_selections = self
 4903            .selections_with_autoclose_regions(selections, &buffer)
 4904            .map(|(mut selection, region)| {
 4905                if !selection.is_empty() {
 4906                    return selection;
 4907                }
 4908
 4909                if let Some(region) = region {
 4910                    let mut range = region.range.to_offset(&buffer);
 4911                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4912                        range.start -= region.pair.start.len();
 4913                        if buffer.contains_str_at(range.start, &region.pair.start)
 4914                            && buffer.contains_str_at(range.end, &region.pair.end)
 4915                        {
 4916                            range.end += region.pair.end.len();
 4917                            selection.start = range.start;
 4918                            selection.end = range.end;
 4919
 4920                            return selection;
 4921                        }
 4922                    }
 4923                }
 4924
 4925                let always_treat_brackets_as_autoclosed = buffer
 4926                    .language_settings_at(selection.start, cx)
 4927                    .always_treat_brackets_as_autoclosed;
 4928
 4929                if !always_treat_brackets_as_autoclosed {
 4930                    return selection;
 4931                }
 4932
 4933                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4934                    for (pair, enabled) in scope.brackets() {
 4935                        if !enabled || !pair.close {
 4936                            continue;
 4937                        }
 4938
 4939                        if buffer.contains_str_at(selection.start, &pair.end) {
 4940                            let pair_start_len = pair.start.len();
 4941                            if buffer.contains_str_at(
 4942                                selection.start.saturating_sub(pair_start_len),
 4943                                &pair.start,
 4944                            ) {
 4945                                selection.start -= pair_start_len;
 4946                                selection.end += pair.end.len();
 4947
 4948                                return selection;
 4949                            }
 4950                        }
 4951                    }
 4952                }
 4953
 4954                selection
 4955            })
 4956            .collect();
 4957
 4958        drop(buffer);
 4959        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4960            selections.select(new_selections)
 4961        });
 4962    }
 4963
 4964    /// Iterate the given selections, and for each one, find the smallest surrounding
 4965    /// autoclose region. This uses the ordering of the selections and the autoclose
 4966    /// regions to avoid repeated comparisons.
 4967    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4968        &'a self,
 4969        selections: impl IntoIterator<Item = Selection<D>>,
 4970        buffer: &'a MultiBufferSnapshot,
 4971    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4972        let mut i = 0;
 4973        let mut regions = self.autoclose_regions.as_slice();
 4974        selections.into_iter().map(move |selection| {
 4975            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4976
 4977            let mut enclosing = None;
 4978            while let Some(pair_state) = regions.get(i) {
 4979                if pair_state.range.end.to_offset(buffer) < range.start {
 4980                    regions = &regions[i + 1..];
 4981                    i = 0;
 4982                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4983                    break;
 4984                } else {
 4985                    if pair_state.selection_id == selection.id {
 4986                        enclosing = Some(pair_state);
 4987                    }
 4988                    i += 1;
 4989                }
 4990            }
 4991
 4992            (selection, enclosing)
 4993        })
 4994    }
 4995
 4996    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4997    fn invalidate_autoclose_regions(
 4998        &mut self,
 4999        mut selections: &[Selection<Anchor>],
 5000        buffer: &MultiBufferSnapshot,
 5001    ) {
 5002        self.autoclose_regions.retain(|state| {
 5003            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5004                return false;
 5005            }
 5006
 5007            let mut i = 0;
 5008            while let Some(selection) = selections.get(i) {
 5009                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5010                    selections = &selections[1..];
 5011                    continue;
 5012                }
 5013                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5014                    break;
 5015                }
 5016                if selection.id == state.selection_id {
 5017                    return true;
 5018                } else {
 5019                    i += 1;
 5020                }
 5021            }
 5022            false
 5023        });
 5024    }
 5025
 5026    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5027        let offset = position.to_offset(buffer);
 5028        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5029        if offset > word_range.start && kind == Some(CharKind::Word) {
 5030            Some(
 5031                buffer
 5032                    .text_for_range(word_range.start..offset)
 5033                    .collect::<String>(),
 5034            )
 5035        } else {
 5036            None
 5037        }
 5038    }
 5039
 5040    pub fn toggle_inline_values(
 5041        &mut self,
 5042        _: &ToggleInlineValues,
 5043        _: &mut Window,
 5044        cx: &mut Context<Self>,
 5045    ) {
 5046        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5047
 5048        self.refresh_inline_values(cx);
 5049    }
 5050
 5051    pub fn toggle_inlay_hints(
 5052        &mut self,
 5053        _: &ToggleInlayHints,
 5054        _: &mut Window,
 5055        cx: &mut Context<Self>,
 5056    ) {
 5057        self.refresh_inlay_hints(
 5058            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5059            cx,
 5060        );
 5061    }
 5062
 5063    pub fn inlay_hints_enabled(&self) -> bool {
 5064        self.inlay_hint_cache.enabled
 5065    }
 5066
 5067    pub fn inline_values_enabled(&self) -> bool {
 5068        self.inline_value_cache.enabled
 5069    }
 5070
 5071    #[cfg(any(test, feature = "test-support"))]
 5072    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5073        self.display_map
 5074            .read(cx)
 5075            .current_inlays()
 5076            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5077            .cloned()
 5078            .collect()
 5079    }
 5080
 5081    #[cfg(any(test, feature = "test-support"))]
 5082    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5083        self.display_map
 5084            .read(cx)
 5085            .current_inlays()
 5086            .cloned()
 5087            .collect()
 5088    }
 5089
 5090    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5091        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5092            return;
 5093        }
 5094
 5095        let reason_description = reason.description();
 5096        let ignore_debounce = matches!(
 5097            reason,
 5098            InlayHintRefreshReason::SettingsChange(_)
 5099                | InlayHintRefreshReason::Toggle(_)
 5100                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5101                | InlayHintRefreshReason::ModifiersChanged(_)
 5102        );
 5103        let (invalidate_cache, required_languages) = match reason {
 5104            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5105                match self.inlay_hint_cache.modifiers_override(enabled) {
 5106                    Some(enabled) => {
 5107                        if enabled {
 5108                            (InvalidationStrategy::RefreshRequested, None)
 5109                        } else {
 5110                            self.splice_inlays(
 5111                                &self
 5112                                    .visible_inlay_hints(cx)
 5113                                    .iter()
 5114                                    .map(|inlay| inlay.id)
 5115                                    .collect::<Vec<InlayId>>(),
 5116                                Vec::new(),
 5117                                cx,
 5118                            );
 5119                            return;
 5120                        }
 5121                    }
 5122                    None => return,
 5123                }
 5124            }
 5125            InlayHintRefreshReason::Toggle(enabled) => {
 5126                if self.inlay_hint_cache.toggle(enabled) {
 5127                    if enabled {
 5128                        (InvalidationStrategy::RefreshRequested, None)
 5129                    } else {
 5130                        self.splice_inlays(
 5131                            &self
 5132                                .visible_inlay_hints(cx)
 5133                                .iter()
 5134                                .map(|inlay| inlay.id)
 5135                                .collect::<Vec<InlayId>>(),
 5136                            Vec::new(),
 5137                            cx,
 5138                        );
 5139                        return;
 5140                    }
 5141                } else {
 5142                    return;
 5143                }
 5144            }
 5145            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5146                match self.inlay_hint_cache.update_settings(
 5147                    &self.buffer,
 5148                    new_settings,
 5149                    self.visible_inlay_hints(cx),
 5150                    cx,
 5151                ) {
 5152                    ControlFlow::Break(Some(InlaySplice {
 5153                        to_remove,
 5154                        to_insert,
 5155                    })) => {
 5156                        self.splice_inlays(&to_remove, to_insert, cx);
 5157                        return;
 5158                    }
 5159                    ControlFlow::Break(None) => return,
 5160                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5161                }
 5162            }
 5163            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5164                if let Some(InlaySplice {
 5165                    to_remove,
 5166                    to_insert,
 5167                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5168                {
 5169                    self.splice_inlays(&to_remove, to_insert, cx);
 5170                }
 5171                self.display_map.update(cx, |display_map, _| {
 5172                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5173                });
 5174                return;
 5175            }
 5176            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5177            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5178                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5179            }
 5180            InlayHintRefreshReason::RefreshRequested => {
 5181                (InvalidationStrategy::RefreshRequested, None)
 5182            }
 5183        };
 5184
 5185        if let Some(InlaySplice {
 5186            to_remove,
 5187            to_insert,
 5188        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5189            reason_description,
 5190            self.visible_excerpts(required_languages.as_ref(), cx),
 5191            invalidate_cache,
 5192            ignore_debounce,
 5193            cx,
 5194        ) {
 5195            self.splice_inlays(&to_remove, to_insert, cx);
 5196        }
 5197    }
 5198
 5199    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5200        self.display_map
 5201            .read(cx)
 5202            .current_inlays()
 5203            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5204            .cloned()
 5205            .collect()
 5206    }
 5207
 5208    pub fn visible_excerpts(
 5209        &self,
 5210        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5211        cx: &mut Context<Editor>,
 5212    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5213        let Some(project) = self.project() else {
 5214            return HashMap::default();
 5215        };
 5216        let project = project.read(cx);
 5217        let multi_buffer = self.buffer().read(cx);
 5218        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5219        let multi_buffer_visible_start = self
 5220            .scroll_manager
 5221            .anchor()
 5222            .anchor
 5223            .to_point(&multi_buffer_snapshot);
 5224        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5225            multi_buffer_visible_start
 5226                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5227            Bias::Left,
 5228        );
 5229        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5230        multi_buffer_snapshot
 5231            .range_to_buffer_ranges(multi_buffer_visible_range)
 5232            .into_iter()
 5233            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5234            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5235                let buffer_file = project::File::from_dyn(buffer.file())?;
 5236                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5237                let worktree_entry = buffer_worktree
 5238                    .read(cx)
 5239                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5240                if worktree_entry.is_ignored {
 5241                    return None;
 5242                }
 5243
 5244                let language = buffer.language()?;
 5245                if let Some(restrict_to_languages) = restrict_to_languages
 5246                    && !restrict_to_languages.contains(language)
 5247                {
 5248                    return None;
 5249                }
 5250                Some((
 5251                    excerpt_id,
 5252                    (
 5253                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5254                        buffer.version().clone(),
 5255                        excerpt_visible_range,
 5256                    ),
 5257                ))
 5258            })
 5259            .collect()
 5260    }
 5261
 5262    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5263        TextLayoutDetails {
 5264            text_system: window.text_system().clone(),
 5265            editor_style: self.style.clone().unwrap(),
 5266            rem_size: window.rem_size(),
 5267            scroll_anchor: self.scroll_manager.anchor(),
 5268            visible_rows: self.visible_line_count(),
 5269            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5270        }
 5271    }
 5272
 5273    pub fn splice_inlays(
 5274        &self,
 5275        to_remove: &[InlayId],
 5276        to_insert: Vec<Inlay>,
 5277        cx: &mut Context<Self>,
 5278    ) {
 5279        self.display_map.update(cx, |display_map, cx| {
 5280            display_map.splice_inlays(to_remove, to_insert, cx)
 5281        });
 5282        cx.notify();
 5283    }
 5284
 5285    fn trigger_on_type_formatting(
 5286        &self,
 5287        input: String,
 5288        window: &mut Window,
 5289        cx: &mut Context<Self>,
 5290    ) -> Option<Task<Result<()>>> {
 5291        if input.len() != 1 {
 5292            return None;
 5293        }
 5294
 5295        let project = self.project()?;
 5296        let position = self.selections.newest_anchor().head();
 5297        let (buffer, buffer_position) = self
 5298            .buffer
 5299            .read(cx)
 5300            .text_anchor_for_position(position, cx)?;
 5301
 5302        let settings = language_settings::language_settings(
 5303            buffer
 5304                .read(cx)
 5305                .language_at(buffer_position)
 5306                .map(|l| l.name()),
 5307            buffer.read(cx).file(),
 5308            cx,
 5309        );
 5310        if !settings.use_on_type_format {
 5311            return None;
 5312        }
 5313
 5314        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5315        // hence we do LSP request & edit on host side only — add formats to host's history.
 5316        let push_to_lsp_host_history = true;
 5317        // If this is not the host, append its history with new edits.
 5318        let push_to_client_history = project.read(cx).is_via_collab();
 5319
 5320        let on_type_formatting = project.update(cx, |project, cx| {
 5321            project.on_type_format(
 5322                buffer.clone(),
 5323                buffer_position,
 5324                input,
 5325                push_to_lsp_host_history,
 5326                cx,
 5327            )
 5328        });
 5329        Some(cx.spawn_in(window, async move |editor, cx| {
 5330            if let Some(transaction) = on_type_formatting.await? {
 5331                if push_to_client_history {
 5332                    buffer
 5333                        .update(cx, |buffer, _| {
 5334                            buffer.push_transaction(transaction, Instant::now());
 5335                            buffer.finalize_last_transaction();
 5336                        })
 5337                        .ok();
 5338                }
 5339                editor.update(cx, |editor, cx| {
 5340                    editor.refresh_document_highlights(cx);
 5341                })?;
 5342            }
 5343            Ok(())
 5344        }))
 5345    }
 5346
 5347    pub fn show_word_completions(
 5348        &mut self,
 5349        _: &ShowWordCompletions,
 5350        window: &mut Window,
 5351        cx: &mut Context<Self>,
 5352    ) {
 5353        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5354    }
 5355
 5356    pub fn show_completions(
 5357        &mut self,
 5358        options: &ShowCompletions,
 5359        window: &mut Window,
 5360        cx: &mut Context<Self>,
 5361    ) {
 5362        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5363    }
 5364
 5365    fn open_or_update_completions_menu(
 5366        &mut self,
 5367        requested_source: Option<CompletionsMenuSource>,
 5368        trigger: Option<&str>,
 5369        window: &mut Window,
 5370        cx: &mut Context<Self>,
 5371    ) {
 5372        if self.pending_rename.is_some() {
 5373            return;
 5374        }
 5375
 5376        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5377
 5378        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5379        // inserted and selected. To handle that case, the start of the selection is used so that
 5380        // the menu starts with all choices.
 5381        let position = self
 5382            .selections
 5383            .newest_anchor()
 5384            .start
 5385            .bias_right(&multibuffer_snapshot);
 5386        if position.diff_base_anchor.is_some() {
 5387            return;
 5388        }
 5389        let (buffer, buffer_position) =
 5390            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5391                output
 5392            } else {
 5393                return;
 5394            };
 5395        let buffer_snapshot = buffer.read(cx).snapshot();
 5396
 5397        let query: Option<Arc<String>> =
 5398            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5399
 5400        drop(multibuffer_snapshot);
 5401
 5402        let provider = match requested_source {
 5403            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5404            Some(CompletionsMenuSource::Words) => None,
 5405            Some(CompletionsMenuSource::SnippetChoices) => {
 5406                log::error!("bug: SnippetChoices requested_source is not handled");
 5407                None
 5408            }
 5409        };
 5410
 5411        let sort_completions = provider
 5412            .as_ref()
 5413            .is_some_and(|provider| provider.sort_completions());
 5414
 5415        let filter_completions = provider
 5416            .as_ref()
 5417            .is_none_or(|provider| provider.filter_completions());
 5418
 5419        let trigger_kind = match trigger {
 5420            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5421                CompletionTriggerKind::TRIGGER_CHARACTER
 5422            }
 5423            _ => CompletionTriggerKind::INVOKED,
 5424        };
 5425        let completion_context = CompletionContext {
 5426            trigger_character: trigger.and_then(|trigger| {
 5427                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5428                    Some(String::from(trigger))
 5429                } else {
 5430                    None
 5431                }
 5432            }),
 5433            trigger_kind,
 5434        };
 5435
 5436        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5437        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5438        // involve trigger chars, so this is skipped in that case.
 5439        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5440        {
 5441            let menu_is_open = matches!(
 5442                self.context_menu.borrow().as_ref(),
 5443                Some(CodeContextMenu::Completions(_))
 5444            );
 5445            if menu_is_open {
 5446                self.hide_context_menu(window, cx);
 5447            }
 5448        }
 5449
 5450        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5451            if filter_completions {
 5452                menu.filter(query.clone(), provider.clone(), window, cx);
 5453            }
 5454            // When `is_incomplete` is false, no need to re-query completions when the current query
 5455            // is a suffix of the initial query.
 5456            if !menu.is_incomplete {
 5457                // If the new query is a suffix of the old query (typing more characters) and
 5458                // the previous result was complete, the existing completions can be filtered.
 5459                //
 5460                // Note that this is always true for snippet completions.
 5461                let query_matches = match (&menu.initial_query, &query) {
 5462                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5463                    (None, _) => true,
 5464                    _ => false,
 5465                };
 5466                if query_matches {
 5467                    let position_matches = if menu.initial_position == position {
 5468                        true
 5469                    } else {
 5470                        let snapshot = self.buffer.read(cx).read(cx);
 5471                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5472                    };
 5473                    if position_matches {
 5474                        return;
 5475                    }
 5476                }
 5477            }
 5478        };
 5479
 5480        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5481            buffer_snapshot.surrounding_word(buffer_position, false)
 5482        {
 5483            let word_to_exclude = buffer_snapshot
 5484                .text_for_range(word_range.clone())
 5485                .collect::<String>();
 5486            (
 5487                buffer_snapshot.anchor_before(word_range.start)
 5488                    ..buffer_snapshot.anchor_after(buffer_position),
 5489                Some(word_to_exclude),
 5490            )
 5491        } else {
 5492            (buffer_position..buffer_position, None)
 5493        };
 5494
 5495        let language = buffer_snapshot
 5496            .language_at(buffer_position)
 5497            .map(|language| language.name());
 5498
 5499        let completion_settings =
 5500            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5501
 5502        let show_completion_documentation = buffer_snapshot
 5503            .settings_at(buffer_position, cx)
 5504            .show_completion_documentation;
 5505
 5506        // The document can be large, so stay in reasonable bounds when searching for words,
 5507        // otherwise completion pop-up might be slow to appear.
 5508        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5509        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5510        let min_word_search = buffer_snapshot.clip_point(
 5511            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5512            Bias::Left,
 5513        );
 5514        let max_word_search = buffer_snapshot.clip_point(
 5515            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5516            Bias::Right,
 5517        );
 5518        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5519            ..buffer_snapshot.point_to_offset(max_word_search);
 5520
 5521        let skip_digits = query
 5522            .as_ref()
 5523            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5524
 5525        let (mut words, provider_responses) = match &provider {
 5526            Some(provider) => {
 5527                let provider_responses = provider.completions(
 5528                    position.excerpt_id,
 5529                    &buffer,
 5530                    buffer_position,
 5531                    completion_context,
 5532                    window,
 5533                    cx,
 5534                );
 5535
 5536                let words = match completion_settings.words {
 5537                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5538                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5539                        .background_spawn(async move {
 5540                            buffer_snapshot.words_in_range(WordsQuery {
 5541                                fuzzy_contents: None,
 5542                                range: word_search_range,
 5543                                skip_digits,
 5544                            })
 5545                        }),
 5546                };
 5547
 5548                (words, provider_responses)
 5549            }
 5550            None => (
 5551                cx.background_spawn(async move {
 5552                    buffer_snapshot.words_in_range(WordsQuery {
 5553                        fuzzy_contents: None,
 5554                        range: word_search_range,
 5555                        skip_digits,
 5556                    })
 5557                }),
 5558                Task::ready(Ok(Vec::new())),
 5559            ),
 5560        };
 5561
 5562        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5563
 5564        let id = post_inc(&mut self.next_completion_id);
 5565        let task = cx.spawn_in(window, async move |editor, cx| {
 5566            let Ok(()) = editor.update(cx, |this, _| {
 5567                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5568            }) else {
 5569                return;
 5570            };
 5571
 5572            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5573            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5574            let mut completions = Vec::new();
 5575            let mut is_incomplete = false;
 5576            if let Some(provider_responses) = provider_responses.await.log_err()
 5577                && !provider_responses.is_empty()
 5578            {
 5579                for response in provider_responses {
 5580                    completions.extend(response.completions);
 5581                    is_incomplete = is_incomplete || response.is_incomplete;
 5582                }
 5583                if completion_settings.words == WordsCompletionMode::Fallback {
 5584                    words = Task::ready(BTreeMap::default());
 5585                }
 5586            }
 5587
 5588            let mut words = words.await;
 5589            if let Some(word_to_exclude) = &word_to_exclude {
 5590                words.remove(word_to_exclude);
 5591            }
 5592            for lsp_completion in &completions {
 5593                words.remove(&lsp_completion.new_text);
 5594            }
 5595            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5596                replace_range: word_replace_range.clone(),
 5597                new_text: word.clone(),
 5598                label: CodeLabel::plain(word, None),
 5599                icon_path: None,
 5600                documentation: None,
 5601                source: CompletionSource::BufferWord {
 5602                    word_range,
 5603                    resolved: false,
 5604                },
 5605                insert_text_mode: Some(InsertTextMode::AS_IS),
 5606                confirm: None,
 5607            }));
 5608
 5609            let menu = if completions.is_empty() {
 5610                None
 5611            } else {
 5612                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5613                    let languages = editor
 5614                        .workspace
 5615                        .as_ref()
 5616                        .and_then(|(workspace, _)| workspace.upgrade())
 5617                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5618                    let menu = CompletionsMenu::new(
 5619                        id,
 5620                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5621                        sort_completions,
 5622                        show_completion_documentation,
 5623                        position,
 5624                        query.clone(),
 5625                        is_incomplete,
 5626                        buffer.clone(),
 5627                        completions.into(),
 5628                        snippet_sort_order,
 5629                        languages,
 5630                        language,
 5631                        cx,
 5632                    );
 5633
 5634                    let query = if filter_completions { query } else { None };
 5635                    let matches_task = if let Some(query) = query {
 5636                        menu.do_async_filtering(query, cx)
 5637                    } else {
 5638                        Task::ready(menu.unfiltered_matches())
 5639                    };
 5640                    (menu, matches_task)
 5641                }) else {
 5642                    return;
 5643                };
 5644
 5645                let matches = matches_task.await;
 5646
 5647                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5648                    // Newer menu already set, so exit.
 5649                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5650                        editor.context_menu.borrow().as_ref()
 5651                        && prev_menu.id > id
 5652                    {
 5653                        return;
 5654                    };
 5655
 5656                    // Only valid to take prev_menu because it the new menu is immediately set
 5657                    // below, or the menu is hidden.
 5658                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5659                        editor.context_menu.borrow_mut().take()
 5660                    {
 5661                        let position_matches =
 5662                            if prev_menu.initial_position == menu.initial_position {
 5663                                true
 5664                            } else {
 5665                                let snapshot = editor.buffer.read(cx).read(cx);
 5666                                prev_menu.initial_position.to_offset(&snapshot)
 5667                                    == menu.initial_position.to_offset(&snapshot)
 5668                            };
 5669                        if position_matches {
 5670                            // Preserve markdown cache before `set_filter_results` because it will
 5671                            // try to populate the documentation cache.
 5672                            menu.preserve_markdown_cache(prev_menu);
 5673                        }
 5674                    };
 5675
 5676                    menu.set_filter_results(matches, provider, window, cx);
 5677                }) else {
 5678                    return;
 5679                };
 5680
 5681                menu.visible().then_some(menu)
 5682            };
 5683
 5684            editor
 5685                .update_in(cx, |editor, window, cx| {
 5686                    if editor.focus_handle.is_focused(window)
 5687                        && let Some(menu) = menu
 5688                    {
 5689                        *editor.context_menu.borrow_mut() =
 5690                            Some(CodeContextMenu::Completions(menu));
 5691
 5692                        crate::hover_popover::hide_hover(editor, cx);
 5693                        if editor.show_edit_predictions_in_menu() {
 5694                            editor.update_visible_edit_prediction(window, cx);
 5695                        } else {
 5696                            editor.discard_edit_prediction(false, cx);
 5697                        }
 5698
 5699                        cx.notify();
 5700                        return;
 5701                    }
 5702
 5703                    if editor.completion_tasks.len() <= 1 {
 5704                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5705                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5706                        // If it was already hidden and we don't show edit predictions in the menu,
 5707                        // we should also show the edit prediction when available.
 5708                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5709                            editor.update_visible_edit_prediction(window, cx);
 5710                        }
 5711                    }
 5712                })
 5713                .ok();
 5714        });
 5715
 5716        self.completion_tasks.push((id, task));
 5717    }
 5718
 5719    #[cfg(feature = "test-support")]
 5720    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5721        let menu = self.context_menu.borrow();
 5722        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5723            let completions = menu.completions.borrow();
 5724            Some(completions.to_vec())
 5725        } else {
 5726            None
 5727        }
 5728    }
 5729
 5730    pub fn with_completions_menu_matching_id<R>(
 5731        &self,
 5732        id: CompletionId,
 5733        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5734    ) -> R {
 5735        let mut context_menu = self.context_menu.borrow_mut();
 5736        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5737            return f(None);
 5738        };
 5739        if completions_menu.id != id {
 5740            return f(None);
 5741        }
 5742        f(Some(completions_menu))
 5743    }
 5744
 5745    pub fn confirm_completion(
 5746        &mut self,
 5747        action: &ConfirmCompletion,
 5748        window: &mut Window,
 5749        cx: &mut Context<Self>,
 5750    ) -> Option<Task<Result<()>>> {
 5751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5752        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5753    }
 5754
 5755    pub fn confirm_completion_insert(
 5756        &mut self,
 5757        _: &ConfirmCompletionInsert,
 5758        window: &mut Window,
 5759        cx: &mut Context<Self>,
 5760    ) -> Option<Task<Result<()>>> {
 5761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5762        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5763    }
 5764
 5765    pub fn confirm_completion_replace(
 5766        &mut self,
 5767        _: &ConfirmCompletionReplace,
 5768        window: &mut Window,
 5769        cx: &mut Context<Self>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5772        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5773    }
 5774
 5775    pub fn compose_completion(
 5776        &mut self,
 5777        action: &ComposeCompletion,
 5778        window: &mut Window,
 5779        cx: &mut Context<Self>,
 5780    ) -> Option<Task<Result<()>>> {
 5781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5782        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5783    }
 5784
 5785    fn do_completion(
 5786        &mut self,
 5787        item_ix: Option<usize>,
 5788        intent: CompletionIntent,
 5789        window: &mut Window,
 5790        cx: &mut Context<Editor>,
 5791    ) -> Option<Task<Result<()>>> {
 5792        use language::ToOffset as _;
 5793
 5794        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5795        else {
 5796            return None;
 5797        };
 5798
 5799        let candidate_id = {
 5800            let entries = completions_menu.entries.borrow();
 5801            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5802            if self.show_edit_predictions_in_menu() {
 5803                self.discard_edit_prediction(true, cx);
 5804            }
 5805            mat.candidate_id
 5806        };
 5807
 5808        let completion = completions_menu
 5809            .completions
 5810            .borrow()
 5811            .get(candidate_id)?
 5812            .clone();
 5813        cx.stop_propagation();
 5814
 5815        let buffer_handle = completions_menu.buffer.clone();
 5816
 5817        let CompletionEdit {
 5818            new_text,
 5819            snippet,
 5820            replace_range,
 5821        } = process_completion_for_edit(
 5822            &completion,
 5823            intent,
 5824            &buffer_handle,
 5825            &completions_menu.initial_position.text_anchor,
 5826            cx,
 5827        );
 5828
 5829        let buffer = buffer_handle.read(cx);
 5830        let snapshot = self.buffer.read(cx).snapshot(cx);
 5831        let newest_anchor = self.selections.newest_anchor();
 5832        let replace_range_multibuffer = {
 5833            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5834            let multibuffer_anchor = snapshot
 5835                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5836                .unwrap()
 5837                ..snapshot
 5838                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5839                    .unwrap();
 5840            multibuffer_anchor.start.to_offset(&snapshot)
 5841                ..multibuffer_anchor.end.to_offset(&snapshot)
 5842        };
 5843        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5844            return None;
 5845        }
 5846
 5847        let old_text = buffer
 5848            .text_for_range(replace_range.clone())
 5849            .collect::<String>();
 5850        let lookbehind = newest_anchor
 5851            .start
 5852            .text_anchor
 5853            .to_offset(buffer)
 5854            .saturating_sub(replace_range.start);
 5855        let lookahead = replace_range
 5856            .end
 5857            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5858        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5859        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5860
 5861        let selections = self.selections.all::<usize>(cx);
 5862        let mut ranges = Vec::new();
 5863        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5864
 5865        for selection in &selections {
 5866            let range = if selection.id == newest_anchor.id {
 5867                replace_range_multibuffer.clone()
 5868            } else {
 5869                let mut range = selection.range();
 5870
 5871                // if prefix is present, don't duplicate it
 5872                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5873                    range.start = range.start.saturating_sub(lookbehind);
 5874
 5875                    // if suffix is also present, mimic the newest cursor and replace it
 5876                    if selection.id != newest_anchor.id
 5877                        && snapshot.contains_str_at(range.end, suffix)
 5878                    {
 5879                        range.end += lookahead;
 5880                    }
 5881                }
 5882                range
 5883            };
 5884
 5885            ranges.push(range.clone());
 5886
 5887            if !self.linked_edit_ranges.is_empty() {
 5888                let start_anchor = snapshot.anchor_before(range.start);
 5889                let end_anchor = snapshot.anchor_after(range.end);
 5890                if let Some(ranges) = self
 5891                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5892                {
 5893                    for (buffer, edits) in ranges {
 5894                        linked_edits
 5895                            .entry(buffer.clone())
 5896                            .or_default()
 5897                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5898                    }
 5899                }
 5900            }
 5901        }
 5902
 5903        let common_prefix_len = old_text
 5904            .chars()
 5905            .zip(new_text.chars())
 5906            .take_while(|(a, b)| a == b)
 5907            .map(|(a, _)| a.len_utf8())
 5908            .sum::<usize>();
 5909
 5910        cx.emit(EditorEvent::InputHandled {
 5911            utf16_range_to_replace: None,
 5912            text: new_text[common_prefix_len..].into(),
 5913        });
 5914
 5915        self.transact(window, cx, |editor, window, cx| {
 5916            if let Some(mut snippet) = snippet {
 5917                snippet.text = new_text.to_string();
 5918                editor
 5919                    .insert_snippet(&ranges, snippet, window, cx)
 5920                    .log_err();
 5921            } else {
 5922                editor.buffer.update(cx, |multi_buffer, cx| {
 5923                    let auto_indent = match completion.insert_text_mode {
 5924                        Some(InsertTextMode::AS_IS) => None,
 5925                        _ => editor.autoindent_mode.clone(),
 5926                    };
 5927                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5928                    multi_buffer.edit(edits, auto_indent, cx);
 5929                });
 5930            }
 5931            for (buffer, edits) in linked_edits {
 5932                buffer.update(cx, |buffer, cx| {
 5933                    let snapshot = buffer.snapshot();
 5934                    let edits = edits
 5935                        .into_iter()
 5936                        .map(|(range, text)| {
 5937                            use text::ToPoint as TP;
 5938                            let end_point = TP::to_point(&range.end, &snapshot);
 5939                            let start_point = TP::to_point(&range.start, &snapshot);
 5940                            (start_point..end_point, text)
 5941                        })
 5942                        .sorted_by_key(|(range, _)| range.start);
 5943                    buffer.edit(edits, None, cx);
 5944                })
 5945            }
 5946
 5947            editor.refresh_edit_prediction(true, false, window, cx);
 5948        });
 5949        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5950
 5951        let show_new_completions_on_confirm = completion
 5952            .confirm
 5953            .as_ref()
 5954            .is_some_and(|confirm| confirm(intent, window, cx));
 5955        if show_new_completions_on_confirm {
 5956            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5957        }
 5958
 5959        let provider = self.completion_provider.as_ref()?;
 5960        drop(completion);
 5961        let apply_edits = provider.apply_additional_edits_for_completion(
 5962            buffer_handle,
 5963            completions_menu.completions.clone(),
 5964            candidate_id,
 5965            true,
 5966            cx,
 5967        );
 5968
 5969        let editor_settings = EditorSettings::get_global(cx);
 5970        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5971            // After the code completion is finished, users often want to know what signatures are needed.
 5972            // so we should automatically call signature_help
 5973            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5974        }
 5975
 5976        Some(cx.foreground_executor().spawn(async move {
 5977            apply_edits.await?;
 5978            Ok(())
 5979        }))
 5980    }
 5981
 5982    pub fn toggle_code_actions(
 5983        &mut self,
 5984        action: &ToggleCodeActions,
 5985        window: &mut Window,
 5986        cx: &mut Context<Self>,
 5987    ) {
 5988        let quick_launch = action.quick_launch;
 5989        let mut context_menu = self.context_menu.borrow_mut();
 5990        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5991            if code_actions.deployed_from == action.deployed_from {
 5992                // Toggle if we're selecting the same one
 5993                *context_menu = None;
 5994                cx.notify();
 5995                return;
 5996            } else {
 5997                // Otherwise, clear it and start a new one
 5998                *context_menu = None;
 5999                cx.notify();
 6000            }
 6001        }
 6002        drop(context_menu);
 6003        let snapshot = self.snapshot(window, cx);
 6004        let deployed_from = action.deployed_from.clone();
 6005        let action = action.clone();
 6006        self.completion_tasks.clear();
 6007        self.discard_edit_prediction(false, cx);
 6008
 6009        let multibuffer_point = match &action.deployed_from {
 6010            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6011                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6012            }
 6013            _ => self.selections.newest::<Point>(cx).head(),
 6014        };
 6015        let Some((buffer, buffer_row)) = snapshot
 6016            .buffer_snapshot
 6017            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6018            .and_then(|(buffer_snapshot, range)| {
 6019                self.buffer()
 6020                    .read(cx)
 6021                    .buffer(buffer_snapshot.remote_id())
 6022                    .map(|buffer| (buffer, range.start.row))
 6023            })
 6024        else {
 6025            return;
 6026        };
 6027        let buffer_id = buffer.read(cx).remote_id();
 6028        let tasks = self
 6029            .tasks
 6030            .get(&(buffer_id, buffer_row))
 6031            .map(|t| Arc::new(t.to_owned()));
 6032
 6033        if !self.focus_handle.is_focused(window) {
 6034            return;
 6035        }
 6036        let project = self.project.clone();
 6037
 6038        let code_actions_task = match deployed_from {
 6039            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6040            _ => self.code_actions(buffer_row, window, cx),
 6041        };
 6042
 6043        let runnable_task = match deployed_from {
 6044            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6045            _ => {
 6046                let mut task_context_task = Task::ready(None);
 6047                if let Some(tasks) = &tasks
 6048                    && let Some(project) = project
 6049                {
 6050                    task_context_task =
 6051                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6052                }
 6053
 6054                cx.spawn_in(window, {
 6055                    let buffer = buffer.clone();
 6056                    async move |editor, cx| {
 6057                        let task_context = task_context_task.await;
 6058
 6059                        let resolved_tasks =
 6060                            tasks
 6061                                .zip(task_context.clone())
 6062                                .map(|(tasks, task_context)| ResolvedTasks {
 6063                                    templates: tasks.resolve(&task_context).collect(),
 6064                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6065                                        multibuffer_point.row,
 6066                                        tasks.column,
 6067                                    )),
 6068                                });
 6069                        let debug_scenarios = editor
 6070                            .update(cx, |editor, cx| {
 6071                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6072                            })?
 6073                            .await;
 6074                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6075                    }
 6076                })
 6077            }
 6078        };
 6079
 6080        cx.spawn_in(window, async move |editor, cx| {
 6081            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6082            let code_actions = code_actions_task.await;
 6083            let spawn_straight_away = quick_launch
 6084                && resolved_tasks
 6085                    .as_ref()
 6086                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6087                && code_actions
 6088                    .as_ref()
 6089                    .is_none_or(|actions| actions.is_empty())
 6090                && debug_scenarios.is_empty();
 6091
 6092            editor.update_in(cx, |editor, window, cx| {
 6093                crate::hover_popover::hide_hover(editor, cx);
 6094                let actions = CodeActionContents::new(
 6095                    resolved_tasks,
 6096                    code_actions,
 6097                    debug_scenarios,
 6098                    task_context.unwrap_or_default(),
 6099                );
 6100
 6101                // Don't show the menu if there are no actions available
 6102                if actions.is_empty() {
 6103                    cx.notify();
 6104                    return Task::ready(Ok(()));
 6105                }
 6106
 6107                *editor.context_menu.borrow_mut() =
 6108                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6109                        buffer,
 6110                        actions,
 6111                        selected_item: Default::default(),
 6112                        scroll_handle: UniformListScrollHandle::default(),
 6113                        deployed_from,
 6114                    }));
 6115                cx.notify();
 6116                if spawn_straight_away
 6117                    && let Some(task) = editor.confirm_code_action(
 6118                        &ConfirmCodeAction { item_ix: Some(0) },
 6119                        window,
 6120                        cx,
 6121                    )
 6122                {
 6123                    return task;
 6124                }
 6125
 6126                Task::ready(Ok(()))
 6127            })
 6128        })
 6129        .detach_and_log_err(cx);
 6130    }
 6131
 6132    fn debug_scenarios(
 6133        &mut self,
 6134        resolved_tasks: &Option<ResolvedTasks>,
 6135        buffer: &Entity<Buffer>,
 6136        cx: &mut App,
 6137    ) -> Task<Vec<task::DebugScenario>> {
 6138        maybe!({
 6139            let project = self.project()?;
 6140            let dap_store = project.read(cx).dap_store();
 6141            let mut scenarios = vec![];
 6142            let resolved_tasks = resolved_tasks.as_ref()?;
 6143            let buffer = buffer.read(cx);
 6144            let language = buffer.language()?;
 6145            let file = buffer.file();
 6146            let debug_adapter = language_settings(language.name().into(), file, cx)
 6147                .debuggers
 6148                .first()
 6149                .map(SharedString::from)
 6150                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6151
 6152            dap_store.update(cx, |dap_store, cx| {
 6153                for (_, task) in &resolved_tasks.templates {
 6154                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6155                        task.original_task().clone(),
 6156                        debug_adapter.clone().into(),
 6157                        task.display_label().to_owned().into(),
 6158                        cx,
 6159                    );
 6160                    scenarios.push(maybe_scenario);
 6161                }
 6162            });
 6163            Some(cx.background_spawn(async move {
 6164                futures::future::join_all(scenarios)
 6165                    .await
 6166                    .into_iter()
 6167                    .flatten()
 6168                    .collect::<Vec<_>>()
 6169            }))
 6170        })
 6171        .unwrap_or_else(|| Task::ready(vec![]))
 6172    }
 6173
 6174    fn code_actions(
 6175        &mut self,
 6176        buffer_row: u32,
 6177        window: &mut Window,
 6178        cx: &mut Context<Self>,
 6179    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6180        let mut task = self.code_actions_task.take();
 6181        cx.spawn_in(window, async move |editor, cx| {
 6182            while let Some(prev_task) = task {
 6183                prev_task.await.log_err();
 6184                task = editor
 6185                    .update(cx, |this, _| this.code_actions_task.take())
 6186                    .ok()?;
 6187            }
 6188
 6189            editor
 6190                .update(cx, |editor, cx| {
 6191                    editor
 6192                        .available_code_actions
 6193                        .clone()
 6194                        .and_then(|(location, code_actions)| {
 6195                            let snapshot = location.buffer.read(cx).snapshot();
 6196                            let point_range = location.range.to_point(&snapshot);
 6197                            let point_range = point_range.start.row..=point_range.end.row;
 6198                            if point_range.contains(&buffer_row) {
 6199                                Some(code_actions)
 6200                            } else {
 6201                                None
 6202                            }
 6203                        })
 6204                })
 6205                .ok()
 6206                .flatten()
 6207        })
 6208    }
 6209
 6210    pub fn confirm_code_action(
 6211        &mut self,
 6212        action: &ConfirmCodeAction,
 6213        window: &mut Window,
 6214        cx: &mut Context<Self>,
 6215    ) -> Option<Task<Result<()>>> {
 6216        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6217
 6218        let actions_menu =
 6219            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6220                menu
 6221            } else {
 6222                return None;
 6223            };
 6224
 6225        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6226        let action = actions_menu.actions.get(action_ix)?;
 6227        let title = action.label();
 6228        let buffer = actions_menu.buffer;
 6229        let workspace = self.workspace()?;
 6230
 6231        match action {
 6232            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6233                workspace.update(cx, |workspace, cx| {
 6234                    workspace.schedule_resolved_task(
 6235                        task_source_kind,
 6236                        resolved_task,
 6237                        false,
 6238                        window,
 6239                        cx,
 6240                    );
 6241
 6242                    Some(Task::ready(Ok(())))
 6243                })
 6244            }
 6245            CodeActionsItem::CodeAction {
 6246                excerpt_id,
 6247                action,
 6248                provider,
 6249            } => {
 6250                let apply_code_action =
 6251                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6252                let workspace = workspace.downgrade();
 6253                Some(cx.spawn_in(window, async move |editor, cx| {
 6254                    let project_transaction = apply_code_action.await?;
 6255                    Self::open_project_transaction(
 6256                        &editor,
 6257                        workspace,
 6258                        project_transaction,
 6259                        title,
 6260                        cx,
 6261                    )
 6262                    .await
 6263                }))
 6264            }
 6265            CodeActionsItem::DebugScenario(scenario) => {
 6266                let context = actions_menu.actions.context;
 6267
 6268                workspace.update(cx, |workspace, cx| {
 6269                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6270                    workspace.start_debug_session(
 6271                        scenario,
 6272                        context,
 6273                        Some(buffer),
 6274                        None,
 6275                        window,
 6276                        cx,
 6277                    );
 6278                });
 6279                Some(Task::ready(Ok(())))
 6280            }
 6281        }
 6282    }
 6283
 6284    pub async fn open_project_transaction(
 6285        this: &WeakEntity<Editor>,
 6286        workspace: WeakEntity<Workspace>,
 6287        transaction: ProjectTransaction,
 6288        title: String,
 6289        cx: &mut AsyncWindowContext,
 6290    ) -> Result<()> {
 6291        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6292        cx.update(|_, cx| {
 6293            entries.sort_unstable_by_key(|(buffer, _)| {
 6294                buffer.read(cx).file().map(|f| f.path().clone())
 6295            });
 6296        })?;
 6297
 6298        // If the project transaction's edits are all contained within this editor, then
 6299        // avoid opening a new editor to display them.
 6300
 6301        if let Some((buffer, transaction)) = entries.first() {
 6302            if entries.len() == 1 {
 6303                let excerpt = this.update(cx, |editor, cx| {
 6304                    editor
 6305                        .buffer()
 6306                        .read(cx)
 6307                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6308                })?;
 6309                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6310                    && excerpted_buffer == *buffer
 6311                {
 6312                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6313                        let excerpt_range = excerpt_range.to_offset(buffer);
 6314                        buffer
 6315                            .edited_ranges_for_transaction::<usize>(transaction)
 6316                            .all(|range| {
 6317                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6318                            })
 6319                    })?;
 6320
 6321                    if all_edits_within_excerpt {
 6322                        return Ok(());
 6323                    }
 6324                }
 6325            }
 6326        } else {
 6327            return Ok(());
 6328        }
 6329
 6330        let mut ranges_to_highlight = Vec::new();
 6331        let excerpt_buffer = cx.new(|cx| {
 6332            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6333            for (buffer_handle, transaction) in &entries {
 6334                let edited_ranges = buffer_handle
 6335                    .read(cx)
 6336                    .edited_ranges_for_transaction::<Point>(transaction)
 6337                    .collect::<Vec<_>>();
 6338                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6339                    PathKey::for_buffer(buffer_handle, cx),
 6340                    buffer_handle.clone(),
 6341                    edited_ranges,
 6342                    DEFAULT_MULTIBUFFER_CONTEXT,
 6343                    cx,
 6344                );
 6345
 6346                ranges_to_highlight.extend(ranges);
 6347            }
 6348            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6349            multibuffer
 6350        })?;
 6351
 6352        workspace.update_in(cx, |workspace, window, cx| {
 6353            let project = workspace.project().clone();
 6354            let editor =
 6355                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6356            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6357            editor.update(cx, |editor, cx| {
 6358                editor.highlight_background::<Self>(
 6359                    &ranges_to_highlight,
 6360                    |theme| theme.colors().editor_highlighted_line_background,
 6361                    cx,
 6362                );
 6363            });
 6364        })?;
 6365
 6366        Ok(())
 6367    }
 6368
 6369    pub fn clear_code_action_providers(&mut self) {
 6370        self.code_action_providers.clear();
 6371        self.available_code_actions.take();
 6372    }
 6373
 6374    pub fn add_code_action_provider(
 6375        &mut self,
 6376        provider: Rc<dyn CodeActionProvider>,
 6377        window: &mut Window,
 6378        cx: &mut Context<Self>,
 6379    ) {
 6380        if self
 6381            .code_action_providers
 6382            .iter()
 6383            .any(|existing_provider| existing_provider.id() == provider.id())
 6384        {
 6385            return;
 6386        }
 6387
 6388        self.code_action_providers.push(provider);
 6389        self.refresh_code_actions(window, cx);
 6390    }
 6391
 6392    pub fn remove_code_action_provider(
 6393        &mut self,
 6394        id: Arc<str>,
 6395        window: &mut Window,
 6396        cx: &mut Context<Self>,
 6397    ) {
 6398        self.code_action_providers
 6399            .retain(|provider| provider.id() != id);
 6400        self.refresh_code_actions(window, cx);
 6401    }
 6402
 6403    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6404        !self.code_action_providers.is_empty()
 6405            && EditorSettings::get_global(cx).toolbar.code_actions
 6406    }
 6407
 6408    pub fn has_available_code_actions(&self) -> bool {
 6409        self.available_code_actions
 6410            .as_ref()
 6411            .is_some_and(|(_, actions)| !actions.is_empty())
 6412    }
 6413
 6414    fn render_inline_code_actions(
 6415        &self,
 6416        icon_size: ui::IconSize,
 6417        display_row: DisplayRow,
 6418        is_active: bool,
 6419        cx: &mut Context<Self>,
 6420    ) -> AnyElement {
 6421        let show_tooltip = !self.context_menu_visible();
 6422        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6423            .icon_size(icon_size)
 6424            .shape(ui::IconButtonShape::Square)
 6425            .icon_color(ui::Color::Hidden)
 6426            .toggle_state(is_active)
 6427            .when(show_tooltip, |this| {
 6428                this.tooltip({
 6429                    let focus_handle = self.focus_handle.clone();
 6430                    move |window, cx| {
 6431                        Tooltip::for_action_in(
 6432                            "Toggle Code Actions",
 6433                            &ToggleCodeActions {
 6434                                deployed_from: None,
 6435                                quick_launch: false,
 6436                            },
 6437                            &focus_handle,
 6438                            window,
 6439                            cx,
 6440                        )
 6441                    }
 6442                })
 6443            })
 6444            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6445                window.focus(&editor.focus_handle(cx));
 6446                editor.toggle_code_actions(
 6447                    &crate::actions::ToggleCodeActions {
 6448                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6449                            display_row,
 6450                        )),
 6451                        quick_launch: false,
 6452                    },
 6453                    window,
 6454                    cx,
 6455                );
 6456            }))
 6457            .into_any_element()
 6458    }
 6459
 6460    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6461        &self.context_menu
 6462    }
 6463
 6464    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6465        let newest_selection = self.selections.newest_anchor().clone();
 6466        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6467        let buffer = self.buffer.read(cx);
 6468        if newest_selection.head().diff_base_anchor.is_some() {
 6469            return None;
 6470        }
 6471        let (start_buffer, start) =
 6472            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6473        let (end_buffer, end) =
 6474            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6475        if start_buffer != end_buffer {
 6476            return None;
 6477        }
 6478
 6479        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6480            cx.background_executor()
 6481                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6482                .await;
 6483
 6484            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6485                let providers = this.code_action_providers.clone();
 6486                let tasks = this
 6487                    .code_action_providers
 6488                    .iter()
 6489                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6490                    .collect::<Vec<_>>();
 6491                (providers, tasks)
 6492            })?;
 6493
 6494            let mut actions = Vec::new();
 6495            for (provider, provider_actions) in
 6496                providers.into_iter().zip(future::join_all(tasks).await)
 6497            {
 6498                if let Some(provider_actions) = provider_actions.log_err() {
 6499                    actions.extend(provider_actions.into_iter().map(|action| {
 6500                        AvailableCodeAction {
 6501                            excerpt_id: newest_selection.start.excerpt_id,
 6502                            action,
 6503                            provider: provider.clone(),
 6504                        }
 6505                    }));
 6506                }
 6507            }
 6508
 6509            this.update(cx, |this, cx| {
 6510                this.available_code_actions = if actions.is_empty() {
 6511                    None
 6512                } else {
 6513                    Some((
 6514                        Location {
 6515                            buffer: start_buffer,
 6516                            range: start..end,
 6517                        },
 6518                        actions.into(),
 6519                    ))
 6520                };
 6521                cx.notify();
 6522            })
 6523        }));
 6524        None
 6525    }
 6526
 6527    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6528        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6529            self.show_git_blame_inline = false;
 6530
 6531            self.show_git_blame_inline_delay_task =
 6532                Some(cx.spawn_in(window, async move |this, cx| {
 6533                    cx.background_executor().timer(delay).await;
 6534
 6535                    this.update(cx, |this, cx| {
 6536                        this.show_git_blame_inline = true;
 6537                        cx.notify();
 6538                    })
 6539                    .log_err();
 6540                }));
 6541        }
 6542    }
 6543
 6544    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6545        let snapshot = self.snapshot(window, cx);
 6546        let cursor = self.selections.newest::<Point>(cx).head();
 6547        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6548        else {
 6549            return;
 6550        };
 6551
 6552        let Some(blame) = self.blame.as_ref() else {
 6553            return;
 6554        };
 6555
 6556        let row_info = RowInfo {
 6557            buffer_id: Some(buffer.remote_id()),
 6558            buffer_row: Some(point.row),
 6559            ..Default::default()
 6560        };
 6561        let Some(blame_entry) = blame
 6562            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6563            .flatten()
 6564        else {
 6565            return;
 6566        };
 6567
 6568        let anchor = self.selections.newest_anchor().head();
 6569        let position = self.to_pixel_point(anchor, &snapshot, window);
 6570        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6571            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6572        };
 6573    }
 6574
 6575    fn show_blame_popover(
 6576        &mut self,
 6577        blame_entry: &BlameEntry,
 6578        position: gpui::Point<Pixels>,
 6579        ignore_timeout: bool,
 6580        cx: &mut Context<Self>,
 6581    ) {
 6582        if let Some(state) = &mut self.inline_blame_popover {
 6583            state.hide_task.take();
 6584        } else {
 6585            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6586            let blame_entry = blame_entry.clone();
 6587            let show_task = cx.spawn(async move |editor, cx| {
 6588                if !ignore_timeout {
 6589                    cx.background_executor()
 6590                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6591                        .await;
 6592                }
 6593                editor
 6594                    .update(cx, |editor, cx| {
 6595                        editor.inline_blame_popover_show_task.take();
 6596                        let Some(blame) = editor.blame.as_ref() else {
 6597                            return;
 6598                        };
 6599                        let blame = blame.read(cx);
 6600                        let details = blame.details_for_entry(&blame_entry);
 6601                        let markdown = cx.new(|cx| {
 6602                            Markdown::new(
 6603                                details
 6604                                    .as_ref()
 6605                                    .map(|message| message.message.clone())
 6606                                    .unwrap_or_default(),
 6607                                None,
 6608                                None,
 6609                                cx,
 6610                            )
 6611                        });
 6612                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6613                            position,
 6614                            hide_task: None,
 6615                            popover_bounds: None,
 6616                            popover_state: InlineBlamePopoverState {
 6617                                scroll_handle: ScrollHandle::new(),
 6618                                commit_message: details,
 6619                                markdown,
 6620                            },
 6621                            keyboard_grace: ignore_timeout,
 6622                        });
 6623                        cx.notify();
 6624                    })
 6625                    .ok();
 6626            });
 6627            self.inline_blame_popover_show_task = Some(show_task);
 6628        }
 6629    }
 6630
 6631    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6632        self.inline_blame_popover_show_task.take();
 6633        if let Some(state) = &mut self.inline_blame_popover {
 6634            let hide_task = cx.spawn(async move |editor, cx| {
 6635                cx.background_executor()
 6636                    .timer(std::time::Duration::from_millis(100))
 6637                    .await;
 6638                editor
 6639                    .update(cx, |editor, cx| {
 6640                        editor.inline_blame_popover.take();
 6641                        cx.notify();
 6642                    })
 6643                    .ok();
 6644            });
 6645            state.hide_task = Some(hide_task);
 6646        }
 6647    }
 6648
 6649    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6650        if self.pending_rename.is_some() {
 6651            return None;
 6652        }
 6653
 6654        let provider = self.semantics_provider.clone()?;
 6655        let buffer = self.buffer.read(cx);
 6656        let newest_selection = self.selections.newest_anchor().clone();
 6657        let cursor_position = newest_selection.head();
 6658        let (cursor_buffer, cursor_buffer_position) =
 6659            buffer.text_anchor_for_position(cursor_position, cx)?;
 6660        let (tail_buffer, tail_buffer_position) =
 6661            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6662        if cursor_buffer != tail_buffer {
 6663            return None;
 6664        }
 6665
 6666        let snapshot = cursor_buffer.read(cx).snapshot();
 6667        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6668        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6669        if start_word_range != end_word_range {
 6670            self.document_highlights_task.take();
 6671            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6672            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6673            return None;
 6674        }
 6675
 6676        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6677        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6678            cx.background_executor()
 6679                .timer(Duration::from_millis(debounce))
 6680                .await;
 6681
 6682            let highlights = if let Some(highlights) = cx
 6683                .update(|cx| {
 6684                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6685                })
 6686                .ok()
 6687                .flatten()
 6688            {
 6689                highlights.await.log_err()
 6690            } else {
 6691                None
 6692            };
 6693
 6694            if let Some(highlights) = highlights {
 6695                this.update(cx, |this, cx| {
 6696                    if this.pending_rename.is_some() {
 6697                        return;
 6698                    }
 6699
 6700                    let buffer = this.buffer.read(cx);
 6701                    if buffer
 6702                        .text_anchor_for_position(cursor_position, cx)
 6703                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6704                    {
 6705                        return;
 6706                    }
 6707
 6708                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6709                    let mut write_ranges = Vec::new();
 6710                    let mut read_ranges = Vec::new();
 6711                    for highlight in highlights {
 6712                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6713                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6714                        {
 6715                            let start = highlight
 6716                                .range
 6717                                .start
 6718                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6719                            let end = highlight
 6720                                .range
 6721                                .end
 6722                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6723                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6724                                continue;
 6725                            }
 6726
 6727                            let range = Anchor {
 6728                                buffer_id: Some(buffer_id),
 6729                                excerpt_id,
 6730                                text_anchor: start,
 6731                                diff_base_anchor: None,
 6732                            }..Anchor {
 6733                                buffer_id: Some(buffer_id),
 6734                                excerpt_id,
 6735                                text_anchor: end,
 6736                                diff_base_anchor: None,
 6737                            };
 6738                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6739                                write_ranges.push(range);
 6740                            } else {
 6741                                read_ranges.push(range);
 6742                            }
 6743                        }
 6744                    }
 6745
 6746                    this.highlight_background::<DocumentHighlightRead>(
 6747                        &read_ranges,
 6748                        |theme| theme.colors().editor_document_highlight_read_background,
 6749                        cx,
 6750                    );
 6751                    this.highlight_background::<DocumentHighlightWrite>(
 6752                        &write_ranges,
 6753                        |theme| theme.colors().editor_document_highlight_write_background,
 6754                        cx,
 6755                    );
 6756                    cx.notify();
 6757                })
 6758                .log_err();
 6759            }
 6760        }));
 6761        None
 6762    }
 6763
 6764    fn prepare_highlight_query_from_selection(
 6765        &mut self,
 6766        cx: &mut Context<Editor>,
 6767    ) -> Option<(String, Range<Anchor>)> {
 6768        if matches!(self.mode, EditorMode::SingleLine) {
 6769            return None;
 6770        }
 6771        if !EditorSettings::get_global(cx).selection_highlight {
 6772            return None;
 6773        }
 6774        if self.selections.count() != 1 || self.selections.line_mode {
 6775            return None;
 6776        }
 6777        let selection = self.selections.newest::<Point>(cx);
 6778        if selection.is_empty() || selection.start.row != selection.end.row {
 6779            return None;
 6780        }
 6781        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6782        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6783        let query = multi_buffer_snapshot
 6784            .text_for_range(selection_anchor_range.clone())
 6785            .collect::<String>();
 6786        if query.trim().is_empty() {
 6787            return None;
 6788        }
 6789        Some((query, selection_anchor_range))
 6790    }
 6791
 6792    fn update_selection_occurrence_highlights(
 6793        &mut self,
 6794        query_text: String,
 6795        query_range: Range<Anchor>,
 6796        multi_buffer_range_to_query: Range<Point>,
 6797        use_debounce: bool,
 6798        window: &mut Window,
 6799        cx: &mut Context<Editor>,
 6800    ) -> Task<()> {
 6801        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6802        cx.spawn_in(window, async move |editor, cx| {
 6803            if use_debounce {
 6804                cx.background_executor()
 6805                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6806                    .await;
 6807            }
 6808            let match_task = cx.background_spawn(async move {
 6809                let buffer_ranges = multi_buffer_snapshot
 6810                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6811                    .into_iter()
 6812                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6813                let mut match_ranges = Vec::new();
 6814                let Ok(regex) = project::search::SearchQuery::text(
 6815                    query_text.clone(),
 6816                    false,
 6817                    false,
 6818                    false,
 6819                    Default::default(),
 6820                    Default::default(),
 6821                    false,
 6822                    None,
 6823                ) else {
 6824                    return Vec::default();
 6825                };
 6826                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6827                    match_ranges.extend(
 6828                        regex
 6829                            .search(buffer_snapshot, Some(search_range.clone()))
 6830                            .await
 6831                            .into_iter()
 6832                            .filter_map(|match_range| {
 6833                                let match_start = buffer_snapshot
 6834                                    .anchor_after(search_range.start + match_range.start);
 6835                                let match_end = buffer_snapshot
 6836                                    .anchor_before(search_range.start + match_range.end);
 6837                                let match_anchor_range = Anchor::range_in_buffer(
 6838                                    excerpt_id,
 6839                                    buffer_snapshot.remote_id(),
 6840                                    match_start..match_end,
 6841                                );
 6842                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6843                            }),
 6844                    );
 6845                }
 6846                match_ranges
 6847            });
 6848            let match_ranges = match_task.await;
 6849            editor
 6850                .update_in(cx, |editor, _, cx| {
 6851                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6852                    if !match_ranges.is_empty() {
 6853                        editor.highlight_background::<SelectedTextHighlight>(
 6854                            &match_ranges,
 6855                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6856                            cx,
 6857                        )
 6858                    }
 6859                })
 6860                .log_err();
 6861        })
 6862    }
 6863
 6864    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6865        struct NewlineFold;
 6866        let type_id = std::any::TypeId::of::<NewlineFold>();
 6867        if !self.mode.is_single_line() {
 6868            return;
 6869        }
 6870        let snapshot = self.snapshot(window, cx);
 6871        if snapshot.buffer_snapshot.max_point().row == 0 {
 6872            return;
 6873        }
 6874        let task = cx.background_spawn(async move {
 6875            let new_newlines = snapshot
 6876                .buffer_chars_at(0)
 6877                .filter_map(|(c, i)| {
 6878                    if c == '\n' {
 6879                        Some(
 6880                            snapshot.buffer_snapshot.anchor_after(i)
 6881                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6882                        )
 6883                    } else {
 6884                        None
 6885                    }
 6886                })
 6887                .collect::<Vec<_>>();
 6888            let existing_newlines = snapshot
 6889                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6890                .filter_map(|fold| {
 6891                    if fold.placeholder.type_tag == Some(type_id) {
 6892                        Some(fold.range.start..fold.range.end)
 6893                    } else {
 6894                        None
 6895                    }
 6896                })
 6897                .collect::<Vec<_>>();
 6898
 6899            (new_newlines, existing_newlines)
 6900        });
 6901        self.folding_newlines = cx.spawn(async move |this, cx| {
 6902            let (new_newlines, existing_newlines) = task.await;
 6903            if new_newlines == existing_newlines {
 6904                return;
 6905            }
 6906            let placeholder = FoldPlaceholder {
 6907                render: Arc::new(move |_, _, cx| {
 6908                    div()
 6909                        .bg(cx.theme().status().hint_background)
 6910                        .border_b_1()
 6911                        .size_full()
 6912                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6913                        .border_color(cx.theme().status().hint)
 6914                        .child("\\n")
 6915                        .into_any()
 6916                }),
 6917                constrain_width: false,
 6918                merge_adjacent: false,
 6919                type_tag: Some(type_id),
 6920            };
 6921            let creases = new_newlines
 6922                .into_iter()
 6923                .map(|range| Crease::simple(range, placeholder.clone()))
 6924                .collect();
 6925            this.update(cx, |this, cx| {
 6926                this.display_map.update(cx, |display_map, cx| {
 6927                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6928                    display_map.fold(creases, cx);
 6929                });
 6930            })
 6931            .ok();
 6932        });
 6933    }
 6934
 6935    fn refresh_selected_text_highlights(
 6936        &mut self,
 6937        on_buffer_edit: bool,
 6938        window: &mut Window,
 6939        cx: &mut Context<Editor>,
 6940    ) {
 6941        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6942        else {
 6943            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6944            self.quick_selection_highlight_task.take();
 6945            self.debounced_selection_highlight_task.take();
 6946            return;
 6947        };
 6948        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6949        if on_buffer_edit
 6950            || self
 6951                .quick_selection_highlight_task
 6952                .as_ref()
 6953                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6954        {
 6955            let multi_buffer_visible_start = self
 6956                .scroll_manager
 6957                .anchor()
 6958                .anchor
 6959                .to_point(&multi_buffer_snapshot);
 6960            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6961                multi_buffer_visible_start
 6962                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6963                Bias::Left,
 6964            );
 6965            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6966            self.quick_selection_highlight_task = Some((
 6967                query_range.clone(),
 6968                self.update_selection_occurrence_highlights(
 6969                    query_text.clone(),
 6970                    query_range.clone(),
 6971                    multi_buffer_visible_range,
 6972                    false,
 6973                    window,
 6974                    cx,
 6975                ),
 6976            ));
 6977        }
 6978        if on_buffer_edit
 6979            || self
 6980                .debounced_selection_highlight_task
 6981                .as_ref()
 6982                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6983        {
 6984            let multi_buffer_start = multi_buffer_snapshot
 6985                .anchor_before(0)
 6986                .to_point(&multi_buffer_snapshot);
 6987            let multi_buffer_end = multi_buffer_snapshot
 6988                .anchor_after(multi_buffer_snapshot.len())
 6989                .to_point(&multi_buffer_snapshot);
 6990            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6991            self.debounced_selection_highlight_task = Some((
 6992                query_range.clone(),
 6993                self.update_selection_occurrence_highlights(
 6994                    query_text,
 6995                    query_range,
 6996                    multi_buffer_full_range,
 6997                    true,
 6998                    window,
 6999                    cx,
 7000                ),
 7001            ));
 7002        }
 7003    }
 7004
 7005    pub fn refresh_edit_prediction(
 7006        &mut self,
 7007        debounce: bool,
 7008        user_requested: bool,
 7009        window: &mut Window,
 7010        cx: &mut Context<Self>,
 7011    ) -> Option<()> {
 7012        if DisableAiSettings::get_global(cx).disable_ai {
 7013            return None;
 7014        }
 7015
 7016        let provider = self.edit_prediction_provider()?;
 7017        let cursor = self.selections.newest_anchor().head();
 7018        let (buffer, cursor_buffer_position) =
 7019            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7020
 7021        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7022            self.discard_edit_prediction(false, cx);
 7023            return None;
 7024        }
 7025
 7026        if !user_requested
 7027            && (!self.should_show_edit_predictions()
 7028                || !self.is_focused(window)
 7029                || buffer.read(cx).is_empty())
 7030        {
 7031            self.discard_edit_prediction(false, cx);
 7032            return None;
 7033        }
 7034
 7035        self.update_visible_edit_prediction(window, cx);
 7036        provider.refresh(
 7037            self.project.clone(),
 7038            buffer,
 7039            cursor_buffer_position,
 7040            debounce,
 7041            cx,
 7042        );
 7043        Some(())
 7044    }
 7045
 7046    fn show_edit_predictions_in_menu(&self) -> bool {
 7047        match self.edit_prediction_settings {
 7048            EditPredictionSettings::Disabled => false,
 7049            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7050        }
 7051    }
 7052
 7053    pub fn edit_predictions_enabled(&self) -> bool {
 7054        match self.edit_prediction_settings {
 7055            EditPredictionSettings::Disabled => false,
 7056            EditPredictionSettings::Enabled { .. } => true,
 7057        }
 7058    }
 7059
 7060    fn edit_prediction_requires_modifier(&self) -> bool {
 7061        match self.edit_prediction_settings {
 7062            EditPredictionSettings::Disabled => false,
 7063            EditPredictionSettings::Enabled {
 7064                preview_requires_modifier,
 7065                ..
 7066            } => preview_requires_modifier,
 7067        }
 7068    }
 7069
 7070    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7071        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7072            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7073            self.discard_edit_prediction(false, cx);
 7074        } else {
 7075            let selection = self.selections.newest_anchor();
 7076            let cursor = selection.head();
 7077
 7078            if let Some((buffer, cursor_buffer_position)) =
 7079                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7080            {
 7081                self.edit_prediction_settings =
 7082                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7083            }
 7084        }
 7085    }
 7086
 7087    fn edit_prediction_settings_at_position(
 7088        &self,
 7089        buffer: &Entity<Buffer>,
 7090        buffer_position: language::Anchor,
 7091        cx: &App,
 7092    ) -> EditPredictionSettings {
 7093        if !self.mode.is_full()
 7094            || !self.show_edit_predictions_override.unwrap_or(true)
 7095            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7096        {
 7097            return EditPredictionSettings::Disabled;
 7098        }
 7099
 7100        let buffer = buffer.read(cx);
 7101
 7102        let file = buffer.file();
 7103
 7104        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7105            return EditPredictionSettings::Disabled;
 7106        };
 7107
 7108        let by_provider = matches!(
 7109            self.menu_edit_predictions_policy,
 7110            MenuEditPredictionsPolicy::ByProvider
 7111        );
 7112
 7113        let show_in_menu = by_provider
 7114            && self
 7115                .edit_prediction_provider
 7116                .as_ref()
 7117                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7118
 7119        let preview_requires_modifier =
 7120            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7121
 7122        EditPredictionSettings::Enabled {
 7123            show_in_menu,
 7124            preview_requires_modifier,
 7125        }
 7126    }
 7127
 7128    fn should_show_edit_predictions(&self) -> bool {
 7129        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7130    }
 7131
 7132    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7133        matches!(
 7134            self.edit_prediction_preview,
 7135            EditPredictionPreview::Active { .. }
 7136        )
 7137    }
 7138
 7139    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7140        let cursor = self.selections.newest_anchor().head();
 7141        if let Some((buffer, cursor_position)) =
 7142            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7143        {
 7144            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7145        } else {
 7146            false
 7147        }
 7148    }
 7149
 7150    pub fn supports_minimap(&self, cx: &App) -> bool {
 7151        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7152    }
 7153
 7154    fn edit_predictions_enabled_in_buffer(
 7155        &self,
 7156        buffer: &Entity<Buffer>,
 7157        buffer_position: language::Anchor,
 7158        cx: &App,
 7159    ) -> bool {
 7160        maybe!({
 7161            if self.read_only(cx) {
 7162                return Some(false);
 7163            }
 7164            let provider = self.edit_prediction_provider()?;
 7165            if !provider.is_enabled(buffer, buffer_position, cx) {
 7166                return Some(false);
 7167            }
 7168            let buffer = buffer.read(cx);
 7169            let Some(file) = buffer.file() else {
 7170                return Some(true);
 7171            };
 7172            let settings = all_language_settings(Some(file), cx);
 7173            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7174        })
 7175        .unwrap_or(false)
 7176    }
 7177
 7178    fn cycle_edit_prediction(
 7179        &mut self,
 7180        direction: Direction,
 7181        window: &mut Window,
 7182        cx: &mut Context<Self>,
 7183    ) -> Option<()> {
 7184        let provider = self.edit_prediction_provider()?;
 7185        let cursor = self.selections.newest_anchor().head();
 7186        let (buffer, cursor_buffer_position) =
 7187            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7188        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7189            return None;
 7190        }
 7191
 7192        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7193        self.update_visible_edit_prediction(window, cx);
 7194
 7195        Some(())
 7196    }
 7197
 7198    pub fn show_edit_prediction(
 7199        &mut self,
 7200        _: &ShowEditPrediction,
 7201        window: &mut Window,
 7202        cx: &mut Context<Self>,
 7203    ) {
 7204        if !self.has_active_edit_prediction() {
 7205            self.refresh_edit_prediction(false, true, window, cx);
 7206            return;
 7207        }
 7208
 7209        self.update_visible_edit_prediction(window, cx);
 7210    }
 7211
 7212    pub fn display_cursor_names(
 7213        &mut self,
 7214        _: &DisplayCursorNames,
 7215        window: &mut Window,
 7216        cx: &mut Context<Self>,
 7217    ) {
 7218        self.show_cursor_names(window, cx);
 7219    }
 7220
 7221    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7222        self.show_cursor_names = true;
 7223        cx.notify();
 7224        cx.spawn_in(window, async move |this, cx| {
 7225            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7226            this.update(cx, |this, cx| {
 7227                this.show_cursor_names = false;
 7228                cx.notify()
 7229            })
 7230            .ok()
 7231        })
 7232        .detach();
 7233    }
 7234
 7235    pub fn next_edit_prediction(
 7236        &mut self,
 7237        _: &NextEditPrediction,
 7238        window: &mut Window,
 7239        cx: &mut Context<Self>,
 7240    ) {
 7241        if self.has_active_edit_prediction() {
 7242            self.cycle_edit_prediction(Direction::Next, window, cx);
 7243        } else {
 7244            let is_copilot_disabled = self
 7245                .refresh_edit_prediction(false, true, window, cx)
 7246                .is_none();
 7247            if is_copilot_disabled {
 7248                cx.propagate();
 7249            }
 7250        }
 7251    }
 7252
 7253    pub fn previous_edit_prediction(
 7254        &mut self,
 7255        _: &PreviousEditPrediction,
 7256        window: &mut Window,
 7257        cx: &mut Context<Self>,
 7258    ) {
 7259        if self.has_active_edit_prediction() {
 7260            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7261        } else {
 7262            let is_copilot_disabled = self
 7263                .refresh_edit_prediction(false, true, window, cx)
 7264                .is_none();
 7265            if is_copilot_disabled {
 7266                cx.propagate();
 7267            }
 7268        }
 7269    }
 7270
 7271    pub fn accept_edit_prediction(
 7272        &mut self,
 7273        _: &AcceptEditPrediction,
 7274        window: &mut Window,
 7275        cx: &mut Context<Self>,
 7276    ) {
 7277        if self.show_edit_predictions_in_menu() {
 7278            self.hide_context_menu(window, cx);
 7279        }
 7280
 7281        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7282            return;
 7283        };
 7284
 7285        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7286
 7287        match &active_edit_prediction.completion {
 7288            EditPrediction::Move { target, .. } => {
 7289                let target = *target;
 7290
 7291                if let Some(position_map) = &self.last_position_map {
 7292                    if position_map
 7293                        .visible_row_range
 7294                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7295                        || !self.edit_prediction_requires_modifier()
 7296                    {
 7297                        self.unfold_ranges(&[target..target], true, false, cx);
 7298                        // Note that this is also done in vim's handler of the Tab action.
 7299                        self.change_selections(
 7300                            SelectionEffects::scroll(Autoscroll::newest()),
 7301                            window,
 7302                            cx,
 7303                            |selections| {
 7304                                selections.select_anchor_ranges([target..target]);
 7305                            },
 7306                        );
 7307                        self.clear_row_highlights::<EditPredictionPreview>();
 7308
 7309                        self.edit_prediction_preview
 7310                            .set_previous_scroll_position(None);
 7311                    } else {
 7312                        self.edit_prediction_preview
 7313                            .set_previous_scroll_position(Some(
 7314                                position_map.snapshot.scroll_anchor,
 7315                            ));
 7316
 7317                        self.highlight_rows::<EditPredictionPreview>(
 7318                            target..target,
 7319                            cx.theme().colors().editor_highlighted_line_background,
 7320                            RowHighlightOptions {
 7321                                autoscroll: true,
 7322                                ..Default::default()
 7323                            },
 7324                            cx,
 7325                        );
 7326                        self.request_autoscroll(Autoscroll::fit(), cx);
 7327                    }
 7328                }
 7329            }
 7330            EditPrediction::Edit { edits, .. } => {
 7331                if let Some(provider) = self.edit_prediction_provider() {
 7332                    provider.accept(cx);
 7333                }
 7334
 7335                // Store the transaction ID and selections before applying the edit
 7336                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7337
 7338                let snapshot = self.buffer.read(cx).snapshot(cx);
 7339                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7340
 7341                self.buffer.update(cx, |buffer, cx| {
 7342                    buffer.edit(edits.iter().cloned(), None, cx)
 7343                });
 7344
 7345                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7346                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7347                });
 7348
 7349                let selections = self.selections.disjoint_anchors();
 7350                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7351                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7352                    if has_new_transaction {
 7353                        self.selection_history
 7354                            .insert_transaction(transaction_id_now, selections);
 7355                    }
 7356                }
 7357
 7358                self.update_visible_edit_prediction(window, cx);
 7359                if self.active_edit_prediction.is_none() {
 7360                    self.refresh_edit_prediction(true, true, window, cx);
 7361                }
 7362
 7363                cx.notify();
 7364            }
 7365        }
 7366
 7367        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7368    }
 7369
 7370    pub fn accept_partial_edit_prediction(
 7371        &mut self,
 7372        _: &AcceptPartialEditPrediction,
 7373        window: &mut Window,
 7374        cx: &mut Context<Self>,
 7375    ) {
 7376        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7377            return;
 7378        };
 7379        if self.selections.count() != 1 {
 7380            return;
 7381        }
 7382
 7383        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7384
 7385        match &active_edit_prediction.completion {
 7386            EditPrediction::Move { target, .. } => {
 7387                let target = *target;
 7388                self.change_selections(
 7389                    SelectionEffects::scroll(Autoscroll::newest()),
 7390                    window,
 7391                    cx,
 7392                    |selections| {
 7393                        selections.select_anchor_ranges([target..target]);
 7394                    },
 7395                );
 7396            }
 7397            EditPrediction::Edit { edits, .. } => {
 7398                // Find an insertion that starts at the cursor position.
 7399                let snapshot = self.buffer.read(cx).snapshot(cx);
 7400                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7401                let insertion = edits.iter().find_map(|(range, text)| {
 7402                    let range = range.to_offset(&snapshot);
 7403                    if range.is_empty() && range.start == cursor_offset {
 7404                        Some(text)
 7405                    } else {
 7406                        None
 7407                    }
 7408                });
 7409
 7410                if let Some(text) = insertion {
 7411                    let mut partial_completion = text
 7412                        .chars()
 7413                        .by_ref()
 7414                        .take_while(|c| c.is_alphabetic())
 7415                        .collect::<String>();
 7416                    if partial_completion.is_empty() {
 7417                        partial_completion = text
 7418                            .chars()
 7419                            .by_ref()
 7420                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7421                            .collect::<String>();
 7422                    }
 7423
 7424                    cx.emit(EditorEvent::InputHandled {
 7425                        utf16_range_to_replace: None,
 7426                        text: partial_completion.clone().into(),
 7427                    });
 7428
 7429                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7430
 7431                    self.refresh_edit_prediction(true, true, window, cx);
 7432                    cx.notify();
 7433                } else {
 7434                    self.accept_edit_prediction(&Default::default(), window, cx);
 7435                }
 7436            }
 7437        }
 7438    }
 7439
 7440    fn discard_edit_prediction(
 7441        &mut self,
 7442        should_report_edit_prediction_event: bool,
 7443        cx: &mut Context<Self>,
 7444    ) -> bool {
 7445        if should_report_edit_prediction_event {
 7446            let completion_id = self
 7447                .active_edit_prediction
 7448                .as_ref()
 7449                .and_then(|active_completion| active_completion.completion_id.clone());
 7450
 7451            self.report_edit_prediction_event(completion_id, false, cx);
 7452        }
 7453
 7454        if let Some(provider) = self.edit_prediction_provider() {
 7455            provider.discard(cx);
 7456        }
 7457
 7458        self.take_active_edit_prediction(cx)
 7459    }
 7460
 7461    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7462        let Some(provider) = self.edit_prediction_provider() else {
 7463            return;
 7464        };
 7465
 7466        let Some((_, buffer, _)) = self
 7467            .buffer
 7468            .read(cx)
 7469            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7470        else {
 7471            return;
 7472        };
 7473
 7474        let extension = buffer
 7475            .read(cx)
 7476            .file()
 7477            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7478
 7479        let event_type = match accepted {
 7480            true => "Edit Prediction Accepted",
 7481            false => "Edit Prediction Discarded",
 7482        };
 7483        telemetry::event!(
 7484            event_type,
 7485            provider = provider.name(),
 7486            prediction_id = id,
 7487            suggestion_accepted = accepted,
 7488            file_extension = extension,
 7489        );
 7490    }
 7491
 7492    pub fn has_active_edit_prediction(&self) -> bool {
 7493        self.active_edit_prediction.is_some()
 7494    }
 7495
 7496    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7497        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7498            return false;
 7499        };
 7500
 7501        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7502        self.clear_highlights::<EditPredictionHighlight>(cx);
 7503        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7504        true
 7505    }
 7506
 7507    /// Returns true when we're displaying the edit prediction popover below the cursor
 7508    /// like we are not previewing and the LSP autocomplete menu is visible
 7509    /// or we are in `when_holding_modifier` mode.
 7510    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7511        if self.edit_prediction_preview_is_active()
 7512            || !self.show_edit_predictions_in_menu()
 7513            || !self.edit_predictions_enabled()
 7514        {
 7515            return false;
 7516        }
 7517
 7518        if self.has_visible_completions_menu() {
 7519            return true;
 7520        }
 7521
 7522        has_completion && self.edit_prediction_requires_modifier()
 7523    }
 7524
 7525    fn handle_modifiers_changed(
 7526        &mut self,
 7527        modifiers: Modifiers,
 7528        position_map: &PositionMap,
 7529        window: &mut Window,
 7530        cx: &mut Context<Self>,
 7531    ) {
 7532        if self.show_edit_predictions_in_menu() {
 7533            self.update_edit_prediction_preview(&modifiers, window, cx);
 7534        }
 7535
 7536        self.update_selection_mode(&modifiers, position_map, window, cx);
 7537
 7538        let mouse_position = window.mouse_position();
 7539        if !position_map.text_hitbox.is_hovered(window) {
 7540            return;
 7541        }
 7542
 7543        self.update_hovered_link(
 7544            position_map.point_for_position(mouse_position),
 7545            &position_map.snapshot,
 7546            modifiers,
 7547            window,
 7548            cx,
 7549        )
 7550    }
 7551
 7552    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7553        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7554        if invert {
 7555            match multi_cursor_setting {
 7556                MultiCursorModifier::Alt => modifiers.alt,
 7557                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7558            }
 7559        } else {
 7560            match multi_cursor_setting {
 7561                MultiCursorModifier::Alt => modifiers.secondary(),
 7562                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7563            }
 7564        }
 7565    }
 7566
 7567    fn columnar_selection_mode(
 7568        modifiers: &Modifiers,
 7569        cx: &mut Context<Self>,
 7570    ) -> Option<ColumnarMode> {
 7571        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7572            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7573                Some(ColumnarMode::FromMouse)
 7574            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7575                Some(ColumnarMode::FromSelection)
 7576            } else {
 7577                None
 7578            }
 7579        } else {
 7580            None
 7581        }
 7582    }
 7583
 7584    fn update_selection_mode(
 7585        &mut self,
 7586        modifiers: &Modifiers,
 7587        position_map: &PositionMap,
 7588        window: &mut Window,
 7589        cx: &mut Context<Self>,
 7590    ) {
 7591        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7592            return;
 7593        };
 7594        if self.selections.pending.is_none() {
 7595            return;
 7596        }
 7597
 7598        let mouse_position = window.mouse_position();
 7599        let point_for_position = position_map.point_for_position(mouse_position);
 7600        let position = point_for_position.previous_valid;
 7601
 7602        self.select(
 7603            SelectPhase::BeginColumnar {
 7604                position,
 7605                reset: false,
 7606                mode,
 7607                goal_column: point_for_position.exact_unclipped.column(),
 7608            },
 7609            window,
 7610            cx,
 7611        );
 7612    }
 7613
 7614    fn update_edit_prediction_preview(
 7615        &mut self,
 7616        modifiers: &Modifiers,
 7617        window: &mut Window,
 7618        cx: &mut Context<Self>,
 7619    ) {
 7620        let mut modifiers_held = false;
 7621        if let Some(accept_keystroke) = self
 7622            .accept_edit_prediction_keybind(false, window, cx)
 7623            .keystroke()
 7624        {
 7625            modifiers_held = modifiers_held
 7626                || (&accept_keystroke.modifiers == modifiers
 7627                    && accept_keystroke.modifiers.modified());
 7628        };
 7629        if let Some(accept_partial_keystroke) = self
 7630            .accept_edit_prediction_keybind(true, window, cx)
 7631            .keystroke()
 7632        {
 7633            modifiers_held = modifiers_held
 7634                || (&accept_partial_keystroke.modifiers == modifiers
 7635                    && accept_partial_keystroke.modifiers.modified());
 7636        }
 7637
 7638        if modifiers_held {
 7639            if matches!(
 7640                self.edit_prediction_preview,
 7641                EditPredictionPreview::Inactive { .. }
 7642            ) {
 7643                self.edit_prediction_preview = EditPredictionPreview::Active {
 7644                    previous_scroll_position: None,
 7645                    since: Instant::now(),
 7646                };
 7647
 7648                self.update_visible_edit_prediction(window, cx);
 7649                cx.notify();
 7650            }
 7651        } else if let EditPredictionPreview::Active {
 7652            previous_scroll_position,
 7653            since,
 7654        } = self.edit_prediction_preview
 7655        {
 7656            if let (Some(previous_scroll_position), Some(position_map)) =
 7657                (previous_scroll_position, self.last_position_map.as_ref())
 7658            {
 7659                self.set_scroll_position(
 7660                    previous_scroll_position
 7661                        .scroll_position(&position_map.snapshot.display_snapshot),
 7662                    window,
 7663                    cx,
 7664                );
 7665            }
 7666
 7667            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7668                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7669            };
 7670            self.clear_row_highlights::<EditPredictionPreview>();
 7671            self.update_visible_edit_prediction(window, cx);
 7672            cx.notify();
 7673        }
 7674    }
 7675
 7676    fn update_visible_edit_prediction(
 7677        &mut self,
 7678        _window: &mut Window,
 7679        cx: &mut Context<Self>,
 7680    ) -> Option<()> {
 7681        if DisableAiSettings::get_global(cx).disable_ai {
 7682            return None;
 7683        }
 7684
 7685        let selection = self.selections.newest_anchor();
 7686        let cursor = selection.head();
 7687        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7688        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7689        let excerpt_id = cursor.excerpt_id;
 7690
 7691        let show_in_menu = self.show_edit_predictions_in_menu();
 7692        let completions_menu_has_precedence = !show_in_menu
 7693            && (self.context_menu.borrow().is_some()
 7694                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7695
 7696        if completions_menu_has_precedence
 7697            || !offset_selection.is_empty()
 7698            || self
 7699                .active_edit_prediction
 7700                .as_ref()
 7701                .is_some_and(|completion| {
 7702                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7703                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7704                    !invalidation_range.contains(&offset_selection.head())
 7705                })
 7706        {
 7707            self.discard_edit_prediction(false, cx);
 7708            return None;
 7709        }
 7710
 7711        self.take_active_edit_prediction(cx);
 7712        let Some(provider) = self.edit_prediction_provider() else {
 7713            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7714            return None;
 7715        };
 7716
 7717        let (buffer, cursor_buffer_position) =
 7718            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7719
 7720        self.edit_prediction_settings =
 7721            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7722
 7723        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7724            self.discard_edit_prediction(false, cx);
 7725            return None;
 7726        };
 7727
 7728        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7729
 7730        if self.edit_prediction_indent_conflict {
 7731            let cursor_point = cursor.to_point(&multibuffer);
 7732
 7733            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7734
 7735            if let Some((_, indent)) = indents.iter().next()
 7736                && indent.len == cursor_point.column
 7737            {
 7738                self.edit_prediction_indent_conflict = false;
 7739            }
 7740        }
 7741
 7742        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7743        let edits = edit_prediction
 7744            .edits
 7745            .into_iter()
 7746            .flat_map(|(range, new_text)| {
 7747                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7748                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7749                Some((start..end, new_text))
 7750            })
 7751            .collect::<Vec<_>>();
 7752        if edits.is_empty() {
 7753            return None;
 7754        }
 7755
 7756        let first_edit_start = edits.first().unwrap().0.start;
 7757        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7758        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7759
 7760        let last_edit_end = edits.last().unwrap().0.end;
 7761        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7762        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7763
 7764        let cursor_row = cursor.to_point(&multibuffer).row;
 7765
 7766        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7767
 7768        let mut inlay_ids = Vec::new();
 7769        let invalidation_row_range;
 7770        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7771            Some(cursor_row..edit_end_row)
 7772        } else if cursor_row > edit_end_row {
 7773            Some(edit_start_row..cursor_row)
 7774        } else {
 7775            None
 7776        };
 7777        let supports_jump = self
 7778            .edit_prediction_provider
 7779            .as_ref()
 7780            .map(|provider| provider.provider.supports_jump_to_edit())
 7781            .unwrap_or(true);
 7782
 7783        let is_move = supports_jump
 7784            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7785        let completion = if is_move {
 7786            invalidation_row_range =
 7787                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7788            let target = first_edit_start;
 7789            EditPrediction::Move { target, snapshot }
 7790        } else {
 7791            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7792                && !self.edit_predictions_hidden_for_vim_mode;
 7793
 7794            if show_completions_in_buffer {
 7795                if edits
 7796                    .iter()
 7797                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7798                {
 7799                    let mut inlays = Vec::new();
 7800                    for (range, new_text) in &edits {
 7801                        let inlay = Inlay::edit_prediction(
 7802                            post_inc(&mut self.next_inlay_id),
 7803                            range.start,
 7804                            new_text.as_str(),
 7805                        );
 7806                        inlay_ids.push(inlay.id);
 7807                        inlays.push(inlay);
 7808                    }
 7809
 7810                    self.splice_inlays(&[], inlays, cx);
 7811                } else {
 7812                    let background_color = cx.theme().status().deleted_background;
 7813                    self.highlight_text::<EditPredictionHighlight>(
 7814                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7815                        HighlightStyle {
 7816                            background_color: Some(background_color),
 7817                            ..Default::default()
 7818                        },
 7819                        cx,
 7820                    );
 7821                }
 7822            }
 7823
 7824            invalidation_row_range = edit_start_row..edit_end_row;
 7825
 7826            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7827                if provider.show_tab_accept_marker() {
 7828                    EditDisplayMode::TabAccept
 7829                } else {
 7830                    EditDisplayMode::Inline
 7831                }
 7832            } else {
 7833                EditDisplayMode::DiffPopover
 7834            };
 7835
 7836            EditPrediction::Edit {
 7837                edits,
 7838                edit_preview: edit_prediction.edit_preview,
 7839                display_mode,
 7840                snapshot,
 7841            }
 7842        };
 7843
 7844        let invalidation_range = multibuffer
 7845            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7846            ..multibuffer.anchor_after(Point::new(
 7847                invalidation_row_range.end,
 7848                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7849            ));
 7850
 7851        self.stale_edit_prediction_in_menu = None;
 7852        self.active_edit_prediction = Some(EditPredictionState {
 7853            inlay_ids,
 7854            completion,
 7855            completion_id: edit_prediction.id,
 7856            invalidation_range,
 7857        });
 7858
 7859        cx.notify();
 7860
 7861        Some(())
 7862    }
 7863
 7864    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7865        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7866    }
 7867
 7868    fn clear_tasks(&mut self) {
 7869        self.tasks.clear()
 7870    }
 7871
 7872    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7873        if self.tasks.insert(key, value).is_some() {
 7874            // This case should hopefully be rare, but just in case...
 7875            log::error!(
 7876                "multiple different run targets found on a single line, only the last target will be rendered"
 7877            )
 7878        }
 7879    }
 7880
 7881    /// Get all display points of breakpoints that will be rendered within editor
 7882    ///
 7883    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7884    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7885    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7886    fn active_breakpoints(
 7887        &self,
 7888        range: Range<DisplayRow>,
 7889        window: &mut Window,
 7890        cx: &mut Context<Self>,
 7891    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7892        let mut breakpoint_display_points = HashMap::default();
 7893
 7894        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7895            return breakpoint_display_points;
 7896        };
 7897
 7898        let snapshot = self.snapshot(window, cx);
 7899
 7900        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7901        let Some(project) = self.project() else {
 7902            return breakpoint_display_points;
 7903        };
 7904
 7905        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7906            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7907
 7908        for (buffer_snapshot, range, excerpt_id) in
 7909            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7910        {
 7911            let Some(buffer) = project
 7912                .read(cx)
 7913                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7914            else {
 7915                continue;
 7916            };
 7917            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7918                &buffer,
 7919                Some(
 7920                    buffer_snapshot.anchor_before(range.start)
 7921                        ..buffer_snapshot.anchor_after(range.end),
 7922                ),
 7923                buffer_snapshot,
 7924                cx,
 7925            );
 7926            for (breakpoint, state) in breakpoints {
 7927                let multi_buffer_anchor =
 7928                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7929                let position = multi_buffer_anchor
 7930                    .to_point(multi_buffer_snapshot)
 7931                    .to_display_point(&snapshot);
 7932
 7933                breakpoint_display_points.insert(
 7934                    position.row(),
 7935                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7936                );
 7937            }
 7938        }
 7939
 7940        breakpoint_display_points
 7941    }
 7942
 7943    fn breakpoint_context_menu(
 7944        &self,
 7945        anchor: Anchor,
 7946        window: &mut Window,
 7947        cx: &mut Context<Self>,
 7948    ) -> Entity<ui::ContextMenu> {
 7949        let weak_editor = cx.weak_entity();
 7950        let focus_handle = self.focus_handle(cx);
 7951
 7952        let row = self
 7953            .buffer
 7954            .read(cx)
 7955            .snapshot(cx)
 7956            .summary_for_anchor::<Point>(&anchor)
 7957            .row;
 7958
 7959        let breakpoint = self
 7960            .breakpoint_at_row(row, window, cx)
 7961            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7962
 7963        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7964            "Edit Log Breakpoint"
 7965        } else {
 7966            "Set Log Breakpoint"
 7967        };
 7968
 7969        let condition_breakpoint_msg = if breakpoint
 7970            .as_ref()
 7971            .is_some_and(|bp| bp.1.condition.is_some())
 7972        {
 7973            "Edit Condition Breakpoint"
 7974        } else {
 7975            "Set Condition Breakpoint"
 7976        };
 7977
 7978        let hit_condition_breakpoint_msg = if breakpoint
 7979            .as_ref()
 7980            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7981        {
 7982            "Edit Hit Condition Breakpoint"
 7983        } else {
 7984            "Set Hit Condition Breakpoint"
 7985        };
 7986
 7987        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7988            "Unset Breakpoint"
 7989        } else {
 7990            "Set Breakpoint"
 7991        };
 7992
 7993        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7994
 7995        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7996            BreakpointState::Enabled => Some("Disable"),
 7997            BreakpointState::Disabled => Some("Enable"),
 7998        });
 7999
 8000        let (anchor, breakpoint) =
 8001            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8002
 8003        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8004            menu.on_blur_subscription(Subscription::new(|| {}))
 8005                .context(focus_handle)
 8006                .when(run_to_cursor, |this| {
 8007                    let weak_editor = weak_editor.clone();
 8008                    this.entry("Run to cursor", None, move |window, cx| {
 8009                        weak_editor
 8010                            .update(cx, |editor, cx| {
 8011                                editor.change_selections(
 8012                                    SelectionEffects::no_scroll(),
 8013                                    window,
 8014                                    cx,
 8015                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8016                                );
 8017                            })
 8018                            .ok();
 8019
 8020                        window.dispatch_action(Box::new(RunToCursor), cx);
 8021                    })
 8022                    .separator()
 8023                })
 8024                .when_some(toggle_state_msg, |this, msg| {
 8025                    this.entry(msg, None, {
 8026                        let weak_editor = weak_editor.clone();
 8027                        let breakpoint = breakpoint.clone();
 8028                        move |_window, cx| {
 8029                            weak_editor
 8030                                .update(cx, |this, cx| {
 8031                                    this.edit_breakpoint_at_anchor(
 8032                                        anchor,
 8033                                        breakpoint.as_ref().clone(),
 8034                                        BreakpointEditAction::InvertState,
 8035                                        cx,
 8036                                    );
 8037                                })
 8038                                .log_err();
 8039                        }
 8040                    })
 8041                })
 8042                .entry(set_breakpoint_msg, None, {
 8043                    let weak_editor = weak_editor.clone();
 8044                    let breakpoint = breakpoint.clone();
 8045                    move |_window, cx| {
 8046                        weak_editor
 8047                            .update(cx, |this, cx| {
 8048                                this.edit_breakpoint_at_anchor(
 8049                                    anchor,
 8050                                    breakpoint.as_ref().clone(),
 8051                                    BreakpointEditAction::Toggle,
 8052                                    cx,
 8053                                );
 8054                            })
 8055                            .log_err();
 8056                    }
 8057                })
 8058                .entry(log_breakpoint_msg, None, {
 8059                    let breakpoint = breakpoint.clone();
 8060                    let weak_editor = weak_editor.clone();
 8061                    move |window, cx| {
 8062                        weak_editor
 8063                            .update(cx, |this, cx| {
 8064                                this.add_edit_breakpoint_block(
 8065                                    anchor,
 8066                                    breakpoint.as_ref(),
 8067                                    BreakpointPromptEditAction::Log,
 8068                                    window,
 8069                                    cx,
 8070                                );
 8071                            })
 8072                            .log_err();
 8073                    }
 8074                })
 8075                .entry(condition_breakpoint_msg, None, {
 8076                    let breakpoint = breakpoint.clone();
 8077                    let weak_editor = weak_editor.clone();
 8078                    move |window, cx| {
 8079                        weak_editor
 8080                            .update(cx, |this, cx| {
 8081                                this.add_edit_breakpoint_block(
 8082                                    anchor,
 8083                                    breakpoint.as_ref(),
 8084                                    BreakpointPromptEditAction::Condition,
 8085                                    window,
 8086                                    cx,
 8087                                );
 8088                            })
 8089                            .log_err();
 8090                    }
 8091                })
 8092                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8093                    weak_editor
 8094                        .update(cx, |this, cx| {
 8095                            this.add_edit_breakpoint_block(
 8096                                anchor,
 8097                                breakpoint.as_ref(),
 8098                                BreakpointPromptEditAction::HitCondition,
 8099                                window,
 8100                                cx,
 8101                            );
 8102                        })
 8103                        .log_err();
 8104                })
 8105        })
 8106    }
 8107
 8108    fn render_breakpoint(
 8109        &self,
 8110        position: Anchor,
 8111        row: DisplayRow,
 8112        breakpoint: &Breakpoint,
 8113        state: Option<BreakpointSessionState>,
 8114        cx: &mut Context<Self>,
 8115    ) -> IconButton {
 8116        let is_rejected = state.is_some_and(|s| !s.verified);
 8117        // Is it a breakpoint that shows up when hovering over gutter?
 8118        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8119            (false, false),
 8120            |PhantomBreakpointIndicator {
 8121                 is_active,
 8122                 display_row,
 8123                 collides_with_existing_breakpoint,
 8124             }| {
 8125                (
 8126                    is_active && display_row == row,
 8127                    collides_with_existing_breakpoint,
 8128                )
 8129            },
 8130        );
 8131
 8132        let (color, icon) = {
 8133            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8134                (false, false) => ui::IconName::DebugBreakpoint,
 8135                (true, false) => ui::IconName::DebugLogBreakpoint,
 8136                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8137                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8138            };
 8139
 8140            let color = if is_phantom {
 8141                Color::Hint
 8142            } else if is_rejected {
 8143                Color::Disabled
 8144            } else {
 8145                Color::Debugger
 8146            };
 8147
 8148            (color, icon)
 8149        };
 8150
 8151        let breakpoint = Arc::from(breakpoint.clone());
 8152
 8153        let alt_as_text = gpui::Keystroke {
 8154            modifiers: Modifiers::secondary_key(),
 8155            ..Default::default()
 8156        };
 8157        let primary_action_text = if breakpoint.is_disabled() {
 8158            "Enable breakpoint"
 8159        } else if is_phantom && !collides_with_existing {
 8160            "Set breakpoint"
 8161        } else {
 8162            "Unset breakpoint"
 8163        };
 8164        let focus_handle = self.focus_handle.clone();
 8165
 8166        let meta = if is_rejected {
 8167            SharedString::from("No executable code is associated with this line.")
 8168        } else if collides_with_existing && !breakpoint.is_disabled() {
 8169            SharedString::from(format!(
 8170                "{alt_as_text}-click to disable,\nright-click for more options."
 8171            ))
 8172        } else {
 8173            SharedString::from("Right-click for more options.")
 8174        };
 8175        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8176            .icon_size(IconSize::XSmall)
 8177            .size(ui::ButtonSize::None)
 8178            .when(is_rejected, |this| {
 8179                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8180            })
 8181            .icon_color(color)
 8182            .style(ButtonStyle::Transparent)
 8183            .on_click(cx.listener({
 8184                move |editor, event: &ClickEvent, window, cx| {
 8185                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8186                        BreakpointEditAction::InvertState
 8187                    } else {
 8188                        BreakpointEditAction::Toggle
 8189                    };
 8190
 8191                    window.focus(&editor.focus_handle(cx));
 8192                    editor.edit_breakpoint_at_anchor(
 8193                        position,
 8194                        breakpoint.as_ref().clone(),
 8195                        edit_action,
 8196                        cx,
 8197                    );
 8198                }
 8199            }))
 8200            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8201                editor.set_breakpoint_context_menu(
 8202                    row,
 8203                    Some(position),
 8204                    event.position(),
 8205                    window,
 8206                    cx,
 8207                );
 8208            }))
 8209            .tooltip(move |window, cx| {
 8210                Tooltip::with_meta_in(
 8211                    primary_action_text,
 8212                    Some(&ToggleBreakpoint),
 8213                    meta.clone(),
 8214                    &focus_handle,
 8215                    window,
 8216                    cx,
 8217                )
 8218            })
 8219    }
 8220
 8221    fn build_tasks_context(
 8222        project: &Entity<Project>,
 8223        buffer: &Entity<Buffer>,
 8224        buffer_row: u32,
 8225        tasks: &Arc<RunnableTasks>,
 8226        cx: &mut Context<Self>,
 8227    ) -> Task<Option<task::TaskContext>> {
 8228        let position = Point::new(buffer_row, tasks.column);
 8229        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8230        let location = Location {
 8231            buffer: buffer.clone(),
 8232            range: range_start..range_start,
 8233        };
 8234        // Fill in the environmental variables from the tree-sitter captures
 8235        let mut captured_task_variables = TaskVariables::default();
 8236        for (capture_name, value) in tasks.extra_variables.clone() {
 8237            captured_task_variables.insert(
 8238                task::VariableName::Custom(capture_name.into()),
 8239                value.clone(),
 8240            );
 8241        }
 8242        project.update(cx, |project, cx| {
 8243            project.task_store().update(cx, |task_store, cx| {
 8244                task_store.task_context_for_location(captured_task_variables, location, cx)
 8245            })
 8246        })
 8247    }
 8248
 8249    pub fn spawn_nearest_task(
 8250        &mut self,
 8251        action: &SpawnNearestTask,
 8252        window: &mut Window,
 8253        cx: &mut Context<Self>,
 8254    ) {
 8255        let Some((workspace, _)) = self.workspace.clone() else {
 8256            return;
 8257        };
 8258        let Some(project) = self.project.clone() else {
 8259            return;
 8260        };
 8261
 8262        // Try to find a closest, enclosing node using tree-sitter that has a task
 8263        let Some((buffer, buffer_row, tasks)) = self
 8264            .find_enclosing_node_task(cx)
 8265            // Or find the task that's closest in row-distance.
 8266            .or_else(|| self.find_closest_task(cx))
 8267        else {
 8268            return;
 8269        };
 8270
 8271        let reveal_strategy = action.reveal;
 8272        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8273        cx.spawn_in(window, async move |_, cx| {
 8274            let context = task_context.await?;
 8275            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8276
 8277            let resolved = &mut resolved_task.resolved;
 8278            resolved.reveal = reveal_strategy;
 8279
 8280            workspace
 8281                .update_in(cx, |workspace, window, cx| {
 8282                    workspace.schedule_resolved_task(
 8283                        task_source_kind,
 8284                        resolved_task,
 8285                        false,
 8286                        window,
 8287                        cx,
 8288                    );
 8289                })
 8290                .ok()
 8291        })
 8292        .detach();
 8293    }
 8294
 8295    fn find_closest_task(
 8296        &mut self,
 8297        cx: &mut Context<Self>,
 8298    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8299        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8300
 8301        let ((buffer_id, row), tasks) = self
 8302            .tasks
 8303            .iter()
 8304            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8305
 8306        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8307        let tasks = Arc::new(tasks.to_owned());
 8308        Some((buffer, *row, tasks))
 8309    }
 8310
 8311    fn find_enclosing_node_task(
 8312        &mut self,
 8313        cx: &mut Context<Self>,
 8314    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8315        let snapshot = self.buffer.read(cx).snapshot(cx);
 8316        let offset = self.selections.newest::<usize>(cx).head();
 8317        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8318        let buffer_id = excerpt.buffer().remote_id();
 8319
 8320        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8321        let mut cursor = layer.node().walk();
 8322
 8323        while cursor.goto_first_child_for_byte(offset).is_some() {
 8324            if cursor.node().end_byte() == offset {
 8325                cursor.goto_next_sibling();
 8326            }
 8327        }
 8328
 8329        // Ascend to the smallest ancestor that contains the range and has a task.
 8330        loop {
 8331            let node = cursor.node();
 8332            let node_range = node.byte_range();
 8333            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8334
 8335            // Check if this node contains our offset
 8336            if node_range.start <= offset && node_range.end >= offset {
 8337                // If it contains offset, check for task
 8338                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8339                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8340                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8341                }
 8342            }
 8343
 8344            if !cursor.goto_parent() {
 8345                break;
 8346            }
 8347        }
 8348        None
 8349    }
 8350
 8351    fn render_run_indicator(
 8352        &self,
 8353        _style: &EditorStyle,
 8354        is_active: bool,
 8355        row: DisplayRow,
 8356        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8357        cx: &mut Context<Self>,
 8358    ) -> IconButton {
 8359        let color = Color::Muted;
 8360        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8361
 8362        IconButton::new(
 8363            ("run_indicator", row.0 as usize),
 8364            ui::IconName::PlayOutlined,
 8365        )
 8366        .shape(ui::IconButtonShape::Square)
 8367        .icon_size(IconSize::XSmall)
 8368        .icon_color(color)
 8369        .toggle_state(is_active)
 8370        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8371            let quick_launch = match e {
 8372                ClickEvent::Keyboard(_) => true,
 8373                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8374            };
 8375
 8376            window.focus(&editor.focus_handle(cx));
 8377            editor.toggle_code_actions(
 8378                &ToggleCodeActions {
 8379                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8380                    quick_launch,
 8381                },
 8382                window,
 8383                cx,
 8384            );
 8385        }))
 8386        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8387            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8388        }))
 8389    }
 8390
 8391    pub fn context_menu_visible(&self) -> bool {
 8392        !self.edit_prediction_preview_is_active()
 8393            && self
 8394                .context_menu
 8395                .borrow()
 8396                .as_ref()
 8397                .is_some_and(|menu| menu.visible())
 8398    }
 8399
 8400    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8401        self.context_menu
 8402            .borrow()
 8403            .as_ref()
 8404            .map(|menu| menu.origin())
 8405    }
 8406
 8407    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8408        self.context_menu_options = Some(options);
 8409    }
 8410
 8411    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8412    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8413
 8414    fn render_edit_prediction_popover(
 8415        &mut self,
 8416        text_bounds: &Bounds<Pixels>,
 8417        content_origin: gpui::Point<Pixels>,
 8418        right_margin: Pixels,
 8419        editor_snapshot: &EditorSnapshot,
 8420        visible_row_range: Range<DisplayRow>,
 8421        scroll_top: f32,
 8422        scroll_bottom: f32,
 8423        line_layouts: &[LineWithInvisibles],
 8424        line_height: Pixels,
 8425        scroll_pixel_position: gpui::Point<Pixels>,
 8426        newest_selection_head: Option<DisplayPoint>,
 8427        editor_width: Pixels,
 8428        style: &EditorStyle,
 8429        window: &mut Window,
 8430        cx: &mut App,
 8431    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8432        if self.mode().is_minimap() {
 8433            return None;
 8434        }
 8435        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8436
 8437        if self.edit_prediction_visible_in_cursor_popover(true) {
 8438            return None;
 8439        }
 8440
 8441        match &active_edit_prediction.completion {
 8442            EditPrediction::Move { target, .. } => {
 8443                let target_display_point = target.to_display_point(editor_snapshot);
 8444
 8445                if self.edit_prediction_requires_modifier() {
 8446                    if !self.edit_prediction_preview_is_active() {
 8447                        return None;
 8448                    }
 8449
 8450                    self.render_edit_prediction_modifier_jump_popover(
 8451                        text_bounds,
 8452                        content_origin,
 8453                        visible_row_range,
 8454                        line_layouts,
 8455                        line_height,
 8456                        scroll_pixel_position,
 8457                        newest_selection_head,
 8458                        target_display_point,
 8459                        window,
 8460                        cx,
 8461                    )
 8462                } else {
 8463                    self.render_edit_prediction_eager_jump_popover(
 8464                        text_bounds,
 8465                        content_origin,
 8466                        editor_snapshot,
 8467                        visible_row_range,
 8468                        scroll_top,
 8469                        scroll_bottom,
 8470                        line_height,
 8471                        scroll_pixel_position,
 8472                        target_display_point,
 8473                        editor_width,
 8474                        window,
 8475                        cx,
 8476                    )
 8477                }
 8478            }
 8479            EditPrediction::Edit {
 8480                display_mode: EditDisplayMode::Inline,
 8481                ..
 8482            } => None,
 8483            EditPrediction::Edit {
 8484                display_mode: EditDisplayMode::TabAccept,
 8485                edits,
 8486                ..
 8487            } => {
 8488                let range = &edits.first()?.0;
 8489                let target_display_point = range.end.to_display_point(editor_snapshot);
 8490
 8491                self.render_edit_prediction_end_of_line_popover(
 8492                    "Accept",
 8493                    editor_snapshot,
 8494                    visible_row_range,
 8495                    target_display_point,
 8496                    line_height,
 8497                    scroll_pixel_position,
 8498                    content_origin,
 8499                    editor_width,
 8500                    window,
 8501                    cx,
 8502                )
 8503            }
 8504            EditPrediction::Edit {
 8505                edits,
 8506                edit_preview,
 8507                display_mode: EditDisplayMode::DiffPopover,
 8508                snapshot,
 8509            } => self.render_edit_prediction_diff_popover(
 8510                text_bounds,
 8511                content_origin,
 8512                right_margin,
 8513                editor_snapshot,
 8514                visible_row_range,
 8515                line_layouts,
 8516                line_height,
 8517                scroll_pixel_position,
 8518                newest_selection_head,
 8519                editor_width,
 8520                style,
 8521                edits,
 8522                edit_preview,
 8523                snapshot,
 8524                window,
 8525                cx,
 8526            ),
 8527        }
 8528    }
 8529
 8530    fn render_edit_prediction_modifier_jump_popover(
 8531        &mut self,
 8532        text_bounds: &Bounds<Pixels>,
 8533        content_origin: gpui::Point<Pixels>,
 8534        visible_row_range: Range<DisplayRow>,
 8535        line_layouts: &[LineWithInvisibles],
 8536        line_height: Pixels,
 8537        scroll_pixel_position: gpui::Point<Pixels>,
 8538        newest_selection_head: Option<DisplayPoint>,
 8539        target_display_point: DisplayPoint,
 8540        window: &mut Window,
 8541        cx: &mut App,
 8542    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8543        let scrolled_content_origin =
 8544            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8545
 8546        const SCROLL_PADDING_Y: Pixels = px(12.);
 8547
 8548        if target_display_point.row() < visible_row_range.start {
 8549            return self.render_edit_prediction_scroll_popover(
 8550                |_| SCROLL_PADDING_Y,
 8551                IconName::ArrowUp,
 8552                visible_row_range,
 8553                line_layouts,
 8554                newest_selection_head,
 8555                scrolled_content_origin,
 8556                window,
 8557                cx,
 8558            );
 8559        } else if target_display_point.row() >= visible_row_range.end {
 8560            return self.render_edit_prediction_scroll_popover(
 8561                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8562                IconName::ArrowDown,
 8563                visible_row_range,
 8564                line_layouts,
 8565                newest_selection_head,
 8566                scrolled_content_origin,
 8567                window,
 8568                cx,
 8569            );
 8570        }
 8571
 8572        const POLE_WIDTH: Pixels = px(2.);
 8573
 8574        let line_layout =
 8575            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8576        let target_column = target_display_point.column() as usize;
 8577
 8578        let target_x = line_layout.x_for_index(target_column);
 8579        let target_y =
 8580            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8581
 8582        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8583
 8584        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8585        border_color.l += 0.001;
 8586
 8587        let mut element = v_flex()
 8588            .items_end()
 8589            .when(flag_on_right, |el| el.items_start())
 8590            .child(if flag_on_right {
 8591                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8592                    .rounded_bl(px(0.))
 8593                    .rounded_tl(px(0.))
 8594                    .border_l_2()
 8595                    .border_color(border_color)
 8596            } else {
 8597                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8598                    .rounded_br(px(0.))
 8599                    .rounded_tr(px(0.))
 8600                    .border_r_2()
 8601                    .border_color(border_color)
 8602            })
 8603            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8604            .into_any();
 8605
 8606        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8607
 8608        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8609            - point(
 8610                if flag_on_right {
 8611                    POLE_WIDTH
 8612                } else {
 8613                    size.width - POLE_WIDTH
 8614                },
 8615                size.height - line_height,
 8616            );
 8617
 8618        origin.x = origin.x.max(content_origin.x);
 8619
 8620        element.prepaint_at(origin, window, cx);
 8621
 8622        Some((element, origin))
 8623    }
 8624
 8625    fn render_edit_prediction_scroll_popover(
 8626        &mut self,
 8627        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8628        scroll_icon: IconName,
 8629        visible_row_range: Range<DisplayRow>,
 8630        line_layouts: &[LineWithInvisibles],
 8631        newest_selection_head: Option<DisplayPoint>,
 8632        scrolled_content_origin: gpui::Point<Pixels>,
 8633        window: &mut Window,
 8634        cx: &mut App,
 8635    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8636        let mut element = self
 8637            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8638            .into_any();
 8639
 8640        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8641
 8642        let cursor = newest_selection_head?;
 8643        let cursor_row_layout =
 8644            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8645        let cursor_column = cursor.column() as usize;
 8646
 8647        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8648
 8649        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8650
 8651        element.prepaint_at(origin, window, cx);
 8652        Some((element, origin))
 8653    }
 8654
 8655    fn render_edit_prediction_eager_jump_popover(
 8656        &mut self,
 8657        text_bounds: &Bounds<Pixels>,
 8658        content_origin: gpui::Point<Pixels>,
 8659        editor_snapshot: &EditorSnapshot,
 8660        visible_row_range: Range<DisplayRow>,
 8661        scroll_top: f32,
 8662        scroll_bottom: f32,
 8663        line_height: Pixels,
 8664        scroll_pixel_position: gpui::Point<Pixels>,
 8665        target_display_point: DisplayPoint,
 8666        editor_width: Pixels,
 8667        window: &mut Window,
 8668        cx: &mut App,
 8669    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8670        if target_display_point.row().as_f32() < scroll_top {
 8671            let mut element = self
 8672                .render_edit_prediction_line_popover(
 8673                    "Jump to Edit",
 8674                    Some(IconName::ArrowUp),
 8675                    window,
 8676                    cx,
 8677                )?
 8678                .into_any();
 8679
 8680            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8681            let offset = point(
 8682                (text_bounds.size.width - size.width) / 2.,
 8683                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8684            );
 8685
 8686            let origin = text_bounds.origin + offset;
 8687            element.prepaint_at(origin, window, cx);
 8688            Some((element, origin))
 8689        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8690            let mut element = self
 8691                .render_edit_prediction_line_popover(
 8692                    "Jump to Edit",
 8693                    Some(IconName::ArrowDown),
 8694                    window,
 8695                    cx,
 8696                )?
 8697                .into_any();
 8698
 8699            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8700            let offset = point(
 8701                (text_bounds.size.width - size.width) / 2.,
 8702                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8703            );
 8704
 8705            let origin = text_bounds.origin + offset;
 8706            element.prepaint_at(origin, window, cx);
 8707            Some((element, origin))
 8708        } else {
 8709            self.render_edit_prediction_end_of_line_popover(
 8710                "Jump to Edit",
 8711                editor_snapshot,
 8712                visible_row_range,
 8713                target_display_point,
 8714                line_height,
 8715                scroll_pixel_position,
 8716                content_origin,
 8717                editor_width,
 8718                window,
 8719                cx,
 8720            )
 8721        }
 8722    }
 8723
 8724    fn render_edit_prediction_end_of_line_popover(
 8725        self: &mut Editor,
 8726        label: &'static str,
 8727        editor_snapshot: &EditorSnapshot,
 8728        visible_row_range: Range<DisplayRow>,
 8729        target_display_point: DisplayPoint,
 8730        line_height: Pixels,
 8731        scroll_pixel_position: gpui::Point<Pixels>,
 8732        content_origin: gpui::Point<Pixels>,
 8733        editor_width: Pixels,
 8734        window: &mut Window,
 8735        cx: &mut App,
 8736    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8737        let target_line_end = DisplayPoint::new(
 8738            target_display_point.row(),
 8739            editor_snapshot.line_len(target_display_point.row()),
 8740        );
 8741
 8742        let mut element = self
 8743            .render_edit_prediction_line_popover(label, None, window, cx)?
 8744            .into_any();
 8745
 8746        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8747
 8748        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8749
 8750        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8751        let mut origin = start_point
 8752            + line_origin
 8753            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8754        origin.x = origin.x.max(content_origin.x);
 8755
 8756        let max_x = content_origin.x + editor_width - size.width;
 8757
 8758        if origin.x > max_x {
 8759            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8760
 8761            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8762                origin.y += offset;
 8763                IconName::ArrowUp
 8764            } else {
 8765                origin.y -= offset;
 8766                IconName::ArrowDown
 8767            };
 8768
 8769            element = self
 8770                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8771                .into_any();
 8772
 8773            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8774
 8775            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8776        }
 8777
 8778        element.prepaint_at(origin, window, cx);
 8779        Some((element, origin))
 8780    }
 8781
 8782    fn render_edit_prediction_diff_popover(
 8783        self: &Editor,
 8784        text_bounds: &Bounds<Pixels>,
 8785        content_origin: gpui::Point<Pixels>,
 8786        right_margin: Pixels,
 8787        editor_snapshot: &EditorSnapshot,
 8788        visible_row_range: Range<DisplayRow>,
 8789        line_layouts: &[LineWithInvisibles],
 8790        line_height: Pixels,
 8791        scroll_pixel_position: gpui::Point<Pixels>,
 8792        newest_selection_head: Option<DisplayPoint>,
 8793        editor_width: Pixels,
 8794        style: &EditorStyle,
 8795        edits: &Vec<(Range<Anchor>, String)>,
 8796        edit_preview: &Option<language::EditPreview>,
 8797        snapshot: &language::BufferSnapshot,
 8798        window: &mut Window,
 8799        cx: &mut App,
 8800    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8801        let edit_start = edits
 8802            .first()
 8803            .unwrap()
 8804            .0
 8805            .start
 8806            .to_display_point(editor_snapshot);
 8807        let edit_end = edits
 8808            .last()
 8809            .unwrap()
 8810            .0
 8811            .end
 8812            .to_display_point(editor_snapshot);
 8813
 8814        let is_visible = visible_row_range.contains(&edit_start.row())
 8815            || visible_row_range.contains(&edit_end.row());
 8816        if !is_visible {
 8817            return None;
 8818        }
 8819
 8820        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8821            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8822        } else {
 8823            // Fallback for providers without edit_preview
 8824            crate::edit_prediction_fallback_text(edits, cx)
 8825        };
 8826
 8827        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8828        let line_count = highlighted_edits.text.lines().count();
 8829
 8830        const BORDER_WIDTH: Pixels = px(1.);
 8831
 8832        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8833        let has_keybind = keybind.is_some();
 8834
 8835        let mut element = h_flex()
 8836            .items_start()
 8837            .child(
 8838                h_flex()
 8839                    .bg(cx.theme().colors().editor_background)
 8840                    .border(BORDER_WIDTH)
 8841                    .shadow_xs()
 8842                    .border_color(cx.theme().colors().border)
 8843                    .rounded_l_lg()
 8844                    .when(line_count > 1, |el| el.rounded_br_lg())
 8845                    .pr_1()
 8846                    .child(styled_text),
 8847            )
 8848            .child(
 8849                h_flex()
 8850                    .h(line_height + BORDER_WIDTH * 2.)
 8851                    .px_1p5()
 8852                    .gap_1()
 8853                    // Workaround: For some reason, there's a gap if we don't do this
 8854                    .ml(-BORDER_WIDTH)
 8855                    .shadow(vec![gpui::BoxShadow {
 8856                        color: gpui::black().opacity(0.05),
 8857                        offset: point(px(1.), px(1.)),
 8858                        blur_radius: px(2.),
 8859                        spread_radius: px(0.),
 8860                    }])
 8861                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8862                    .border(BORDER_WIDTH)
 8863                    .border_color(cx.theme().colors().border)
 8864                    .rounded_r_lg()
 8865                    .id("edit_prediction_diff_popover_keybind")
 8866                    .when(!has_keybind, |el| {
 8867                        let status_colors = cx.theme().status();
 8868
 8869                        el.bg(status_colors.error_background)
 8870                            .border_color(status_colors.error.opacity(0.6))
 8871                            .child(Icon::new(IconName::Info).color(Color::Error))
 8872                            .cursor_default()
 8873                            .hoverable_tooltip(move |_window, cx| {
 8874                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8875                            })
 8876                    })
 8877                    .children(keybind),
 8878            )
 8879            .into_any();
 8880
 8881        let longest_row =
 8882            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8883        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8884            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8885        } else {
 8886            layout_line(
 8887                longest_row,
 8888                editor_snapshot,
 8889                style,
 8890                editor_width,
 8891                |_| false,
 8892                window,
 8893                cx,
 8894            )
 8895            .width
 8896        };
 8897
 8898        let viewport_bounds =
 8899            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8900                right: -right_margin,
 8901                ..Default::default()
 8902            });
 8903
 8904        let x_after_longest =
 8905            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8906                - scroll_pixel_position.x;
 8907
 8908        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8909
 8910        // Fully visible if it can be displayed within the window (allow overlapping other
 8911        // panes). However, this is only allowed if the popover starts within text_bounds.
 8912        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8913            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8914
 8915        let mut origin = if can_position_to_the_right {
 8916            point(
 8917                x_after_longest,
 8918                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8919                    - scroll_pixel_position.y,
 8920            )
 8921        } else {
 8922            let cursor_row = newest_selection_head.map(|head| head.row());
 8923            let above_edit = edit_start
 8924                .row()
 8925                .0
 8926                .checked_sub(line_count as u32)
 8927                .map(DisplayRow);
 8928            let below_edit = Some(edit_end.row() + 1);
 8929            let above_cursor =
 8930                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8931            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8932
 8933            // Place the edit popover adjacent to the edit if there is a location
 8934            // available that is onscreen and does not obscure the cursor. Otherwise,
 8935            // place it adjacent to the cursor.
 8936            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8937                .into_iter()
 8938                .flatten()
 8939                .find(|&start_row| {
 8940                    let end_row = start_row + line_count as u32;
 8941                    visible_row_range.contains(&start_row)
 8942                        && visible_row_range.contains(&end_row)
 8943                        && cursor_row
 8944                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 8945                })?;
 8946
 8947            content_origin
 8948                + point(
 8949                    -scroll_pixel_position.x,
 8950                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8951                )
 8952        };
 8953
 8954        origin.x -= BORDER_WIDTH;
 8955
 8956        window.defer_draw(element, origin, 1);
 8957
 8958        // Do not return an element, since it will already be drawn due to defer_draw.
 8959        None
 8960    }
 8961
 8962    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8963        px(30.)
 8964    }
 8965
 8966    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8967        if self.read_only(cx) {
 8968            cx.theme().players().read_only()
 8969        } else {
 8970            self.style.as_ref().unwrap().local_player
 8971        }
 8972    }
 8973
 8974    fn render_edit_prediction_accept_keybind(
 8975        &self,
 8976        window: &mut Window,
 8977        cx: &App,
 8978    ) -> Option<AnyElement> {
 8979        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8980        let accept_keystroke = accept_binding.keystroke()?;
 8981
 8982        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8983
 8984        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8985            Color::Accent
 8986        } else {
 8987            Color::Muted
 8988        };
 8989
 8990        h_flex()
 8991            .px_0p5()
 8992            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8993            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8994            .text_size(TextSize::XSmall.rems(cx))
 8995            .child(h_flex().children(ui::render_modifiers(
 8996                &accept_keystroke.modifiers,
 8997                PlatformStyle::platform(),
 8998                Some(modifiers_color),
 8999                Some(IconSize::XSmall.rems().into()),
 9000                true,
 9001            )))
 9002            .when(is_platform_style_mac, |parent| {
 9003                parent.child(accept_keystroke.key.clone())
 9004            })
 9005            .when(!is_platform_style_mac, |parent| {
 9006                parent.child(
 9007                    Key::new(
 9008                        util::capitalize(&accept_keystroke.key),
 9009                        Some(Color::Default),
 9010                    )
 9011                    .size(Some(IconSize::XSmall.rems().into())),
 9012                )
 9013            })
 9014            .into_any()
 9015            .into()
 9016    }
 9017
 9018    fn render_edit_prediction_line_popover(
 9019        &self,
 9020        label: impl Into<SharedString>,
 9021        icon: Option<IconName>,
 9022        window: &mut Window,
 9023        cx: &App,
 9024    ) -> Option<Stateful<Div>> {
 9025        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9026
 9027        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9028        let has_keybind = keybind.is_some();
 9029
 9030        let result = h_flex()
 9031            .id("ep-line-popover")
 9032            .py_0p5()
 9033            .pl_1()
 9034            .pr(padding_right)
 9035            .gap_1()
 9036            .rounded_md()
 9037            .border_1()
 9038            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9039            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9040            .shadow_xs()
 9041            .when(!has_keybind, |el| {
 9042                let status_colors = cx.theme().status();
 9043
 9044                el.bg(status_colors.error_background)
 9045                    .border_color(status_colors.error.opacity(0.6))
 9046                    .pl_2()
 9047                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9048                    .cursor_default()
 9049                    .hoverable_tooltip(move |_window, cx| {
 9050                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9051                    })
 9052            })
 9053            .children(keybind)
 9054            .child(
 9055                Label::new(label)
 9056                    .size(LabelSize::Small)
 9057                    .when(!has_keybind, |el| {
 9058                        el.color(cx.theme().status().error.into()).strikethrough()
 9059                    }),
 9060            )
 9061            .when(!has_keybind, |el| {
 9062                el.child(
 9063                    h_flex().ml_1().child(
 9064                        Icon::new(IconName::Info)
 9065                            .size(IconSize::Small)
 9066                            .color(cx.theme().status().error.into()),
 9067                    ),
 9068                )
 9069            })
 9070            .when_some(icon, |element, icon| {
 9071                element.child(
 9072                    div()
 9073                        .mt(px(1.5))
 9074                        .child(Icon::new(icon).size(IconSize::Small)),
 9075                )
 9076            });
 9077
 9078        Some(result)
 9079    }
 9080
 9081    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9082        let accent_color = cx.theme().colors().text_accent;
 9083        let editor_bg_color = cx.theme().colors().editor_background;
 9084        editor_bg_color.blend(accent_color.opacity(0.1))
 9085    }
 9086
 9087    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9088        let accent_color = cx.theme().colors().text_accent;
 9089        let editor_bg_color = cx.theme().colors().editor_background;
 9090        editor_bg_color.blend(accent_color.opacity(0.6))
 9091    }
 9092    fn get_prediction_provider_icon_name(
 9093        provider: &Option<RegisteredEditPredictionProvider>,
 9094    ) -> IconName {
 9095        match provider {
 9096            Some(provider) => match provider.provider.name() {
 9097                "copilot" => IconName::Copilot,
 9098                "supermaven" => IconName::Supermaven,
 9099                _ => IconName::ZedPredict,
 9100            },
 9101            None => IconName::ZedPredict,
 9102        }
 9103    }
 9104
 9105    fn render_edit_prediction_cursor_popover(
 9106        &self,
 9107        min_width: Pixels,
 9108        max_width: Pixels,
 9109        cursor_point: Point,
 9110        style: &EditorStyle,
 9111        accept_keystroke: Option<&gpui::Keystroke>,
 9112        _window: &Window,
 9113        cx: &mut Context<Editor>,
 9114    ) -> Option<AnyElement> {
 9115        let provider = self.edit_prediction_provider.as_ref()?;
 9116        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9117
 9118        if provider.provider.needs_terms_acceptance(cx) {
 9119            return Some(
 9120                h_flex()
 9121                    .min_w(min_width)
 9122                    .flex_1()
 9123                    .px_2()
 9124                    .py_1()
 9125                    .gap_3()
 9126                    .elevation_2(cx)
 9127                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9128                    .id("accept-terms")
 9129                    .cursor_pointer()
 9130                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9131                    .on_click(cx.listener(|this, _event, window, cx| {
 9132                        cx.stop_propagation();
 9133                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9134                        window.dispatch_action(
 9135                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9136                            cx,
 9137                        );
 9138                    }))
 9139                    .child(
 9140                        h_flex()
 9141                            .flex_1()
 9142                            .gap_2()
 9143                            .child(Icon::new(provider_icon))
 9144                            .child(Label::new("Accept Terms of Service"))
 9145                            .child(div().w_full())
 9146                            .child(
 9147                                Icon::new(IconName::ArrowUpRight)
 9148                                    .color(Color::Muted)
 9149                                    .size(IconSize::Small),
 9150                            )
 9151                            .into_any_element(),
 9152                    )
 9153                    .into_any(),
 9154            );
 9155        }
 9156
 9157        let is_refreshing = provider.provider.is_refreshing(cx);
 9158
 9159        fn pending_completion_container(icon: IconName) -> Div {
 9160            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9161        }
 9162
 9163        let completion = match &self.active_edit_prediction {
 9164            Some(prediction) => {
 9165                if !self.has_visible_completions_menu() {
 9166                    const RADIUS: Pixels = px(6.);
 9167                    const BORDER_WIDTH: Pixels = px(1.);
 9168
 9169                    return Some(
 9170                        h_flex()
 9171                            .elevation_2(cx)
 9172                            .border(BORDER_WIDTH)
 9173                            .border_color(cx.theme().colors().border)
 9174                            .when(accept_keystroke.is_none(), |el| {
 9175                                el.border_color(cx.theme().status().error)
 9176                            })
 9177                            .rounded(RADIUS)
 9178                            .rounded_tl(px(0.))
 9179                            .overflow_hidden()
 9180                            .child(div().px_1p5().child(match &prediction.completion {
 9181                                EditPrediction::Move { target, snapshot } => {
 9182                                    use text::ToPoint as _;
 9183                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9184                                    {
 9185                                        Icon::new(IconName::ZedPredictDown)
 9186                                    } else {
 9187                                        Icon::new(IconName::ZedPredictUp)
 9188                                    }
 9189                                }
 9190                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9191                            }))
 9192                            .child(
 9193                                h_flex()
 9194                                    .gap_1()
 9195                                    .py_1()
 9196                                    .px_2()
 9197                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9198                                    .border_l_1()
 9199                                    .border_color(cx.theme().colors().border)
 9200                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9201                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9202                                        el.child(
 9203                                            Label::new("Hold")
 9204                                                .size(LabelSize::Small)
 9205                                                .when(accept_keystroke.is_none(), |el| {
 9206                                                    el.strikethrough()
 9207                                                })
 9208                                                .line_height_style(LineHeightStyle::UiLabel),
 9209                                        )
 9210                                    })
 9211                                    .id("edit_prediction_cursor_popover_keybind")
 9212                                    .when(accept_keystroke.is_none(), |el| {
 9213                                        let status_colors = cx.theme().status();
 9214
 9215                                        el.bg(status_colors.error_background)
 9216                                            .border_color(status_colors.error.opacity(0.6))
 9217                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9218                                            .cursor_default()
 9219                                            .hoverable_tooltip(move |_window, cx| {
 9220                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9221                                                    .into()
 9222                                            })
 9223                                    })
 9224                                    .when_some(
 9225                                        accept_keystroke.as_ref(),
 9226                                        |el, accept_keystroke| {
 9227                                            el.child(h_flex().children(ui::render_modifiers(
 9228                                                &accept_keystroke.modifiers,
 9229                                                PlatformStyle::platform(),
 9230                                                Some(Color::Default),
 9231                                                Some(IconSize::XSmall.rems().into()),
 9232                                                false,
 9233                                            )))
 9234                                        },
 9235                                    ),
 9236                            )
 9237                            .into_any(),
 9238                    );
 9239                }
 9240
 9241                self.render_edit_prediction_cursor_popover_preview(
 9242                    prediction,
 9243                    cursor_point,
 9244                    style,
 9245                    cx,
 9246                )?
 9247            }
 9248
 9249            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9250                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9251                    stale_completion,
 9252                    cursor_point,
 9253                    style,
 9254                    cx,
 9255                )?,
 9256
 9257                None => pending_completion_container(provider_icon)
 9258                    .child(Label::new("...").size(LabelSize::Small)),
 9259            },
 9260
 9261            None => pending_completion_container(provider_icon)
 9262                .child(Label::new("...").size(LabelSize::Small)),
 9263        };
 9264
 9265        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9266            completion
 9267                .with_animation(
 9268                    "loading-completion",
 9269                    Animation::new(Duration::from_secs(2))
 9270                        .repeat()
 9271                        .with_easing(pulsating_between(0.4, 0.8)),
 9272                    |label, delta| label.opacity(delta),
 9273                )
 9274                .into_any_element()
 9275        } else {
 9276            completion.into_any_element()
 9277        };
 9278
 9279        let has_completion = self.active_edit_prediction.is_some();
 9280
 9281        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9282        Some(
 9283            h_flex()
 9284                .min_w(min_width)
 9285                .max_w(max_width)
 9286                .flex_1()
 9287                .elevation_2(cx)
 9288                .border_color(cx.theme().colors().border)
 9289                .child(
 9290                    div()
 9291                        .flex_1()
 9292                        .py_1()
 9293                        .px_2()
 9294                        .overflow_hidden()
 9295                        .child(completion),
 9296                )
 9297                .when_some(accept_keystroke, |el, accept_keystroke| {
 9298                    if !accept_keystroke.modifiers.modified() {
 9299                        return el;
 9300                    }
 9301
 9302                    el.child(
 9303                        h_flex()
 9304                            .h_full()
 9305                            .border_l_1()
 9306                            .rounded_r_lg()
 9307                            .border_color(cx.theme().colors().border)
 9308                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9309                            .gap_1()
 9310                            .py_1()
 9311                            .px_2()
 9312                            .child(
 9313                                h_flex()
 9314                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9315                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9316                                    .child(h_flex().children(ui::render_modifiers(
 9317                                        &accept_keystroke.modifiers,
 9318                                        PlatformStyle::platform(),
 9319                                        Some(if !has_completion {
 9320                                            Color::Muted
 9321                                        } else {
 9322                                            Color::Default
 9323                                        }),
 9324                                        None,
 9325                                        false,
 9326                                    ))),
 9327                            )
 9328                            .child(Label::new("Preview").into_any_element())
 9329                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9330                    )
 9331                })
 9332                .into_any(),
 9333        )
 9334    }
 9335
 9336    fn render_edit_prediction_cursor_popover_preview(
 9337        &self,
 9338        completion: &EditPredictionState,
 9339        cursor_point: Point,
 9340        style: &EditorStyle,
 9341        cx: &mut Context<Editor>,
 9342    ) -> Option<Div> {
 9343        use text::ToPoint as _;
 9344
 9345        fn render_relative_row_jump(
 9346            prefix: impl Into<String>,
 9347            current_row: u32,
 9348            target_row: u32,
 9349        ) -> Div {
 9350            let (row_diff, arrow) = if target_row < current_row {
 9351                (current_row - target_row, IconName::ArrowUp)
 9352            } else {
 9353                (target_row - current_row, IconName::ArrowDown)
 9354            };
 9355
 9356            h_flex()
 9357                .child(
 9358                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9359                        .color(Color::Muted)
 9360                        .size(LabelSize::Small),
 9361                )
 9362                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9363        }
 9364
 9365        let supports_jump = self
 9366            .edit_prediction_provider
 9367            .as_ref()
 9368            .map(|provider| provider.provider.supports_jump_to_edit())
 9369            .unwrap_or(true);
 9370
 9371        match &completion.completion {
 9372            EditPrediction::Move {
 9373                target, snapshot, ..
 9374            } => {
 9375                if !supports_jump {
 9376                    return None;
 9377                }
 9378
 9379                Some(
 9380                    h_flex()
 9381                        .px_2()
 9382                        .gap_2()
 9383                        .flex_1()
 9384                        .child(
 9385                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9386                                Icon::new(IconName::ZedPredictDown)
 9387                            } else {
 9388                                Icon::new(IconName::ZedPredictUp)
 9389                            },
 9390                        )
 9391                        .child(Label::new("Jump to Edit")),
 9392                )
 9393            }
 9394
 9395            EditPrediction::Edit {
 9396                edits,
 9397                edit_preview,
 9398                snapshot,
 9399                display_mode: _,
 9400            } => {
 9401                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9402
 9403                let (highlighted_edits, has_more_lines) =
 9404                    if let Some(edit_preview) = edit_preview.as_ref() {
 9405                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9406                            .first_line_preview()
 9407                    } else {
 9408                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9409                    };
 9410
 9411                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9412                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9413
 9414                let preview = h_flex()
 9415                    .gap_1()
 9416                    .min_w_16()
 9417                    .child(styled_text)
 9418                    .when(has_more_lines, |parent| parent.child(""));
 9419
 9420                let left = if supports_jump && first_edit_row != cursor_point.row {
 9421                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9422                        .into_any_element()
 9423                } else {
 9424                    let icon_name =
 9425                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9426                    Icon::new(icon_name).into_any_element()
 9427                };
 9428
 9429                Some(
 9430                    h_flex()
 9431                        .h_full()
 9432                        .flex_1()
 9433                        .gap_2()
 9434                        .pr_1()
 9435                        .overflow_x_hidden()
 9436                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9437                        .child(left)
 9438                        .child(preview),
 9439                )
 9440            }
 9441        }
 9442    }
 9443
 9444    pub fn render_context_menu(
 9445        &self,
 9446        style: &EditorStyle,
 9447        max_height_in_lines: u32,
 9448        window: &mut Window,
 9449        cx: &mut Context<Editor>,
 9450    ) -> Option<AnyElement> {
 9451        let menu = self.context_menu.borrow();
 9452        let menu = menu.as_ref()?;
 9453        if !menu.visible() {
 9454            return None;
 9455        };
 9456        Some(menu.render(style, max_height_in_lines, window, cx))
 9457    }
 9458
 9459    fn render_context_menu_aside(
 9460        &mut self,
 9461        max_size: Size<Pixels>,
 9462        window: &mut Window,
 9463        cx: &mut Context<Editor>,
 9464    ) -> Option<AnyElement> {
 9465        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9466            if menu.visible() {
 9467                menu.render_aside(max_size, window, cx)
 9468            } else {
 9469                None
 9470            }
 9471        })
 9472    }
 9473
 9474    fn hide_context_menu(
 9475        &mut self,
 9476        window: &mut Window,
 9477        cx: &mut Context<Self>,
 9478    ) -> Option<CodeContextMenu> {
 9479        cx.notify();
 9480        self.completion_tasks.clear();
 9481        let context_menu = self.context_menu.borrow_mut().take();
 9482        self.stale_edit_prediction_in_menu.take();
 9483        self.update_visible_edit_prediction(window, cx);
 9484        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9485            && let Some(completion_provider) = &self.completion_provider
 9486        {
 9487            completion_provider.selection_changed(None, window, cx);
 9488        }
 9489        context_menu
 9490    }
 9491
 9492    fn show_snippet_choices(
 9493        &mut self,
 9494        choices: &Vec<String>,
 9495        selection: Range<Anchor>,
 9496        cx: &mut Context<Self>,
 9497    ) {
 9498        let Some((_, buffer, _)) = self
 9499            .buffer()
 9500            .read(cx)
 9501            .excerpt_containing(selection.start, cx)
 9502        else {
 9503            return;
 9504        };
 9505        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9506        else {
 9507            return;
 9508        };
 9509        if buffer != end_buffer {
 9510            log::error!("expected anchor range to have matching buffer IDs");
 9511            return;
 9512        }
 9513
 9514        let id = post_inc(&mut self.next_completion_id);
 9515        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9516        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9517            CompletionsMenu::new_snippet_choices(
 9518                id,
 9519                true,
 9520                choices,
 9521                selection,
 9522                buffer,
 9523                snippet_sort_order,
 9524            ),
 9525        ));
 9526    }
 9527
 9528    pub fn insert_snippet(
 9529        &mut self,
 9530        insertion_ranges: &[Range<usize>],
 9531        snippet: Snippet,
 9532        window: &mut Window,
 9533        cx: &mut Context<Self>,
 9534    ) -> Result<()> {
 9535        struct Tabstop<T> {
 9536            is_end_tabstop: bool,
 9537            ranges: Vec<Range<T>>,
 9538            choices: Option<Vec<String>>,
 9539        }
 9540
 9541        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9542            let snippet_text: Arc<str> = snippet.text.clone().into();
 9543            let edits = insertion_ranges
 9544                .iter()
 9545                .cloned()
 9546                .map(|range| (range, snippet_text.clone()));
 9547            let autoindent_mode = AutoindentMode::Block {
 9548                original_indent_columns: Vec::new(),
 9549            };
 9550            buffer.edit(edits, Some(autoindent_mode), cx);
 9551
 9552            let snapshot = &*buffer.read(cx);
 9553            let snippet = &snippet;
 9554            snippet
 9555                .tabstops
 9556                .iter()
 9557                .map(|tabstop| {
 9558                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9559                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9560                    });
 9561                    let mut tabstop_ranges = tabstop
 9562                        .ranges
 9563                        .iter()
 9564                        .flat_map(|tabstop_range| {
 9565                            let mut delta = 0_isize;
 9566                            insertion_ranges.iter().map(move |insertion_range| {
 9567                                let insertion_start = insertion_range.start as isize + delta;
 9568                                delta +=
 9569                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9570
 9571                                let start = ((insertion_start + tabstop_range.start) as usize)
 9572                                    .min(snapshot.len());
 9573                                let end = ((insertion_start + tabstop_range.end) as usize)
 9574                                    .min(snapshot.len());
 9575                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9576                            })
 9577                        })
 9578                        .collect::<Vec<_>>();
 9579                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9580
 9581                    Tabstop {
 9582                        is_end_tabstop,
 9583                        ranges: tabstop_ranges,
 9584                        choices: tabstop.choices.clone(),
 9585                    }
 9586                })
 9587                .collect::<Vec<_>>()
 9588        });
 9589        if let Some(tabstop) = tabstops.first() {
 9590            self.change_selections(Default::default(), window, cx, |s| {
 9591                // Reverse order so that the first range is the newest created selection.
 9592                // Completions will use it and autoscroll will prioritize it.
 9593                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9594            });
 9595
 9596            if let Some(choices) = &tabstop.choices
 9597                && let Some(selection) = tabstop.ranges.first()
 9598            {
 9599                self.show_snippet_choices(choices, selection.clone(), cx)
 9600            }
 9601
 9602            // If we're already at the last tabstop and it's at the end of the snippet,
 9603            // we're done, we don't need to keep the state around.
 9604            if !tabstop.is_end_tabstop {
 9605                let choices = tabstops
 9606                    .iter()
 9607                    .map(|tabstop| tabstop.choices.clone())
 9608                    .collect();
 9609
 9610                let ranges = tabstops
 9611                    .into_iter()
 9612                    .map(|tabstop| tabstop.ranges)
 9613                    .collect::<Vec<_>>();
 9614
 9615                self.snippet_stack.push(SnippetState {
 9616                    active_index: 0,
 9617                    ranges,
 9618                    choices,
 9619                });
 9620            }
 9621
 9622            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9623            if self.autoclose_regions.is_empty() {
 9624                let snapshot = self.buffer.read(cx).snapshot(cx);
 9625                let mut all_selections = self.selections.all::<Point>(cx);
 9626                for selection in &mut all_selections {
 9627                    let selection_head = selection.head();
 9628                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9629                        continue;
 9630                    };
 9631
 9632                    let mut bracket_pair = None;
 9633                    let max_lookup_length = scope
 9634                        .brackets()
 9635                        .map(|(pair, _)| {
 9636                            pair.start
 9637                                .as_str()
 9638                                .chars()
 9639                                .count()
 9640                                .max(pair.end.as_str().chars().count())
 9641                        })
 9642                        .max();
 9643                    if let Some(max_lookup_length) = max_lookup_length {
 9644                        let next_text = snapshot
 9645                            .chars_at(selection_head)
 9646                            .take(max_lookup_length)
 9647                            .collect::<String>();
 9648                        let prev_text = snapshot
 9649                            .reversed_chars_at(selection_head)
 9650                            .take(max_lookup_length)
 9651                            .collect::<String>();
 9652
 9653                        for (pair, enabled) in scope.brackets() {
 9654                            if enabled
 9655                                && pair.close
 9656                                && prev_text.starts_with(pair.start.as_str())
 9657                                && next_text.starts_with(pair.end.as_str())
 9658                            {
 9659                                bracket_pair = Some(pair.clone());
 9660                                break;
 9661                            }
 9662                        }
 9663                    }
 9664
 9665                    if let Some(pair) = bracket_pair {
 9666                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9667                        let autoclose_enabled =
 9668                            self.use_autoclose && snapshot_settings.use_autoclose;
 9669                        if autoclose_enabled {
 9670                            let start = snapshot.anchor_after(selection_head);
 9671                            let end = snapshot.anchor_after(selection_head);
 9672                            self.autoclose_regions.push(AutocloseRegion {
 9673                                selection_id: selection.id,
 9674                                range: start..end,
 9675                                pair,
 9676                            });
 9677                        }
 9678                    }
 9679                }
 9680            }
 9681        }
 9682        Ok(())
 9683    }
 9684
 9685    pub fn move_to_next_snippet_tabstop(
 9686        &mut self,
 9687        window: &mut Window,
 9688        cx: &mut Context<Self>,
 9689    ) -> bool {
 9690        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9691    }
 9692
 9693    pub fn move_to_prev_snippet_tabstop(
 9694        &mut self,
 9695        window: &mut Window,
 9696        cx: &mut Context<Self>,
 9697    ) -> bool {
 9698        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9699    }
 9700
 9701    pub fn move_to_snippet_tabstop(
 9702        &mut self,
 9703        bias: Bias,
 9704        window: &mut Window,
 9705        cx: &mut Context<Self>,
 9706    ) -> bool {
 9707        if let Some(mut snippet) = self.snippet_stack.pop() {
 9708            match bias {
 9709                Bias::Left => {
 9710                    if snippet.active_index > 0 {
 9711                        snippet.active_index -= 1;
 9712                    } else {
 9713                        self.snippet_stack.push(snippet);
 9714                        return false;
 9715                    }
 9716                }
 9717                Bias::Right => {
 9718                    if snippet.active_index + 1 < snippet.ranges.len() {
 9719                        snippet.active_index += 1;
 9720                    } else {
 9721                        self.snippet_stack.push(snippet);
 9722                        return false;
 9723                    }
 9724                }
 9725            }
 9726            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9727                self.change_selections(Default::default(), window, cx, |s| {
 9728                    // Reverse order so that the first range is the newest created selection.
 9729                    // Completions will use it and autoscroll will prioritize it.
 9730                    s.select_ranges(current_ranges.iter().rev().cloned())
 9731                });
 9732
 9733                if let Some(choices) = &snippet.choices[snippet.active_index]
 9734                    && let Some(selection) = current_ranges.first()
 9735                {
 9736                    self.show_snippet_choices(choices, selection.clone(), cx);
 9737                }
 9738
 9739                // If snippet state is not at the last tabstop, push it back on the stack
 9740                if snippet.active_index + 1 < snippet.ranges.len() {
 9741                    self.snippet_stack.push(snippet);
 9742                }
 9743                return true;
 9744            }
 9745        }
 9746
 9747        false
 9748    }
 9749
 9750    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9751        self.transact(window, cx, |this, window, cx| {
 9752            this.select_all(&SelectAll, window, cx);
 9753            this.insert("", window, cx);
 9754        });
 9755    }
 9756
 9757    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9759        self.transact(window, cx, |this, window, cx| {
 9760            this.select_autoclose_pair(window, cx);
 9761            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9762            if !this.linked_edit_ranges.is_empty() {
 9763                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9764                let snapshot = this.buffer.read(cx).snapshot(cx);
 9765
 9766                for selection in selections.iter() {
 9767                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9768                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9769                    if selection_start.buffer_id != selection_end.buffer_id {
 9770                        continue;
 9771                    }
 9772                    if let Some(ranges) =
 9773                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9774                    {
 9775                        for (buffer, entries) in ranges {
 9776                            linked_ranges.entry(buffer).or_default().extend(entries);
 9777                        }
 9778                    }
 9779                }
 9780            }
 9781
 9782            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9783            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9784            for selection in &mut selections {
 9785                if selection.is_empty() {
 9786                    let old_head = selection.head();
 9787                    let mut new_head =
 9788                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9789                            .to_point(&display_map);
 9790                    if let Some((buffer, line_buffer_range)) = display_map
 9791                        .buffer_snapshot
 9792                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9793                    {
 9794                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9795                        let indent_len = match indent_size.kind {
 9796                            IndentKind::Space => {
 9797                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9798                            }
 9799                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9800                        };
 9801                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9802                            let indent_len = indent_len.get();
 9803                            new_head = cmp::min(
 9804                                new_head,
 9805                                MultiBufferPoint::new(
 9806                                    old_head.row,
 9807                                    ((old_head.column - 1) / indent_len) * indent_len,
 9808                                ),
 9809                            );
 9810                        }
 9811                    }
 9812
 9813                    selection.set_head(new_head, SelectionGoal::None);
 9814                }
 9815            }
 9816
 9817            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9818            this.insert("", window, cx);
 9819            let empty_str: Arc<str> = Arc::from("");
 9820            for (buffer, edits) in linked_ranges {
 9821                let snapshot = buffer.read(cx).snapshot();
 9822                use text::ToPoint as TP;
 9823
 9824                let edits = edits
 9825                    .into_iter()
 9826                    .map(|range| {
 9827                        let end_point = TP::to_point(&range.end, &snapshot);
 9828                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9829
 9830                        if end_point == start_point {
 9831                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9832                                .saturating_sub(1);
 9833                            start_point =
 9834                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9835                        };
 9836
 9837                        (start_point..end_point, empty_str.clone())
 9838                    })
 9839                    .sorted_by_key(|(range, _)| range.start)
 9840                    .collect::<Vec<_>>();
 9841                buffer.update(cx, |this, cx| {
 9842                    this.edit(edits, None, cx);
 9843                })
 9844            }
 9845            this.refresh_edit_prediction(true, false, window, cx);
 9846            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9847        });
 9848    }
 9849
 9850    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9852        self.transact(window, cx, |this, window, cx| {
 9853            this.change_selections(Default::default(), window, cx, |s| {
 9854                s.move_with(|map, selection| {
 9855                    if selection.is_empty() {
 9856                        let cursor = movement::right(map, selection.head());
 9857                        selection.end = cursor;
 9858                        selection.reversed = true;
 9859                        selection.goal = SelectionGoal::None;
 9860                    }
 9861                })
 9862            });
 9863            this.insert("", window, cx);
 9864            this.refresh_edit_prediction(true, false, window, cx);
 9865        });
 9866    }
 9867
 9868    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9869        if self.mode.is_single_line() {
 9870            cx.propagate();
 9871            return;
 9872        }
 9873
 9874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9875        if self.move_to_prev_snippet_tabstop(window, cx) {
 9876            return;
 9877        }
 9878        self.outdent(&Outdent, window, cx);
 9879    }
 9880
 9881    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9882        if self.mode.is_single_line() {
 9883            cx.propagate();
 9884            return;
 9885        }
 9886
 9887        if self.move_to_next_snippet_tabstop(window, cx) {
 9888            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9889            return;
 9890        }
 9891        if self.read_only(cx) {
 9892            return;
 9893        }
 9894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9895        let mut selections = self.selections.all_adjusted(cx);
 9896        let buffer = self.buffer.read(cx);
 9897        let snapshot = buffer.snapshot(cx);
 9898        let rows_iter = selections.iter().map(|s| s.head().row);
 9899        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9900
 9901        let has_some_cursor_in_whitespace = selections
 9902            .iter()
 9903            .filter(|selection| selection.is_empty())
 9904            .any(|selection| {
 9905                let cursor = selection.head();
 9906                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9907                cursor.column < current_indent.len
 9908            });
 9909
 9910        let mut edits = Vec::new();
 9911        let mut prev_edited_row = 0;
 9912        let mut row_delta = 0;
 9913        for selection in &mut selections {
 9914            if selection.start.row != prev_edited_row {
 9915                row_delta = 0;
 9916            }
 9917            prev_edited_row = selection.end.row;
 9918
 9919            // If the selection is non-empty, then increase the indentation of the selected lines.
 9920            if !selection.is_empty() {
 9921                row_delta =
 9922                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9923                continue;
 9924            }
 9925
 9926            let cursor = selection.head();
 9927            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9928            if let Some(suggested_indent) =
 9929                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9930            {
 9931                // Don't do anything if already at suggested indent
 9932                // and there is any other cursor which is not
 9933                if has_some_cursor_in_whitespace
 9934                    && cursor.column == current_indent.len
 9935                    && current_indent.len == suggested_indent.len
 9936                {
 9937                    continue;
 9938                }
 9939
 9940                // Adjust line and move cursor to suggested indent
 9941                // if cursor is not at suggested indent
 9942                if cursor.column < suggested_indent.len
 9943                    && cursor.column <= current_indent.len
 9944                    && current_indent.len <= suggested_indent.len
 9945                {
 9946                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9947                    selection.end = selection.start;
 9948                    if row_delta == 0 {
 9949                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9950                            cursor.row,
 9951                            current_indent,
 9952                            suggested_indent,
 9953                        ));
 9954                        row_delta = suggested_indent.len - current_indent.len;
 9955                    }
 9956                    continue;
 9957                }
 9958
 9959                // If current indent is more than suggested indent
 9960                // only move cursor to current indent and skip indent
 9961                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9962                    selection.start = Point::new(cursor.row, current_indent.len);
 9963                    selection.end = selection.start;
 9964                    continue;
 9965                }
 9966            }
 9967
 9968            // Otherwise, insert a hard or soft tab.
 9969            let settings = buffer.language_settings_at(cursor, cx);
 9970            let tab_size = if settings.hard_tabs {
 9971                IndentSize::tab()
 9972            } else {
 9973                let tab_size = settings.tab_size.get();
 9974                let indent_remainder = snapshot
 9975                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9976                    .flat_map(str::chars)
 9977                    .fold(row_delta % tab_size, |counter: u32, c| {
 9978                        if c == '\t' {
 9979                            0
 9980                        } else {
 9981                            (counter + 1) % tab_size
 9982                        }
 9983                    });
 9984
 9985                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9986                IndentSize::spaces(chars_to_next_tab_stop)
 9987            };
 9988            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9989            selection.end = selection.start;
 9990            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9991            row_delta += tab_size.len;
 9992        }
 9993
 9994        self.transact(window, cx, |this, window, cx| {
 9995            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9996            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9997            this.refresh_edit_prediction(true, false, window, cx);
 9998        });
 9999    }
10000
10001    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10002        if self.read_only(cx) {
10003            return;
10004        }
10005        if self.mode.is_single_line() {
10006            cx.propagate();
10007            return;
10008        }
10009
10010        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10011        let mut selections = self.selections.all::<Point>(cx);
10012        let mut prev_edited_row = 0;
10013        let mut row_delta = 0;
10014        let mut edits = Vec::new();
10015        let buffer = self.buffer.read(cx);
10016        let snapshot = buffer.snapshot(cx);
10017        for selection in &mut selections {
10018            if selection.start.row != prev_edited_row {
10019                row_delta = 0;
10020            }
10021            prev_edited_row = selection.end.row;
10022
10023            row_delta =
10024                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10025        }
10026
10027        self.transact(window, cx, |this, window, cx| {
10028            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10029            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10030        });
10031    }
10032
10033    fn indent_selection(
10034        buffer: &MultiBuffer,
10035        snapshot: &MultiBufferSnapshot,
10036        selection: &mut Selection<Point>,
10037        edits: &mut Vec<(Range<Point>, String)>,
10038        delta_for_start_row: u32,
10039        cx: &App,
10040    ) -> u32 {
10041        let settings = buffer.language_settings_at(selection.start, cx);
10042        let tab_size = settings.tab_size.get();
10043        let indent_kind = if settings.hard_tabs {
10044            IndentKind::Tab
10045        } else {
10046            IndentKind::Space
10047        };
10048        let mut start_row = selection.start.row;
10049        let mut end_row = selection.end.row + 1;
10050
10051        // If a selection ends at the beginning of a line, don't indent
10052        // that last line.
10053        if selection.end.column == 0 && selection.end.row > selection.start.row {
10054            end_row -= 1;
10055        }
10056
10057        // Avoid re-indenting a row that has already been indented by a
10058        // previous selection, but still update this selection's column
10059        // to reflect that indentation.
10060        if delta_for_start_row > 0 {
10061            start_row += 1;
10062            selection.start.column += delta_for_start_row;
10063            if selection.end.row == selection.start.row {
10064                selection.end.column += delta_for_start_row;
10065            }
10066        }
10067
10068        let mut delta_for_end_row = 0;
10069        let has_multiple_rows = start_row + 1 != end_row;
10070        for row in start_row..end_row {
10071            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10072            let indent_delta = match (current_indent.kind, indent_kind) {
10073                (IndentKind::Space, IndentKind::Space) => {
10074                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10075                    IndentSize::spaces(columns_to_next_tab_stop)
10076                }
10077                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10078                (_, IndentKind::Tab) => IndentSize::tab(),
10079            };
10080
10081            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10082                0
10083            } else {
10084                selection.start.column
10085            };
10086            let row_start = Point::new(row, start);
10087            edits.push((
10088                row_start..row_start,
10089                indent_delta.chars().collect::<String>(),
10090            ));
10091
10092            // Update this selection's endpoints to reflect the indentation.
10093            if row == selection.start.row {
10094                selection.start.column += indent_delta.len;
10095            }
10096            if row == selection.end.row {
10097                selection.end.column += indent_delta.len;
10098                delta_for_end_row = indent_delta.len;
10099            }
10100        }
10101
10102        if selection.start.row == selection.end.row {
10103            delta_for_start_row + delta_for_end_row
10104        } else {
10105            delta_for_end_row
10106        }
10107    }
10108
10109    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10110        if self.read_only(cx) {
10111            return;
10112        }
10113        if self.mode.is_single_line() {
10114            cx.propagate();
10115            return;
10116        }
10117
10118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10120        let selections = self.selections.all::<Point>(cx);
10121        let mut deletion_ranges = Vec::new();
10122        let mut last_outdent = None;
10123        {
10124            let buffer = self.buffer.read(cx);
10125            let snapshot = buffer.snapshot(cx);
10126            for selection in &selections {
10127                let settings = buffer.language_settings_at(selection.start, cx);
10128                let tab_size = settings.tab_size.get();
10129                let mut rows = selection.spanned_rows(false, &display_map);
10130
10131                // Avoid re-outdenting a row that has already been outdented by a
10132                // previous selection.
10133                if let Some(last_row) = last_outdent
10134                    && last_row == rows.start
10135                {
10136                    rows.start = rows.start.next_row();
10137                }
10138                let has_multiple_rows = rows.len() > 1;
10139                for row in rows.iter_rows() {
10140                    let indent_size = snapshot.indent_size_for_line(row);
10141                    if indent_size.len > 0 {
10142                        let deletion_len = match indent_size.kind {
10143                            IndentKind::Space => {
10144                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10145                                if columns_to_prev_tab_stop == 0 {
10146                                    tab_size
10147                                } else {
10148                                    columns_to_prev_tab_stop
10149                                }
10150                            }
10151                            IndentKind::Tab => 1,
10152                        };
10153                        let start = if has_multiple_rows
10154                            || deletion_len > selection.start.column
10155                            || indent_size.len < selection.start.column
10156                        {
10157                            0
10158                        } else {
10159                            selection.start.column - deletion_len
10160                        };
10161                        deletion_ranges.push(
10162                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10163                        );
10164                        last_outdent = Some(row);
10165                    }
10166                }
10167            }
10168        }
10169
10170        self.transact(window, cx, |this, window, cx| {
10171            this.buffer.update(cx, |buffer, cx| {
10172                let empty_str: Arc<str> = Arc::default();
10173                buffer.edit(
10174                    deletion_ranges
10175                        .into_iter()
10176                        .map(|range| (range, empty_str.clone())),
10177                    None,
10178                    cx,
10179                );
10180            });
10181            let selections = this.selections.all::<usize>(cx);
10182            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10183        });
10184    }
10185
10186    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10187        if self.read_only(cx) {
10188            return;
10189        }
10190        if self.mode.is_single_line() {
10191            cx.propagate();
10192            return;
10193        }
10194
10195        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10196        let selections = self
10197            .selections
10198            .all::<usize>(cx)
10199            .into_iter()
10200            .map(|s| s.range());
10201
10202        self.transact(window, cx, |this, window, cx| {
10203            this.buffer.update(cx, |buffer, cx| {
10204                buffer.autoindent_ranges(selections, cx);
10205            });
10206            let selections = this.selections.all::<usize>(cx);
10207            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10208        });
10209    }
10210
10211    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10212        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10213        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10214        let selections = self.selections.all::<Point>(cx);
10215
10216        let mut new_cursors = Vec::new();
10217        let mut edit_ranges = Vec::new();
10218        let mut selections = selections.iter().peekable();
10219        while let Some(selection) = selections.next() {
10220            let mut rows = selection.spanned_rows(false, &display_map);
10221            let goal_display_column = selection.head().to_display_point(&display_map).column();
10222
10223            // Accumulate contiguous regions of rows that we want to delete.
10224            while let Some(next_selection) = selections.peek() {
10225                let next_rows = next_selection.spanned_rows(false, &display_map);
10226                if next_rows.start <= rows.end {
10227                    rows.end = next_rows.end;
10228                    selections.next().unwrap();
10229                } else {
10230                    break;
10231                }
10232            }
10233
10234            let buffer = &display_map.buffer_snapshot;
10235            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10236            let edit_end;
10237            let cursor_buffer_row;
10238            if buffer.max_point().row >= rows.end.0 {
10239                // If there's a line after the range, delete the \n from the end of the row range
10240                // and position the cursor on the next line.
10241                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10242                cursor_buffer_row = rows.end;
10243            } else {
10244                // If there isn't a line after the range, delete the \n from the line before the
10245                // start of the row range and position the cursor there.
10246                edit_start = edit_start.saturating_sub(1);
10247                edit_end = buffer.len();
10248                cursor_buffer_row = rows.start.previous_row();
10249            }
10250
10251            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10252            *cursor.column_mut() =
10253                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10254
10255            new_cursors.push((
10256                selection.id,
10257                buffer.anchor_after(cursor.to_point(&display_map)),
10258            ));
10259            edit_ranges.push(edit_start..edit_end);
10260        }
10261
10262        self.transact(window, cx, |this, window, cx| {
10263            let buffer = this.buffer.update(cx, |buffer, cx| {
10264                let empty_str: Arc<str> = Arc::default();
10265                buffer.edit(
10266                    edit_ranges
10267                        .into_iter()
10268                        .map(|range| (range, empty_str.clone())),
10269                    None,
10270                    cx,
10271                );
10272                buffer.snapshot(cx)
10273            });
10274            let new_selections = new_cursors
10275                .into_iter()
10276                .map(|(id, cursor)| {
10277                    let cursor = cursor.to_point(&buffer);
10278                    Selection {
10279                        id,
10280                        start: cursor,
10281                        end: cursor,
10282                        reversed: false,
10283                        goal: SelectionGoal::None,
10284                    }
10285                })
10286                .collect();
10287
10288            this.change_selections(Default::default(), window, cx, |s| {
10289                s.select(new_selections);
10290            });
10291        });
10292    }
10293
10294    pub fn join_lines_impl(
10295        &mut self,
10296        insert_whitespace: bool,
10297        window: &mut Window,
10298        cx: &mut Context<Self>,
10299    ) {
10300        if self.read_only(cx) {
10301            return;
10302        }
10303        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10304        for selection in self.selections.all::<Point>(cx) {
10305            let start = MultiBufferRow(selection.start.row);
10306            // Treat single line selections as if they include the next line. Otherwise this action
10307            // would do nothing for single line selections individual cursors.
10308            let end = if selection.start.row == selection.end.row {
10309                MultiBufferRow(selection.start.row + 1)
10310            } else {
10311                MultiBufferRow(selection.end.row)
10312            };
10313
10314            if let Some(last_row_range) = row_ranges.last_mut()
10315                && start <= last_row_range.end
10316            {
10317                last_row_range.end = end;
10318                continue;
10319            }
10320            row_ranges.push(start..end);
10321        }
10322
10323        let snapshot = self.buffer.read(cx).snapshot(cx);
10324        let mut cursor_positions = Vec::new();
10325        for row_range in &row_ranges {
10326            let anchor = snapshot.anchor_before(Point::new(
10327                row_range.end.previous_row().0,
10328                snapshot.line_len(row_range.end.previous_row()),
10329            ));
10330            cursor_positions.push(anchor..anchor);
10331        }
10332
10333        self.transact(window, cx, |this, window, cx| {
10334            for row_range in row_ranges.into_iter().rev() {
10335                for row in row_range.iter_rows().rev() {
10336                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10337                    let next_line_row = row.next_row();
10338                    let indent = snapshot.indent_size_for_line(next_line_row);
10339                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10340
10341                    let replace =
10342                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10343                            " "
10344                        } else {
10345                            ""
10346                        };
10347
10348                    this.buffer.update(cx, |buffer, cx| {
10349                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10350                    });
10351                }
10352            }
10353
10354            this.change_selections(Default::default(), window, cx, |s| {
10355                s.select_anchor_ranges(cursor_positions)
10356            });
10357        });
10358    }
10359
10360    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10361        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10362        self.join_lines_impl(true, window, cx);
10363    }
10364
10365    pub fn sort_lines_case_sensitive(
10366        &mut self,
10367        _: &SortLinesCaseSensitive,
10368        window: &mut Window,
10369        cx: &mut Context<Self>,
10370    ) {
10371        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10372    }
10373
10374    pub fn sort_lines_by_length(
10375        &mut self,
10376        _: &SortLinesByLength,
10377        window: &mut Window,
10378        cx: &mut Context<Self>,
10379    ) {
10380        self.manipulate_immutable_lines(window, cx, |lines| {
10381            lines.sort_by_key(|&line| line.chars().count())
10382        })
10383    }
10384
10385    pub fn sort_lines_case_insensitive(
10386        &mut self,
10387        _: &SortLinesCaseInsensitive,
10388        window: &mut Window,
10389        cx: &mut Context<Self>,
10390    ) {
10391        self.manipulate_immutable_lines(window, cx, |lines| {
10392            lines.sort_by_key(|line| line.to_lowercase())
10393        })
10394    }
10395
10396    pub fn unique_lines_case_insensitive(
10397        &mut self,
10398        _: &UniqueLinesCaseInsensitive,
10399        window: &mut Window,
10400        cx: &mut Context<Self>,
10401    ) {
10402        self.manipulate_immutable_lines(window, cx, |lines| {
10403            let mut seen = HashSet::default();
10404            lines.retain(|line| seen.insert(line.to_lowercase()));
10405        })
10406    }
10407
10408    pub fn unique_lines_case_sensitive(
10409        &mut self,
10410        _: &UniqueLinesCaseSensitive,
10411        window: &mut Window,
10412        cx: &mut Context<Self>,
10413    ) {
10414        self.manipulate_immutable_lines(window, cx, |lines| {
10415            let mut seen = HashSet::default();
10416            lines.retain(|line| seen.insert(*line));
10417        })
10418    }
10419
10420    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10421        let Some(project) = self.project.clone() else {
10422            return;
10423        };
10424        self.reload(project, window, cx)
10425            .detach_and_notify_err(window, cx);
10426    }
10427
10428    pub fn restore_file(
10429        &mut self,
10430        _: &::git::RestoreFile,
10431        window: &mut Window,
10432        cx: &mut Context<Self>,
10433    ) {
10434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10435        let mut buffer_ids = HashSet::default();
10436        let snapshot = self.buffer().read(cx).snapshot(cx);
10437        for selection in self.selections.all::<usize>(cx) {
10438            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10439        }
10440
10441        let buffer = self.buffer().read(cx);
10442        let ranges = buffer_ids
10443            .into_iter()
10444            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10445            .collect::<Vec<_>>();
10446
10447        self.restore_hunks_in_ranges(ranges, window, cx);
10448    }
10449
10450    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10452        let selections = self
10453            .selections
10454            .all(cx)
10455            .into_iter()
10456            .map(|s| s.range())
10457            .collect();
10458        self.restore_hunks_in_ranges(selections, window, cx);
10459    }
10460
10461    pub fn restore_hunks_in_ranges(
10462        &mut self,
10463        ranges: Vec<Range<Point>>,
10464        window: &mut Window,
10465        cx: &mut Context<Editor>,
10466    ) {
10467        let mut revert_changes = HashMap::default();
10468        let chunk_by = self
10469            .snapshot(window, cx)
10470            .hunks_for_ranges(ranges)
10471            .into_iter()
10472            .chunk_by(|hunk| hunk.buffer_id);
10473        for (buffer_id, hunks) in &chunk_by {
10474            let hunks = hunks.collect::<Vec<_>>();
10475            for hunk in &hunks {
10476                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10477            }
10478            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10479        }
10480        drop(chunk_by);
10481        if !revert_changes.is_empty() {
10482            self.transact(window, cx, |editor, window, cx| {
10483                editor.restore(revert_changes, window, cx);
10484            });
10485        }
10486    }
10487
10488    pub fn open_active_item_in_terminal(
10489        &mut self,
10490        _: &OpenInTerminal,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10495            let project_path = buffer.read(cx).project_path(cx)?;
10496            let project = self.project()?.read(cx);
10497            let entry = project.entry_for_path(&project_path, cx)?;
10498            let parent = match &entry.canonical_path {
10499                Some(canonical_path) => canonical_path.to_path_buf(),
10500                None => project.absolute_path(&project_path, cx)?,
10501            }
10502            .parent()?
10503            .to_path_buf();
10504            Some(parent)
10505        }) {
10506            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10507        }
10508    }
10509
10510    fn set_breakpoint_context_menu(
10511        &mut self,
10512        display_row: DisplayRow,
10513        position: Option<Anchor>,
10514        clicked_point: gpui::Point<Pixels>,
10515        window: &mut Window,
10516        cx: &mut Context<Self>,
10517    ) {
10518        let source = self
10519            .buffer
10520            .read(cx)
10521            .snapshot(cx)
10522            .anchor_before(Point::new(display_row.0, 0u32));
10523
10524        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10525
10526        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10527            self,
10528            source,
10529            clicked_point,
10530            context_menu,
10531            window,
10532            cx,
10533        );
10534    }
10535
10536    fn add_edit_breakpoint_block(
10537        &mut self,
10538        anchor: Anchor,
10539        breakpoint: &Breakpoint,
10540        edit_action: BreakpointPromptEditAction,
10541        window: &mut Window,
10542        cx: &mut Context<Self>,
10543    ) {
10544        let weak_editor = cx.weak_entity();
10545        let bp_prompt = cx.new(|cx| {
10546            BreakpointPromptEditor::new(
10547                weak_editor,
10548                anchor,
10549                breakpoint.clone(),
10550                edit_action,
10551                window,
10552                cx,
10553            )
10554        });
10555
10556        let height = bp_prompt.update(cx, |this, cx| {
10557            this.prompt
10558                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10559        });
10560        let cloned_prompt = bp_prompt.clone();
10561        let blocks = vec![BlockProperties {
10562            style: BlockStyle::Sticky,
10563            placement: BlockPlacement::Above(anchor),
10564            height: Some(height),
10565            render: Arc::new(move |cx| {
10566                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10567                cloned_prompt.clone().into_any_element()
10568            }),
10569            priority: 0,
10570        }];
10571
10572        let focus_handle = bp_prompt.focus_handle(cx);
10573        window.focus(&focus_handle);
10574
10575        let block_ids = self.insert_blocks(blocks, None, cx);
10576        bp_prompt.update(cx, |prompt, _| {
10577            prompt.add_block_ids(block_ids);
10578        });
10579    }
10580
10581    pub(crate) fn breakpoint_at_row(
10582        &self,
10583        row: u32,
10584        window: &mut Window,
10585        cx: &mut Context<Self>,
10586    ) -> Option<(Anchor, Breakpoint)> {
10587        let snapshot = self.snapshot(window, cx);
10588        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10589
10590        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10591    }
10592
10593    pub(crate) fn breakpoint_at_anchor(
10594        &self,
10595        breakpoint_position: Anchor,
10596        snapshot: &EditorSnapshot,
10597        cx: &mut Context<Self>,
10598    ) -> Option<(Anchor, Breakpoint)> {
10599        let buffer = self
10600            .buffer
10601            .read(cx)
10602            .buffer_for_anchor(breakpoint_position, cx)?;
10603
10604        let enclosing_excerpt = breakpoint_position.excerpt_id;
10605        let buffer_snapshot = buffer.read(cx).snapshot();
10606
10607        let row = buffer_snapshot
10608            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10609            .row;
10610
10611        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10612        let anchor_end = snapshot
10613            .buffer_snapshot
10614            .anchor_after(Point::new(row, line_len));
10615
10616        self.breakpoint_store
10617            .as_ref()?
10618            .read_with(cx, |breakpoint_store, cx| {
10619                breakpoint_store
10620                    .breakpoints(
10621                        &buffer,
10622                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10623                        &buffer_snapshot,
10624                        cx,
10625                    )
10626                    .next()
10627                    .and_then(|(bp, _)| {
10628                        let breakpoint_row = buffer_snapshot
10629                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10630                            .row;
10631
10632                        if breakpoint_row == row {
10633                            snapshot
10634                                .buffer_snapshot
10635                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10636                                .map(|position| (position, bp.bp.clone()))
10637                        } else {
10638                            None
10639                        }
10640                    })
10641            })
10642    }
10643
10644    pub fn edit_log_breakpoint(
10645        &mut self,
10646        _: &EditLogBreakpoint,
10647        window: &mut Window,
10648        cx: &mut Context<Self>,
10649    ) {
10650        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10651            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10652                message: None,
10653                state: BreakpointState::Enabled,
10654                condition: None,
10655                hit_condition: None,
10656            });
10657
10658            self.add_edit_breakpoint_block(
10659                anchor,
10660                &breakpoint,
10661                BreakpointPromptEditAction::Log,
10662                window,
10663                cx,
10664            );
10665        }
10666    }
10667
10668    fn breakpoints_at_cursors(
10669        &self,
10670        window: &mut Window,
10671        cx: &mut Context<Self>,
10672    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10673        let snapshot = self.snapshot(window, cx);
10674        let cursors = self
10675            .selections
10676            .disjoint_anchors()
10677            .iter()
10678            .map(|selection| {
10679                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10680
10681                let breakpoint_position = self
10682                    .breakpoint_at_row(cursor_position.row, window, cx)
10683                    .map(|bp| bp.0)
10684                    .unwrap_or_else(|| {
10685                        snapshot
10686                            .display_snapshot
10687                            .buffer_snapshot
10688                            .anchor_after(Point::new(cursor_position.row, 0))
10689                    });
10690
10691                let breakpoint = self
10692                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10693                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10694
10695                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10696            })
10697            // 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.
10698            .collect::<HashMap<Anchor, _>>();
10699
10700        cursors.into_iter().collect()
10701    }
10702
10703    pub fn enable_breakpoint(
10704        &mut self,
10705        _: &crate::actions::EnableBreakpoint,
10706        window: &mut Window,
10707        cx: &mut Context<Self>,
10708    ) {
10709        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10710            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10711                continue;
10712            };
10713            self.edit_breakpoint_at_anchor(
10714                anchor,
10715                breakpoint,
10716                BreakpointEditAction::InvertState,
10717                cx,
10718            );
10719        }
10720    }
10721
10722    pub fn disable_breakpoint(
10723        &mut self,
10724        _: &crate::actions::DisableBreakpoint,
10725        window: &mut Window,
10726        cx: &mut Context<Self>,
10727    ) {
10728        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10729            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10730                continue;
10731            };
10732            self.edit_breakpoint_at_anchor(
10733                anchor,
10734                breakpoint,
10735                BreakpointEditAction::InvertState,
10736                cx,
10737            );
10738        }
10739    }
10740
10741    pub fn toggle_breakpoint(
10742        &mut self,
10743        _: &crate::actions::ToggleBreakpoint,
10744        window: &mut Window,
10745        cx: &mut Context<Self>,
10746    ) {
10747        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10748            if let Some(breakpoint) = breakpoint {
10749                self.edit_breakpoint_at_anchor(
10750                    anchor,
10751                    breakpoint,
10752                    BreakpointEditAction::Toggle,
10753                    cx,
10754                );
10755            } else {
10756                self.edit_breakpoint_at_anchor(
10757                    anchor,
10758                    Breakpoint::new_standard(),
10759                    BreakpointEditAction::Toggle,
10760                    cx,
10761                );
10762            }
10763        }
10764    }
10765
10766    pub fn edit_breakpoint_at_anchor(
10767        &mut self,
10768        breakpoint_position: Anchor,
10769        breakpoint: Breakpoint,
10770        edit_action: BreakpointEditAction,
10771        cx: &mut Context<Self>,
10772    ) {
10773        let Some(breakpoint_store) = &self.breakpoint_store else {
10774            return;
10775        };
10776
10777        let Some(buffer) = self
10778            .buffer
10779            .read(cx)
10780            .buffer_for_anchor(breakpoint_position, cx)
10781        else {
10782            return;
10783        };
10784
10785        breakpoint_store.update(cx, |breakpoint_store, cx| {
10786            breakpoint_store.toggle_breakpoint(
10787                buffer,
10788                BreakpointWithPosition {
10789                    position: breakpoint_position.text_anchor,
10790                    bp: breakpoint,
10791                },
10792                edit_action,
10793                cx,
10794            );
10795        });
10796
10797        cx.notify();
10798    }
10799
10800    #[cfg(any(test, feature = "test-support"))]
10801    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10802        self.breakpoint_store.clone()
10803    }
10804
10805    pub fn prepare_restore_change(
10806        &self,
10807        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10808        hunk: &MultiBufferDiffHunk,
10809        cx: &mut App,
10810    ) -> Option<()> {
10811        if hunk.is_created_file() {
10812            return None;
10813        }
10814        let buffer = self.buffer.read(cx);
10815        let diff = buffer.diff_for(hunk.buffer_id)?;
10816        let buffer = buffer.buffer(hunk.buffer_id)?;
10817        let buffer = buffer.read(cx);
10818        let original_text = diff
10819            .read(cx)
10820            .base_text()
10821            .as_rope()
10822            .slice(hunk.diff_base_byte_range.clone());
10823        let buffer_snapshot = buffer.snapshot();
10824        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10825        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10826            probe
10827                .0
10828                .start
10829                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10830                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10831        }) {
10832            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10833            Some(())
10834        } else {
10835            None
10836        }
10837    }
10838
10839    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10840        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10841    }
10842
10843    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10844        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10845    }
10846
10847    fn manipulate_lines<M>(
10848        &mut self,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851        mut manipulate: M,
10852    ) where
10853        M: FnMut(&str) -> LineManipulationResult,
10854    {
10855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10856
10857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10858        let buffer = self.buffer.read(cx).snapshot(cx);
10859
10860        let mut edits = Vec::new();
10861
10862        let selections = self.selections.all::<Point>(cx);
10863        let mut selections = selections.iter().peekable();
10864        let mut contiguous_row_selections = Vec::new();
10865        let mut new_selections = Vec::new();
10866        let mut added_lines = 0;
10867        let mut removed_lines = 0;
10868
10869        while let Some(selection) = selections.next() {
10870            let (start_row, end_row) = consume_contiguous_rows(
10871                &mut contiguous_row_selections,
10872                selection,
10873                &display_map,
10874                &mut selections,
10875            );
10876
10877            let start_point = Point::new(start_row.0, 0);
10878            let end_point = Point::new(
10879                end_row.previous_row().0,
10880                buffer.line_len(end_row.previous_row()),
10881            );
10882            let text = buffer
10883                .text_for_range(start_point..end_point)
10884                .collect::<String>();
10885
10886            let LineManipulationResult {
10887                new_text,
10888                line_count_before,
10889                line_count_after,
10890            } = manipulate(&text);
10891
10892            edits.push((start_point..end_point, new_text));
10893
10894            // Selections must change based on added and removed line count
10895            let start_row =
10896                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10897            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10898            new_selections.push(Selection {
10899                id: selection.id,
10900                start: start_row,
10901                end: end_row,
10902                goal: SelectionGoal::None,
10903                reversed: selection.reversed,
10904            });
10905
10906            if line_count_after > line_count_before {
10907                added_lines += line_count_after - line_count_before;
10908            } else if line_count_before > line_count_after {
10909                removed_lines += line_count_before - line_count_after;
10910            }
10911        }
10912
10913        self.transact(window, cx, |this, window, cx| {
10914            let buffer = this.buffer.update(cx, |buffer, cx| {
10915                buffer.edit(edits, None, cx);
10916                buffer.snapshot(cx)
10917            });
10918
10919            // Recalculate offsets on newly edited buffer
10920            let new_selections = new_selections
10921                .iter()
10922                .map(|s| {
10923                    let start_point = Point::new(s.start.0, 0);
10924                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10925                    Selection {
10926                        id: s.id,
10927                        start: buffer.point_to_offset(start_point),
10928                        end: buffer.point_to_offset(end_point),
10929                        goal: s.goal,
10930                        reversed: s.reversed,
10931                    }
10932                })
10933                .collect();
10934
10935            this.change_selections(Default::default(), window, cx, |s| {
10936                s.select(new_selections);
10937            });
10938
10939            this.request_autoscroll(Autoscroll::fit(), cx);
10940        });
10941    }
10942
10943    fn manipulate_immutable_lines<Fn>(
10944        &mut self,
10945        window: &mut Window,
10946        cx: &mut Context<Self>,
10947        mut callback: Fn,
10948    ) where
10949        Fn: FnMut(&mut Vec<&str>),
10950    {
10951        self.manipulate_lines(window, cx, |text| {
10952            let mut lines: Vec<&str> = text.split('\n').collect();
10953            let line_count_before = lines.len();
10954
10955            callback(&mut lines);
10956
10957            LineManipulationResult {
10958                new_text: lines.join("\n"),
10959                line_count_before,
10960                line_count_after: lines.len(),
10961            }
10962        });
10963    }
10964
10965    fn manipulate_mutable_lines<Fn>(
10966        &mut self,
10967        window: &mut Window,
10968        cx: &mut Context<Self>,
10969        mut callback: Fn,
10970    ) where
10971        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10972    {
10973        self.manipulate_lines(window, cx, |text| {
10974            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10975            let line_count_before = lines.len();
10976
10977            callback(&mut lines);
10978
10979            LineManipulationResult {
10980                new_text: lines.join("\n"),
10981                line_count_before,
10982                line_count_after: lines.len(),
10983            }
10984        });
10985    }
10986
10987    pub fn convert_indentation_to_spaces(
10988        &mut self,
10989        _: &ConvertIndentationToSpaces,
10990        window: &mut Window,
10991        cx: &mut Context<Self>,
10992    ) {
10993        let settings = self.buffer.read(cx).language_settings(cx);
10994        let tab_size = settings.tab_size.get() as usize;
10995
10996        self.manipulate_mutable_lines(window, cx, |lines| {
10997            // Allocates a reasonably sized scratch buffer once for the whole loop
10998            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10999            // Avoids recomputing spaces that could be inserted many times
11000            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11001                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11002                .collect();
11003
11004            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11005                let mut chars = line.as_ref().chars();
11006                let mut col = 0;
11007                let mut changed = false;
11008
11009                for ch in chars.by_ref() {
11010                    match ch {
11011                        ' ' => {
11012                            reindented_line.push(' ');
11013                            col += 1;
11014                        }
11015                        '\t' => {
11016                            // \t are converted to spaces depending on the current column
11017                            let spaces_len = tab_size - (col % tab_size);
11018                            reindented_line.extend(&space_cache[spaces_len - 1]);
11019                            col += spaces_len;
11020                            changed = true;
11021                        }
11022                        _ => {
11023                            // If we dont append before break, the character is consumed
11024                            reindented_line.push(ch);
11025                            break;
11026                        }
11027                    }
11028                }
11029
11030                if !changed {
11031                    reindented_line.clear();
11032                    continue;
11033                }
11034                // Append the rest of the line and replace old reference with new one
11035                reindented_line.extend(chars);
11036                *line = Cow::Owned(reindented_line.clone());
11037                reindented_line.clear();
11038            }
11039        });
11040    }
11041
11042    pub fn convert_indentation_to_tabs(
11043        &mut self,
11044        _: &ConvertIndentationToTabs,
11045        window: &mut Window,
11046        cx: &mut Context<Self>,
11047    ) {
11048        let settings = self.buffer.read(cx).language_settings(cx);
11049        let tab_size = settings.tab_size.get() as usize;
11050
11051        self.manipulate_mutable_lines(window, cx, |lines| {
11052            // Allocates a reasonably sized buffer once for the whole loop
11053            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11054            // Avoids recomputing spaces that could be inserted many times
11055            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11056                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11057                .collect();
11058
11059            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11060                let mut chars = line.chars();
11061                let mut spaces_count = 0;
11062                let mut first_non_indent_char = None;
11063                let mut changed = false;
11064
11065                for ch in chars.by_ref() {
11066                    match ch {
11067                        ' ' => {
11068                            // Keep track of spaces. Append \t when we reach tab_size
11069                            spaces_count += 1;
11070                            changed = true;
11071                            if spaces_count == tab_size {
11072                                reindented_line.push('\t');
11073                                spaces_count = 0;
11074                            }
11075                        }
11076                        '\t' => {
11077                            reindented_line.push('\t');
11078                            spaces_count = 0;
11079                        }
11080                        _ => {
11081                            // Dont append it yet, we might have remaining spaces
11082                            first_non_indent_char = Some(ch);
11083                            break;
11084                        }
11085                    }
11086                }
11087
11088                if !changed {
11089                    reindented_line.clear();
11090                    continue;
11091                }
11092                // Remaining spaces that didn't make a full tab stop
11093                if spaces_count > 0 {
11094                    reindented_line.extend(&space_cache[spaces_count - 1]);
11095                }
11096                // If we consume an extra character that was not indentation, add it back
11097                if let Some(extra_char) = first_non_indent_char {
11098                    reindented_line.push(extra_char);
11099                }
11100                // Append the rest of the line and replace old reference with new one
11101                reindented_line.extend(chars);
11102                *line = Cow::Owned(reindented_line.clone());
11103                reindented_line.clear();
11104            }
11105        });
11106    }
11107
11108    pub fn convert_to_upper_case(
11109        &mut self,
11110        _: &ConvertToUpperCase,
11111        window: &mut Window,
11112        cx: &mut Context<Self>,
11113    ) {
11114        self.manipulate_text(window, cx, |text| text.to_uppercase())
11115    }
11116
11117    pub fn convert_to_lower_case(
11118        &mut self,
11119        _: &ConvertToLowerCase,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        self.manipulate_text(window, cx, |text| text.to_lowercase())
11124    }
11125
11126    pub fn convert_to_title_case(
11127        &mut self,
11128        _: &ConvertToTitleCase,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        self.manipulate_text(window, cx, |text| {
11133            text.split('\n')
11134                .map(|line| line.to_case(Case::Title))
11135                .join("\n")
11136        })
11137    }
11138
11139    pub fn convert_to_snake_case(
11140        &mut self,
11141        _: &ConvertToSnakeCase,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11146    }
11147
11148    pub fn convert_to_kebab_case(
11149        &mut self,
11150        _: &ConvertToKebabCase,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153    ) {
11154        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11155    }
11156
11157    pub fn convert_to_upper_camel_case(
11158        &mut self,
11159        _: &ConvertToUpperCamelCase,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162    ) {
11163        self.manipulate_text(window, cx, |text| {
11164            text.split('\n')
11165                .map(|line| line.to_case(Case::UpperCamel))
11166                .join("\n")
11167        })
11168    }
11169
11170    pub fn convert_to_lower_camel_case(
11171        &mut self,
11172        _: &ConvertToLowerCamelCase,
11173        window: &mut Window,
11174        cx: &mut Context<Self>,
11175    ) {
11176        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11177    }
11178
11179    pub fn convert_to_opposite_case(
11180        &mut self,
11181        _: &ConvertToOppositeCase,
11182        window: &mut Window,
11183        cx: &mut Context<Self>,
11184    ) {
11185        self.manipulate_text(window, cx, |text| {
11186            text.chars()
11187                .fold(String::with_capacity(text.len()), |mut t, c| {
11188                    if c.is_uppercase() {
11189                        t.extend(c.to_lowercase());
11190                    } else {
11191                        t.extend(c.to_uppercase());
11192                    }
11193                    t
11194                })
11195        })
11196    }
11197
11198    pub fn convert_to_sentence_case(
11199        &mut self,
11200        _: &ConvertToSentenceCase,
11201        window: &mut Window,
11202        cx: &mut Context<Self>,
11203    ) {
11204        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11205    }
11206
11207    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11208        self.manipulate_text(window, cx, |text| {
11209            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11210            if has_upper_case_characters {
11211                text.to_lowercase()
11212            } else {
11213                text.to_uppercase()
11214            }
11215        })
11216    }
11217
11218    pub fn convert_to_rot13(
11219        &mut self,
11220        _: &ConvertToRot13,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223    ) {
11224        self.manipulate_text(window, cx, |text| {
11225            text.chars()
11226                .map(|c| match c {
11227                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11228                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11229                    _ => c,
11230                })
11231                .collect()
11232        })
11233    }
11234
11235    pub fn convert_to_rot47(
11236        &mut self,
11237        _: &ConvertToRot47,
11238        window: &mut Window,
11239        cx: &mut Context<Self>,
11240    ) {
11241        self.manipulate_text(window, cx, |text| {
11242            text.chars()
11243                .map(|c| {
11244                    let code_point = c as u32;
11245                    if code_point >= 33 && code_point <= 126 {
11246                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11247                    }
11248                    c
11249                })
11250                .collect()
11251        })
11252    }
11253
11254    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11255    where
11256        Fn: FnMut(&str) -> String,
11257    {
11258        let buffer = self.buffer.read(cx).snapshot(cx);
11259
11260        let mut new_selections = Vec::new();
11261        let mut edits = Vec::new();
11262        let mut selection_adjustment = 0i32;
11263
11264        for selection in self.selections.all::<usize>(cx) {
11265            let selection_is_empty = selection.is_empty();
11266
11267            let (start, end) = if selection_is_empty {
11268                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11269                (word_range.start, word_range.end)
11270            } else {
11271                (selection.start, selection.end)
11272            };
11273
11274            let text = buffer.text_for_range(start..end).collect::<String>();
11275            let old_length = text.len() as i32;
11276            let text = callback(&text);
11277
11278            new_selections.push(Selection {
11279                start: (start as i32 - selection_adjustment) as usize,
11280                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11281                goal: SelectionGoal::None,
11282                ..selection
11283            });
11284
11285            selection_adjustment += old_length - text.len() as i32;
11286
11287            edits.push((start..end, text));
11288        }
11289
11290        self.transact(window, cx, |this, window, cx| {
11291            this.buffer.update(cx, |buffer, cx| {
11292                buffer.edit(edits, None, cx);
11293            });
11294
11295            this.change_selections(Default::default(), window, cx, |s| {
11296                s.select(new_selections);
11297            });
11298
11299            this.request_autoscroll(Autoscroll::fit(), cx);
11300        });
11301    }
11302
11303    pub fn move_selection_on_drop(
11304        &mut self,
11305        selection: &Selection<Anchor>,
11306        target: DisplayPoint,
11307        is_cut: bool,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11312        let buffer = &display_map.buffer_snapshot;
11313        let mut edits = Vec::new();
11314        let insert_point = display_map
11315            .clip_point(target, Bias::Left)
11316            .to_point(&display_map);
11317        let text = buffer
11318            .text_for_range(selection.start..selection.end)
11319            .collect::<String>();
11320        if is_cut {
11321            edits.push(((selection.start..selection.end), String::new()));
11322        }
11323        let insert_anchor = buffer.anchor_before(insert_point);
11324        edits.push(((insert_anchor..insert_anchor), text));
11325        let last_edit_start = insert_anchor.bias_left(buffer);
11326        let last_edit_end = insert_anchor.bias_right(buffer);
11327        self.transact(window, cx, |this, window, cx| {
11328            this.buffer.update(cx, |buffer, cx| {
11329                buffer.edit(edits, None, cx);
11330            });
11331            this.change_selections(Default::default(), window, cx, |s| {
11332                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11333            });
11334        });
11335    }
11336
11337    pub fn clear_selection_drag_state(&mut self) {
11338        self.selection_drag_state = SelectionDragState::None;
11339    }
11340
11341    pub fn duplicate(
11342        &mut self,
11343        upwards: bool,
11344        whole_lines: bool,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) {
11348        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11349
11350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11351        let buffer = &display_map.buffer_snapshot;
11352        let selections = self.selections.all::<Point>(cx);
11353
11354        let mut edits = Vec::new();
11355        let mut selections_iter = selections.iter().peekable();
11356        while let Some(selection) = selections_iter.next() {
11357            let mut rows = selection.spanned_rows(false, &display_map);
11358            // duplicate line-wise
11359            if whole_lines || selection.start == selection.end {
11360                // Avoid duplicating the same lines twice.
11361                while let Some(next_selection) = selections_iter.peek() {
11362                    let next_rows = next_selection.spanned_rows(false, &display_map);
11363                    if next_rows.start < rows.end {
11364                        rows.end = next_rows.end;
11365                        selections_iter.next().unwrap();
11366                    } else {
11367                        break;
11368                    }
11369                }
11370
11371                // Copy the text from the selected row region and splice it either at the start
11372                // or end of the region.
11373                let start = Point::new(rows.start.0, 0);
11374                let end = Point::new(
11375                    rows.end.previous_row().0,
11376                    buffer.line_len(rows.end.previous_row()),
11377                );
11378                let text = buffer
11379                    .text_for_range(start..end)
11380                    .chain(Some("\n"))
11381                    .collect::<String>();
11382                let insert_location = if upwards {
11383                    Point::new(rows.end.0, 0)
11384                } else {
11385                    start
11386                };
11387                edits.push((insert_location..insert_location, text));
11388            } else {
11389                // duplicate character-wise
11390                let start = selection.start;
11391                let end = selection.end;
11392                let text = buffer.text_for_range(start..end).collect::<String>();
11393                edits.push((selection.end..selection.end, text));
11394            }
11395        }
11396
11397        self.transact(window, cx, |this, _, cx| {
11398            this.buffer.update(cx, |buffer, cx| {
11399                buffer.edit(edits, None, cx);
11400            });
11401
11402            this.request_autoscroll(Autoscroll::fit(), cx);
11403        });
11404    }
11405
11406    pub fn duplicate_line_up(
11407        &mut self,
11408        _: &DuplicateLineUp,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        self.duplicate(true, true, window, cx);
11413    }
11414
11415    pub fn duplicate_line_down(
11416        &mut self,
11417        _: &DuplicateLineDown,
11418        window: &mut Window,
11419        cx: &mut Context<Self>,
11420    ) {
11421        self.duplicate(false, true, window, cx);
11422    }
11423
11424    pub fn duplicate_selection(
11425        &mut self,
11426        _: &DuplicateSelection,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        self.duplicate(false, false, window, cx);
11431    }
11432
11433    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11435        if self.mode.is_single_line() {
11436            cx.propagate();
11437            return;
11438        }
11439
11440        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11441        let buffer = self.buffer.read(cx).snapshot(cx);
11442
11443        let mut edits = Vec::new();
11444        let mut unfold_ranges = Vec::new();
11445        let mut refold_creases = Vec::new();
11446
11447        let selections = self.selections.all::<Point>(cx);
11448        let mut selections = selections.iter().peekable();
11449        let mut contiguous_row_selections = Vec::new();
11450        let mut new_selections = Vec::new();
11451
11452        while let Some(selection) = selections.next() {
11453            // Find all the selections that span a contiguous row range
11454            let (start_row, end_row) = consume_contiguous_rows(
11455                &mut contiguous_row_selections,
11456                selection,
11457                &display_map,
11458                &mut selections,
11459            );
11460
11461            // Move the text spanned by the row range to be before the line preceding the row range
11462            if start_row.0 > 0 {
11463                let range_to_move = Point::new(
11464                    start_row.previous_row().0,
11465                    buffer.line_len(start_row.previous_row()),
11466                )
11467                    ..Point::new(
11468                        end_row.previous_row().0,
11469                        buffer.line_len(end_row.previous_row()),
11470                    );
11471                let insertion_point = display_map
11472                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11473                    .0;
11474
11475                // Don't move lines across excerpts
11476                if buffer
11477                    .excerpt_containing(insertion_point..range_to_move.end)
11478                    .is_some()
11479                {
11480                    let text = buffer
11481                        .text_for_range(range_to_move.clone())
11482                        .flat_map(|s| s.chars())
11483                        .skip(1)
11484                        .chain(['\n'])
11485                        .collect::<String>();
11486
11487                    edits.push((
11488                        buffer.anchor_after(range_to_move.start)
11489                            ..buffer.anchor_before(range_to_move.end),
11490                        String::new(),
11491                    ));
11492                    let insertion_anchor = buffer.anchor_after(insertion_point);
11493                    edits.push((insertion_anchor..insertion_anchor, text));
11494
11495                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11496
11497                    // Move selections up
11498                    new_selections.extend(contiguous_row_selections.drain(..).map(
11499                        |mut selection| {
11500                            selection.start.row -= row_delta;
11501                            selection.end.row -= row_delta;
11502                            selection
11503                        },
11504                    ));
11505
11506                    // Move folds up
11507                    unfold_ranges.push(range_to_move.clone());
11508                    for fold in display_map.folds_in_range(
11509                        buffer.anchor_before(range_to_move.start)
11510                            ..buffer.anchor_after(range_to_move.end),
11511                    ) {
11512                        let mut start = fold.range.start.to_point(&buffer);
11513                        let mut end = fold.range.end.to_point(&buffer);
11514                        start.row -= row_delta;
11515                        end.row -= row_delta;
11516                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11517                    }
11518                }
11519            }
11520
11521            // If we didn't move line(s), preserve the existing selections
11522            new_selections.append(&mut contiguous_row_selections);
11523        }
11524
11525        self.transact(window, cx, |this, window, cx| {
11526            this.unfold_ranges(&unfold_ranges, true, true, cx);
11527            this.buffer.update(cx, |buffer, cx| {
11528                for (range, text) in edits {
11529                    buffer.edit([(range, text)], None, cx);
11530                }
11531            });
11532            this.fold_creases(refold_creases, true, window, cx);
11533            this.change_selections(Default::default(), window, cx, |s| {
11534                s.select(new_selections);
11535            })
11536        });
11537    }
11538
11539    pub fn move_line_down(
11540        &mut self,
11541        _: &MoveLineDown,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11546        if self.mode.is_single_line() {
11547            cx.propagate();
11548            return;
11549        }
11550
11551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11552        let buffer = self.buffer.read(cx).snapshot(cx);
11553
11554        let mut edits = Vec::new();
11555        let mut unfold_ranges = Vec::new();
11556        let mut refold_creases = Vec::new();
11557
11558        let selections = self.selections.all::<Point>(cx);
11559        let mut selections = selections.iter().peekable();
11560        let mut contiguous_row_selections = Vec::new();
11561        let mut new_selections = Vec::new();
11562
11563        while let Some(selection) = selections.next() {
11564            // Find all the selections that span a contiguous row range
11565            let (start_row, end_row) = consume_contiguous_rows(
11566                &mut contiguous_row_selections,
11567                selection,
11568                &display_map,
11569                &mut selections,
11570            );
11571
11572            // Move the text spanned by the row range to be after the last line of the row range
11573            if end_row.0 <= buffer.max_point().row {
11574                let range_to_move =
11575                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11576                let insertion_point = display_map
11577                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11578                    .0;
11579
11580                // Don't move lines across excerpt boundaries
11581                if buffer
11582                    .excerpt_containing(range_to_move.start..insertion_point)
11583                    .is_some()
11584                {
11585                    let mut text = String::from("\n");
11586                    text.extend(buffer.text_for_range(range_to_move.clone()));
11587                    text.pop(); // Drop trailing newline
11588                    edits.push((
11589                        buffer.anchor_after(range_to_move.start)
11590                            ..buffer.anchor_before(range_to_move.end),
11591                        String::new(),
11592                    ));
11593                    let insertion_anchor = buffer.anchor_after(insertion_point);
11594                    edits.push((insertion_anchor..insertion_anchor, text));
11595
11596                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11597
11598                    // Move selections down
11599                    new_selections.extend(contiguous_row_selections.drain(..).map(
11600                        |mut selection| {
11601                            selection.start.row += row_delta;
11602                            selection.end.row += row_delta;
11603                            selection
11604                        },
11605                    ));
11606
11607                    // Move folds down
11608                    unfold_ranges.push(range_to_move.clone());
11609                    for fold in display_map.folds_in_range(
11610                        buffer.anchor_before(range_to_move.start)
11611                            ..buffer.anchor_after(range_to_move.end),
11612                    ) {
11613                        let mut start = fold.range.start.to_point(&buffer);
11614                        let mut end = fold.range.end.to_point(&buffer);
11615                        start.row += row_delta;
11616                        end.row += row_delta;
11617                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11618                    }
11619                }
11620            }
11621
11622            // If we didn't move line(s), preserve the existing selections
11623            new_selections.append(&mut contiguous_row_selections);
11624        }
11625
11626        self.transact(window, cx, |this, window, cx| {
11627            this.unfold_ranges(&unfold_ranges, true, true, cx);
11628            this.buffer.update(cx, |buffer, cx| {
11629                for (range, text) in edits {
11630                    buffer.edit([(range, text)], None, cx);
11631                }
11632            });
11633            this.fold_creases(refold_creases, true, window, cx);
11634            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11635        });
11636    }
11637
11638    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11640        let text_layout_details = &self.text_layout_details(window);
11641        self.transact(window, cx, |this, window, cx| {
11642            let edits = this.change_selections(Default::default(), window, cx, |s| {
11643                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11644                s.move_with(|display_map, selection| {
11645                    if !selection.is_empty() {
11646                        return;
11647                    }
11648
11649                    let mut head = selection.head();
11650                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11651                    if head.column() == display_map.line_len(head.row()) {
11652                        transpose_offset = display_map
11653                            .buffer_snapshot
11654                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11655                    }
11656
11657                    if transpose_offset == 0 {
11658                        return;
11659                    }
11660
11661                    *head.column_mut() += 1;
11662                    head = display_map.clip_point(head, Bias::Right);
11663                    let goal = SelectionGoal::HorizontalPosition(
11664                        display_map
11665                            .x_for_display_point(head, text_layout_details)
11666                            .into(),
11667                    );
11668                    selection.collapse_to(head, goal);
11669
11670                    let transpose_start = display_map
11671                        .buffer_snapshot
11672                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11673                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11674                        let transpose_end = display_map
11675                            .buffer_snapshot
11676                            .clip_offset(transpose_offset + 1, Bias::Right);
11677                        if let Some(ch) =
11678                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11679                        {
11680                            edits.push((transpose_start..transpose_offset, String::new()));
11681                            edits.push((transpose_end..transpose_end, ch.to_string()));
11682                        }
11683                    }
11684                });
11685                edits
11686            });
11687            this.buffer
11688                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11689            let selections = this.selections.all::<usize>(cx);
11690            this.change_selections(Default::default(), window, cx, |s| {
11691                s.select(selections);
11692            });
11693        });
11694    }
11695
11696    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11698        if self.mode.is_single_line() {
11699            cx.propagate();
11700            return;
11701        }
11702
11703        self.rewrap_impl(RewrapOptions::default(), cx)
11704    }
11705
11706    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11707        let buffer = self.buffer.read(cx).snapshot(cx);
11708        let selections = self.selections.all::<Point>(cx);
11709
11710        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11711        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11712            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11713                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11714                .peekable();
11715
11716            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11717                row
11718            } else {
11719                return Vec::new();
11720            };
11721
11722            let language_settings = buffer.language_settings_at(selection.head(), cx);
11723            let language_scope = buffer.language_scope_at(selection.head());
11724
11725            let indent_and_prefix_for_row =
11726                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11727                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11728                    let (comment_prefix, rewrap_prefix) =
11729                        if let Some(language_scope) = &language_scope {
11730                            let indent_end = Point::new(row, indent.len);
11731                            let comment_prefix = language_scope
11732                                .line_comment_prefixes()
11733                                .iter()
11734                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11735                                .map(|prefix| prefix.to_string());
11736                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11737                            let line_text_after_indent = buffer
11738                                .text_for_range(indent_end..line_end)
11739                                .collect::<String>();
11740                            let rewrap_prefix = language_scope
11741                                .rewrap_prefixes()
11742                                .iter()
11743                                .find_map(|prefix_regex| {
11744                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11745                                        if mat.start() == 0 {
11746                                            Some(mat.as_str().to_string())
11747                                        } else {
11748                                            None
11749                                        }
11750                                    })
11751                                })
11752                                .flatten();
11753                            (comment_prefix, rewrap_prefix)
11754                        } else {
11755                            (None, None)
11756                        };
11757                    (indent, comment_prefix, rewrap_prefix)
11758                };
11759
11760            let mut ranges = Vec::new();
11761            let from_empty_selection = selection.is_empty();
11762
11763            let mut current_range_start = first_row;
11764            let mut prev_row = first_row;
11765            let (
11766                mut current_range_indent,
11767                mut current_range_comment_prefix,
11768                mut current_range_rewrap_prefix,
11769            ) = indent_and_prefix_for_row(first_row);
11770
11771            for row in non_blank_rows_iter.skip(1) {
11772                let has_paragraph_break = row > prev_row + 1;
11773
11774                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11775                    indent_and_prefix_for_row(row);
11776
11777                let has_indent_change = row_indent != current_range_indent;
11778                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11779
11780                let has_boundary_change = has_comment_change
11781                    || row_rewrap_prefix.is_some()
11782                    || (has_indent_change && current_range_comment_prefix.is_some());
11783
11784                if has_paragraph_break || has_boundary_change {
11785                    ranges.push((
11786                        language_settings.clone(),
11787                        Point::new(current_range_start, 0)
11788                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11789                        current_range_indent,
11790                        current_range_comment_prefix.clone(),
11791                        current_range_rewrap_prefix.clone(),
11792                        from_empty_selection,
11793                    ));
11794                    current_range_start = row;
11795                    current_range_indent = row_indent;
11796                    current_range_comment_prefix = row_comment_prefix;
11797                    current_range_rewrap_prefix = row_rewrap_prefix;
11798                }
11799                prev_row = row;
11800            }
11801
11802            ranges.push((
11803                language_settings.clone(),
11804                Point::new(current_range_start, 0)
11805                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11806                current_range_indent,
11807                current_range_comment_prefix,
11808                current_range_rewrap_prefix,
11809                from_empty_selection,
11810            ));
11811
11812            ranges
11813        });
11814
11815        let mut edits = Vec::new();
11816        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11817
11818        for (
11819            language_settings,
11820            wrap_range,
11821            indent_size,
11822            comment_prefix,
11823            rewrap_prefix,
11824            from_empty_selection,
11825        ) in wrap_ranges
11826        {
11827            let mut start_row = wrap_range.start.row;
11828            let mut end_row = wrap_range.end.row;
11829
11830            // Skip selections that overlap with a range that has already been rewrapped.
11831            let selection_range = start_row..end_row;
11832            if rewrapped_row_ranges
11833                .iter()
11834                .any(|range| range.overlaps(&selection_range))
11835            {
11836                continue;
11837            }
11838
11839            let tab_size = language_settings.tab_size;
11840
11841            let indent_prefix = indent_size.chars().collect::<String>();
11842            let mut line_prefix = indent_prefix.clone();
11843            let mut inside_comment = false;
11844            if let Some(prefix) = &comment_prefix {
11845                line_prefix.push_str(prefix);
11846                inside_comment = true;
11847            }
11848            if let Some(prefix) = &rewrap_prefix {
11849                line_prefix.push_str(prefix);
11850            }
11851
11852            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11853                RewrapBehavior::InComments => inside_comment,
11854                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11855                RewrapBehavior::Anywhere => true,
11856            };
11857
11858            let should_rewrap = options.override_language_settings
11859                || allow_rewrap_based_on_language
11860                || self.hard_wrap.is_some();
11861            if !should_rewrap {
11862                continue;
11863            }
11864
11865            if from_empty_selection {
11866                'expand_upwards: while start_row > 0 {
11867                    let prev_row = start_row - 1;
11868                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11869                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11870                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11871                    {
11872                        start_row = prev_row;
11873                    } else {
11874                        break 'expand_upwards;
11875                    }
11876                }
11877
11878                'expand_downwards: while end_row < buffer.max_point().row {
11879                    let next_row = end_row + 1;
11880                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11881                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11882                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11883                    {
11884                        end_row = next_row;
11885                    } else {
11886                        break 'expand_downwards;
11887                    }
11888                }
11889            }
11890
11891            let start = Point::new(start_row, 0);
11892            let start_offset = start.to_offset(&buffer);
11893            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11894            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11895            let Some(lines_without_prefixes) = selection_text
11896                .lines()
11897                .enumerate()
11898                .map(|(ix, line)| {
11899                    let line_trimmed = line.trim_start();
11900                    if rewrap_prefix.is_some() && ix > 0 {
11901                        Ok(line_trimmed)
11902                    } else {
11903                        line_trimmed
11904                            .strip_prefix(&line_prefix.trim_start())
11905                            .with_context(|| {
11906                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11907                            })
11908                    }
11909                })
11910                .collect::<Result<Vec<_>, _>>()
11911                .log_err()
11912            else {
11913                continue;
11914            };
11915
11916            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11917                buffer
11918                    .language_settings_at(Point::new(start_row, 0), cx)
11919                    .preferred_line_length as usize
11920            });
11921
11922            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11923                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11924            } else {
11925                line_prefix.clone()
11926            };
11927
11928            let wrapped_text = wrap_with_prefix(
11929                line_prefix,
11930                subsequent_lines_prefix,
11931                lines_without_prefixes.join("\n"),
11932                wrap_column,
11933                tab_size,
11934                options.preserve_existing_whitespace,
11935            );
11936
11937            // TODO: should always use char-based diff while still supporting cursor behavior that
11938            // matches vim.
11939            let mut diff_options = DiffOptions::default();
11940            if options.override_language_settings {
11941                diff_options.max_word_diff_len = 0;
11942                diff_options.max_word_diff_line_count = 0;
11943            } else {
11944                diff_options.max_word_diff_len = usize::MAX;
11945                diff_options.max_word_diff_line_count = usize::MAX;
11946            }
11947
11948            for (old_range, new_text) in
11949                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11950            {
11951                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11952                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11953                edits.push((edit_start..edit_end, new_text));
11954            }
11955
11956            rewrapped_row_ranges.push(start_row..=end_row);
11957        }
11958
11959        self.buffer
11960            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11961    }
11962
11963    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11964        let mut text = String::new();
11965        let buffer = self.buffer.read(cx).snapshot(cx);
11966        let mut selections = self.selections.all::<Point>(cx);
11967        let mut clipboard_selections = Vec::with_capacity(selections.len());
11968        {
11969            let max_point = buffer.max_point();
11970            let mut is_first = true;
11971            for selection in &mut selections {
11972                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11973                if is_entire_line {
11974                    selection.start = Point::new(selection.start.row, 0);
11975                    if !selection.is_empty() && selection.end.column == 0 {
11976                        selection.end = cmp::min(max_point, selection.end);
11977                    } else {
11978                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11979                    }
11980                    selection.goal = SelectionGoal::None;
11981                }
11982                if is_first {
11983                    is_first = false;
11984                } else {
11985                    text += "\n";
11986                }
11987                let mut len = 0;
11988                for chunk in buffer.text_for_range(selection.start..selection.end) {
11989                    text.push_str(chunk);
11990                    len += chunk.len();
11991                }
11992                clipboard_selections.push(ClipboardSelection {
11993                    len,
11994                    is_entire_line,
11995                    first_line_indent: buffer
11996                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11997                        .len,
11998                });
11999            }
12000        }
12001
12002        self.transact(window, cx, |this, window, cx| {
12003            this.change_selections(Default::default(), window, cx, |s| {
12004                s.select(selections);
12005            });
12006            this.insert("", window, cx);
12007        });
12008        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12009    }
12010
12011    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12012        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12013        let item = self.cut_common(window, cx);
12014        cx.write_to_clipboard(item);
12015    }
12016
12017    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12019        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12020            s.move_with(|snapshot, sel| {
12021                if sel.is_empty() {
12022                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12023                }
12024            });
12025        });
12026        let item = self.cut_common(window, cx);
12027        cx.set_global(KillRing(item))
12028    }
12029
12030    pub fn kill_ring_yank(
12031        &mut self,
12032        _: &KillRingYank,
12033        window: &mut Window,
12034        cx: &mut Context<Self>,
12035    ) {
12036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12037        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12038            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12039                (kill_ring.text().to_string(), kill_ring.metadata_json())
12040            } else {
12041                return;
12042            }
12043        } else {
12044            return;
12045        };
12046        self.do_paste(&text, metadata, false, window, cx);
12047    }
12048
12049    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12050        self.do_copy(true, cx);
12051    }
12052
12053    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12054        self.do_copy(false, cx);
12055    }
12056
12057    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12058        let selections = self.selections.all::<Point>(cx);
12059        let buffer = self.buffer.read(cx).read(cx);
12060        let mut text = String::new();
12061
12062        let mut clipboard_selections = Vec::with_capacity(selections.len());
12063        {
12064            let max_point = buffer.max_point();
12065            let mut is_first = true;
12066            for selection in &selections {
12067                let mut start = selection.start;
12068                let mut end = selection.end;
12069                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12070                if is_entire_line {
12071                    start = Point::new(start.row, 0);
12072                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12073                }
12074
12075                let mut trimmed_selections = Vec::new();
12076                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12077                    let row = MultiBufferRow(start.row);
12078                    let first_indent = buffer.indent_size_for_line(row);
12079                    if first_indent.len == 0 || start.column > first_indent.len {
12080                        trimmed_selections.push(start..end);
12081                    } else {
12082                        trimmed_selections.push(
12083                            Point::new(row.0, first_indent.len)
12084                                ..Point::new(row.0, buffer.line_len(row)),
12085                        );
12086                        for row in start.row + 1..=end.row {
12087                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12088                            if row == end.row {
12089                                line_len = end.column;
12090                            }
12091                            if line_len == 0 {
12092                                trimmed_selections
12093                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12094                                continue;
12095                            }
12096                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12097                            if row_indent_size.len >= first_indent.len {
12098                                trimmed_selections.push(
12099                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12100                                );
12101                            } else {
12102                                trimmed_selections.clear();
12103                                trimmed_selections.push(start..end);
12104                                break;
12105                            }
12106                        }
12107                    }
12108                } else {
12109                    trimmed_selections.push(start..end);
12110                }
12111
12112                for trimmed_range in trimmed_selections {
12113                    if is_first {
12114                        is_first = false;
12115                    } else {
12116                        text += "\n";
12117                    }
12118                    let mut len = 0;
12119                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12120                        text.push_str(chunk);
12121                        len += chunk.len();
12122                    }
12123                    clipboard_selections.push(ClipboardSelection {
12124                        len,
12125                        is_entire_line,
12126                        first_line_indent: buffer
12127                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12128                            .len,
12129                    });
12130                }
12131            }
12132        }
12133
12134        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12135            text,
12136            clipboard_selections,
12137        ));
12138    }
12139
12140    pub fn do_paste(
12141        &mut self,
12142        text: &String,
12143        clipboard_selections: Option<Vec<ClipboardSelection>>,
12144        handle_entire_lines: bool,
12145        window: &mut Window,
12146        cx: &mut Context<Self>,
12147    ) {
12148        if self.read_only(cx) {
12149            return;
12150        }
12151
12152        let clipboard_text = Cow::Borrowed(text);
12153
12154        self.transact(window, cx, |this, window, cx| {
12155            let had_active_edit_prediction = this.has_active_edit_prediction();
12156
12157            if let Some(mut clipboard_selections) = clipboard_selections {
12158                let old_selections = this.selections.all::<usize>(cx);
12159                let all_selections_were_entire_line =
12160                    clipboard_selections.iter().all(|s| s.is_entire_line);
12161                let first_selection_indent_column =
12162                    clipboard_selections.first().map(|s| s.first_line_indent);
12163                if clipboard_selections.len() != old_selections.len() {
12164                    clipboard_selections.drain(..);
12165                }
12166                let cursor_offset = this.selections.last::<usize>(cx).head();
12167                let mut auto_indent_on_paste = true;
12168
12169                this.buffer.update(cx, |buffer, cx| {
12170                    let snapshot = buffer.read(cx);
12171                    auto_indent_on_paste = snapshot
12172                        .language_settings_at(cursor_offset, cx)
12173                        .auto_indent_on_paste;
12174
12175                    let mut start_offset = 0;
12176                    let mut edits = Vec::new();
12177                    let mut original_indent_columns = Vec::new();
12178                    for (ix, selection) in old_selections.iter().enumerate() {
12179                        let to_insert;
12180                        let entire_line;
12181                        let original_indent_column;
12182                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12183                            let end_offset = start_offset + clipboard_selection.len;
12184                            to_insert = &clipboard_text[start_offset..end_offset];
12185                            entire_line = clipboard_selection.is_entire_line;
12186                            start_offset = end_offset + 1;
12187                            original_indent_column = Some(clipboard_selection.first_line_indent);
12188                        } else {
12189                            to_insert = clipboard_text.as_str();
12190                            entire_line = all_selections_were_entire_line;
12191                            original_indent_column = first_selection_indent_column
12192                        }
12193
12194                        // If the corresponding selection was empty when this slice of the
12195                        // clipboard text was written, then the entire line containing the
12196                        // selection was copied. If this selection is also currently empty,
12197                        // then paste the line before the current line of the buffer.
12198                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12199                            let column = selection.start.to_point(&snapshot).column as usize;
12200                            let line_start = selection.start - column;
12201                            line_start..line_start
12202                        } else {
12203                            selection.range()
12204                        };
12205
12206                        edits.push((range, to_insert));
12207                        original_indent_columns.push(original_indent_column);
12208                    }
12209                    drop(snapshot);
12210
12211                    buffer.edit(
12212                        edits,
12213                        if auto_indent_on_paste {
12214                            Some(AutoindentMode::Block {
12215                                original_indent_columns,
12216                            })
12217                        } else {
12218                            None
12219                        },
12220                        cx,
12221                    );
12222                });
12223
12224                let selections = this.selections.all::<usize>(cx);
12225                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12226            } else {
12227                this.insert(&clipboard_text, window, cx);
12228            }
12229
12230            let trigger_in_words =
12231                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12232
12233            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12234        });
12235    }
12236
12237    pub fn diff_clipboard_with_selection(
12238        &mut self,
12239        _: &DiffClipboardWithSelection,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242    ) {
12243        let selections = self.selections.all::<usize>(cx);
12244
12245        if selections.is_empty() {
12246            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12247            return;
12248        };
12249
12250        let clipboard_text = match cx.read_from_clipboard() {
12251            Some(item) => match item.entries().first() {
12252                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12253                _ => None,
12254            },
12255            None => None,
12256        };
12257
12258        let Some(clipboard_text) = clipboard_text else {
12259            log::warn!("Clipboard doesn't contain text.");
12260            return;
12261        };
12262
12263        window.dispatch_action(
12264            Box::new(DiffClipboardWithSelectionData {
12265                clipboard_text,
12266                editor: cx.entity(),
12267            }),
12268            cx,
12269        );
12270    }
12271
12272    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12274        if let Some(item) = cx.read_from_clipboard() {
12275            let entries = item.entries();
12276
12277            match entries.first() {
12278                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12279                // of all the pasted entries.
12280                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12281                    .do_paste(
12282                        clipboard_string.text(),
12283                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12284                        true,
12285                        window,
12286                        cx,
12287                    ),
12288                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12289            }
12290        }
12291    }
12292
12293    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12294        if self.read_only(cx) {
12295            return;
12296        }
12297
12298        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12299
12300        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12301            if let Some((selections, _)) =
12302                self.selection_history.transaction(transaction_id).cloned()
12303            {
12304                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12305                    s.select_anchors(selections.to_vec());
12306                });
12307            } else {
12308                log::error!(
12309                    "No entry in selection_history found for undo. \
12310                     This may correspond to a bug where undo does not update the selection. \
12311                     If this is occurring, please add details to \
12312                     https://github.com/zed-industries/zed/issues/22692"
12313                );
12314            }
12315            self.request_autoscroll(Autoscroll::fit(), cx);
12316            self.unmark_text(window, cx);
12317            self.refresh_edit_prediction(true, false, window, cx);
12318            cx.emit(EditorEvent::Edited { transaction_id });
12319            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12320        }
12321    }
12322
12323    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12324        if self.read_only(cx) {
12325            return;
12326        }
12327
12328        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12329
12330        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12331            if let Some((_, Some(selections))) =
12332                self.selection_history.transaction(transaction_id).cloned()
12333            {
12334                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12335                    s.select_anchors(selections.to_vec());
12336                });
12337            } else {
12338                log::error!(
12339                    "No entry in selection_history found for redo. \
12340                     This may correspond to a bug where undo does not update the selection. \
12341                     If this is occurring, please add details to \
12342                     https://github.com/zed-industries/zed/issues/22692"
12343                );
12344            }
12345            self.request_autoscroll(Autoscroll::fit(), cx);
12346            self.unmark_text(window, cx);
12347            self.refresh_edit_prediction(true, false, window, cx);
12348            cx.emit(EditorEvent::Edited { transaction_id });
12349        }
12350    }
12351
12352    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12353        self.buffer
12354            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12355    }
12356
12357    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12358        self.buffer
12359            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12360    }
12361
12362    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12364        self.change_selections(Default::default(), window, cx, |s| {
12365            s.move_with(|map, selection| {
12366                let cursor = if selection.is_empty() {
12367                    movement::left(map, selection.start)
12368                } else {
12369                    selection.start
12370                };
12371                selection.collapse_to(cursor, SelectionGoal::None);
12372            });
12373        })
12374    }
12375
12376    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12378        self.change_selections(Default::default(), window, cx, |s| {
12379            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12380        })
12381    }
12382
12383    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12385        self.change_selections(Default::default(), window, cx, |s| {
12386            s.move_with(|map, selection| {
12387                let cursor = if selection.is_empty() {
12388                    movement::right(map, selection.end)
12389                } else {
12390                    selection.end
12391                };
12392                selection.collapse_to(cursor, SelectionGoal::None)
12393            });
12394        })
12395    }
12396
12397    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12399        self.change_selections(Default::default(), window, cx, |s| {
12400            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12401        })
12402    }
12403
12404    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12405        if self.take_rename(true, window, cx).is_some() {
12406            return;
12407        }
12408
12409        if self.mode.is_single_line() {
12410            cx.propagate();
12411            return;
12412        }
12413
12414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12415
12416        let text_layout_details = &self.text_layout_details(window);
12417        let selection_count = self.selections.count();
12418        let first_selection = self.selections.first_anchor();
12419
12420        self.change_selections(Default::default(), window, cx, |s| {
12421            s.move_with(|map, selection| {
12422                if !selection.is_empty() {
12423                    selection.goal = SelectionGoal::None;
12424                }
12425                let (cursor, goal) = movement::up(
12426                    map,
12427                    selection.start,
12428                    selection.goal,
12429                    false,
12430                    text_layout_details,
12431                );
12432                selection.collapse_to(cursor, goal);
12433            });
12434        });
12435
12436        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12437        {
12438            cx.propagate();
12439        }
12440    }
12441
12442    pub fn move_up_by_lines(
12443        &mut self,
12444        action: &MoveUpByLines,
12445        window: &mut Window,
12446        cx: &mut Context<Self>,
12447    ) {
12448        if self.take_rename(true, window, cx).is_some() {
12449            return;
12450        }
12451
12452        if self.mode.is_single_line() {
12453            cx.propagate();
12454            return;
12455        }
12456
12457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12458
12459        let text_layout_details = &self.text_layout_details(window);
12460
12461        self.change_selections(Default::default(), window, cx, |s| {
12462            s.move_with(|map, selection| {
12463                if !selection.is_empty() {
12464                    selection.goal = SelectionGoal::None;
12465                }
12466                let (cursor, goal) = movement::up_by_rows(
12467                    map,
12468                    selection.start,
12469                    action.lines,
12470                    selection.goal,
12471                    false,
12472                    text_layout_details,
12473                );
12474                selection.collapse_to(cursor, goal);
12475            });
12476        })
12477    }
12478
12479    pub fn move_down_by_lines(
12480        &mut self,
12481        action: &MoveDownByLines,
12482        window: &mut Window,
12483        cx: &mut Context<Self>,
12484    ) {
12485        if self.take_rename(true, window, cx).is_some() {
12486            return;
12487        }
12488
12489        if self.mode.is_single_line() {
12490            cx.propagate();
12491            return;
12492        }
12493
12494        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12495
12496        let text_layout_details = &self.text_layout_details(window);
12497
12498        self.change_selections(Default::default(), window, cx, |s| {
12499            s.move_with(|map, selection| {
12500                if !selection.is_empty() {
12501                    selection.goal = SelectionGoal::None;
12502                }
12503                let (cursor, goal) = movement::down_by_rows(
12504                    map,
12505                    selection.start,
12506                    action.lines,
12507                    selection.goal,
12508                    false,
12509                    text_layout_details,
12510                );
12511                selection.collapse_to(cursor, goal);
12512            });
12513        })
12514    }
12515
12516    pub fn select_down_by_lines(
12517        &mut self,
12518        action: &SelectDownByLines,
12519        window: &mut Window,
12520        cx: &mut Context<Self>,
12521    ) {
12522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12523        let text_layout_details = &self.text_layout_details(window);
12524        self.change_selections(Default::default(), window, cx, |s| {
12525            s.move_heads_with(|map, head, goal| {
12526                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12527            })
12528        })
12529    }
12530
12531    pub fn select_up_by_lines(
12532        &mut self,
12533        action: &SelectUpByLines,
12534        window: &mut Window,
12535        cx: &mut Context<Self>,
12536    ) {
12537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12538        let text_layout_details = &self.text_layout_details(window);
12539        self.change_selections(Default::default(), window, cx, |s| {
12540            s.move_heads_with(|map, head, goal| {
12541                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12542            })
12543        })
12544    }
12545
12546    pub fn select_page_up(
12547        &mut self,
12548        _: &SelectPageUp,
12549        window: &mut Window,
12550        cx: &mut Context<Self>,
12551    ) {
12552        let Some(row_count) = self.visible_row_count() else {
12553            return;
12554        };
12555
12556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12557
12558        let text_layout_details = &self.text_layout_details(window);
12559
12560        self.change_selections(Default::default(), window, cx, |s| {
12561            s.move_heads_with(|map, head, goal| {
12562                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12563            })
12564        })
12565    }
12566
12567    pub fn move_page_up(
12568        &mut self,
12569        action: &MovePageUp,
12570        window: &mut Window,
12571        cx: &mut Context<Self>,
12572    ) {
12573        if self.take_rename(true, window, cx).is_some() {
12574            return;
12575        }
12576
12577        if self
12578            .context_menu
12579            .borrow_mut()
12580            .as_mut()
12581            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12582            .unwrap_or(false)
12583        {
12584            return;
12585        }
12586
12587        if matches!(self.mode, EditorMode::SingleLine) {
12588            cx.propagate();
12589            return;
12590        }
12591
12592        let Some(row_count) = self.visible_row_count() else {
12593            return;
12594        };
12595
12596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12597
12598        let effects = if action.center_cursor {
12599            SelectionEffects::scroll(Autoscroll::center())
12600        } else {
12601            SelectionEffects::default()
12602        };
12603
12604        let text_layout_details = &self.text_layout_details(window);
12605
12606        self.change_selections(effects, window, cx, |s| {
12607            s.move_with(|map, selection| {
12608                if !selection.is_empty() {
12609                    selection.goal = SelectionGoal::None;
12610                }
12611                let (cursor, goal) = movement::up_by_rows(
12612                    map,
12613                    selection.end,
12614                    row_count,
12615                    selection.goal,
12616                    false,
12617                    text_layout_details,
12618                );
12619                selection.collapse_to(cursor, goal);
12620            });
12621        });
12622    }
12623
12624    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12625        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12626        let text_layout_details = &self.text_layout_details(window);
12627        self.change_selections(Default::default(), window, cx, |s| {
12628            s.move_heads_with(|map, head, goal| {
12629                movement::up(map, head, goal, false, text_layout_details)
12630            })
12631        })
12632    }
12633
12634    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12635        self.take_rename(true, window, cx);
12636
12637        if self.mode.is_single_line() {
12638            cx.propagate();
12639            return;
12640        }
12641
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12643
12644        let text_layout_details = &self.text_layout_details(window);
12645        let selection_count = self.selections.count();
12646        let first_selection = self.selections.first_anchor();
12647
12648        self.change_selections(Default::default(), window, cx, |s| {
12649            s.move_with(|map, selection| {
12650                if !selection.is_empty() {
12651                    selection.goal = SelectionGoal::None;
12652                }
12653                let (cursor, goal) = movement::down(
12654                    map,
12655                    selection.end,
12656                    selection.goal,
12657                    false,
12658                    text_layout_details,
12659                );
12660                selection.collapse_to(cursor, goal);
12661            });
12662        });
12663
12664        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12665        {
12666            cx.propagate();
12667        }
12668    }
12669
12670    pub fn select_page_down(
12671        &mut self,
12672        _: &SelectPageDown,
12673        window: &mut Window,
12674        cx: &mut Context<Self>,
12675    ) {
12676        let Some(row_count) = self.visible_row_count() else {
12677            return;
12678        };
12679
12680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12681
12682        let text_layout_details = &self.text_layout_details(window);
12683
12684        self.change_selections(Default::default(), window, cx, |s| {
12685            s.move_heads_with(|map, head, goal| {
12686                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12687            })
12688        })
12689    }
12690
12691    pub fn move_page_down(
12692        &mut self,
12693        action: &MovePageDown,
12694        window: &mut Window,
12695        cx: &mut Context<Self>,
12696    ) {
12697        if self.take_rename(true, window, cx).is_some() {
12698            return;
12699        }
12700
12701        if self
12702            .context_menu
12703            .borrow_mut()
12704            .as_mut()
12705            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12706            .unwrap_or(false)
12707        {
12708            return;
12709        }
12710
12711        if matches!(self.mode, EditorMode::SingleLine) {
12712            cx.propagate();
12713            return;
12714        }
12715
12716        let Some(row_count) = self.visible_row_count() else {
12717            return;
12718        };
12719
12720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12721
12722        let effects = if action.center_cursor {
12723            SelectionEffects::scroll(Autoscroll::center())
12724        } else {
12725            SelectionEffects::default()
12726        };
12727
12728        let text_layout_details = &self.text_layout_details(window);
12729        self.change_selections(effects, window, cx, |s| {
12730            s.move_with(|map, selection| {
12731                if !selection.is_empty() {
12732                    selection.goal = SelectionGoal::None;
12733                }
12734                let (cursor, goal) = movement::down_by_rows(
12735                    map,
12736                    selection.end,
12737                    row_count,
12738                    selection.goal,
12739                    false,
12740                    text_layout_details,
12741                );
12742                selection.collapse_to(cursor, goal);
12743            });
12744        });
12745    }
12746
12747    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12749        let text_layout_details = &self.text_layout_details(window);
12750        self.change_selections(Default::default(), window, cx, |s| {
12751            s.move_heads_with(|map, head, goal| {
12752                movement::down(map, head, goal, false, text_layout_details)
12753            })
12754        });
12755    }
12756
12757    pub fn context_menu_first(
12758        &mut self,
12759        _: &ContextMenuFirst,
12760        window: &mut Window,
12761        cx: &mut Context<Self>,
12762    ) {
12763        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12764            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12765        }
12766    }
12767
12768    pub fn context_menu_prev(
12769        &mut self,
12770        _: &ContextMenuPrevious,
12771        window: &mut Window,
12772        cx: &mut Context<Self>,
12773    ) {
12774        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12775            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12776        }
12777    }
12778
12779    pub fn context_menu_next(
12780        &mut self,
12781        _: &ContextMenuNext,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12786            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12787        }
12788    }
12789
12790    pub fn context_menu_last(
12791        &mut self,
12792        _: &ContextMenuLast,
12793        window: &mut Window,
12794        cx: &mut Context<Self>,
12795    ) {
12796        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12797            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12798        }
12799    }
12800
12801    pub fn signature_help_prev(
12802        &mut self,
12803        _: &SignatureHelpPrevious,
12804        _: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        if let Some(popover) = self.signature_help_state.popover_mut() {
12808            if popover.current_signature == 0 {
12809                popover.current_signature = popover.signatures.len() - 1;
12810            } else {
12811                popover.current_signature -= 1;
12812            }
12813            cx.notify();
12814        }
12815    }
12816
12817    pub fn signature_help_next(
12818        &mut self,
12819        _: &SignatureHelpNext,
12820        _: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) {
12823        if let Some(popover) = self.signature_help_state.popover_mut() {
12824            if popover.current_signature + 1 == popover.signatures.len() {
12825                popover.current_signature = 0;
12826            } else {
12827                popover.current_signature += 1;
12828            }
12829            cx.notify();
12830        }
12831    }
12832
12833    pub fn move_to_previous_word_start(
12834        &mut self,
12835        _: &MoveToPreviousWordStart,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12840        self.change_selections(Default::default(), window, cx, |s| {
12841            s.move_cursors_with(|map, head, _| {
12842                (
12843                    movement::previous_word_start(map, head),
12844                    SelectionGoal::None,
12845                )
12846            });
12847        })
12848    }
12849
12850    pub fn move_to_previous_subword_start(
12851        &mut self,
12852        _: &MoveToPreviousSubwordStart,
12853        window: &mut Window,
12854        cx: &mut Context<Self>,
12855    ) {
12856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12857        self.change_selections(Default::default(), window, cx, |s| {
12858            s.move_cursors_with(|map, head, _| {
12859                (
12860                    movement::previous_subword_start(map, head),
12861                    SelectionGoal::None,
12862                )
12863            });
12864        })
12865    }
12866
12867    pub fn select_to_previous_word_start(
12868        &mut self,
12869        _: &SelectToPreviousWordStart,
12870        window: &mut Window,
12871        cx: &mut Context<Self>,
12872    ) {
12873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12874        self.change_selections(Default::default(), window, cx, |s| {
12875            s.move_heads_with(|map, head, _| {
12876                (
12877                    movement::previous_word_start(map, head),
12878                    SelectionGoal::None,
12879                )
12880            });
12881        })
12882    }
12883
12884    pub fn select_to_previous_subword_start(
12885        &mut self,
12886        _: &SelectToPreviousSubwordStart,
12887        window: &mut Window,
12888        cx: &mut Context<Self>,
12889    ) {
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12891        self.change_selections(Default::default(), window, cx, |s| {
12892            s.move_heads_with(|map, head, _| {
12893                (
12894                    movement::previous_subword_start(map, head),
12895                    SelectionGoal::None,
12896                )
12897            });
12898        })
12899    }
12900
12901    pub fn delete_to_previous_word_start(
12902        &mut self,
12903        action: &DeleteToPreviousWordStart,
12904        window: &mut Window,
12905        cx: &mut Context<Self>,
12906    ) {
12907        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12908        self.transact(window, cx, |this, window, cx| {
12909            this.select_autoclose_pair(window, cx);
12910            this.change_selections(Default::default(), window, cx, |s| {
12911                s.move_with(|map, selection| {
12912                    if selection.is_empty() {
12913                        let cursor = if action.ignore_newlines {
12914                            movement::previous_word_start(map, selection.head())
12915                        } else {
12916                            movement::previous_word_start_or_newline(map, selection.head())
12917                        };
12918                        selection.set_head(cursor, SelectionGoal::None);
12919                    }
12920                });
12921            });
12922            this.insert("", window, cx);
12923        });
12924    }
12925
12926    pub fn delete_to_previous_subword_start(
12927        &mut self,
12928        _: &DeleteToPreviousSubwordStart,
12929        window: &mut Window,
12930        cx: &mut Context<Self>,
12931    ) {
12932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12933        self.transact(window, cx, |this, window, cx| {
12934            this.select_autoclose_pair(window, cx);
12935            this.change_selections(Default::default(), window, cx, |s| {
12936                s.move_with(|map, selection| {
12937                    if selection.is_empty() {
12938                        let cursor = movement::previous_subword_start(map, selection.head());
12939                        selection.set_head(cursor, SelectionGoal::None);
12940                    }
12941                });
12942            });
12943            this.insert("", window, cx);
12944        });
12945    }
12946
12947    pub fn move_to_next_word_end(
12948        &mut self,
12949        _: &MoveToNextWordEnd,
12950        window: &mut Window,
12951        cx: &mut Context<Self>,
12952    ) {
12953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12954        self.change_selections(Default::default(), window, cx, |s| {
12955            s.move_cursors_with(|map, head, _| {
12956                (movement::next_word_end(map, head), SelectionGoal::None)
12957            });
12958        })
12959    }
12960
12961    pub fn move_to_next_subword_end(
12962        &mut self,
12963        _: &MoveToNextSubwordEnd,
12964        window: &mut Window,
12965        cx: &mut Context<Self>,
12966    ) {
12967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12968        self.change_selections(Default::default(), window, cx, |s| {
12969            s.move_cursors_with(|map, head, _| {
12970                (movement::next_subword_end(map, head), SelectionGoal::None)
12971            });
12972        })
12973    }
12974
12975    pub fn select_to_next_word_end(
12976        &mut self,
12977        _: &SelectToNextWordEnd,
12978        window: &mut Window,
12979        cx: &mut Context<Self>,
12980    ) {
12981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_heads_with(|map, head, _| {
12984                (movement::next_word_end(map, head), SelectionGoal::None)
12985            });
12986        })
12987    }
12988
12989    pub fn select_to_next_subword_end(
12990        &mut self,
12991        _: &SelectToNextSubwordEnd,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12996        self.change_selections(Default::default(), window, cx, |s| {
12997            s.move_heads_with(|map, head, _| {
12998                (movement::next_subword_end(map, head), SelectionGoal::None)
12999            });
13000        })
13001    }
13002
13003    pub fn delete_to_next_word_end(
13004        &mut self,
13005        action: &DeleteToNextWordEnd,
13006        window: &mut Window,
13007        cx: &mut Context<Self>,
13008    ) {
13009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13010        self.transact(window, cx, |this, window, cx| {
13011            this.change_selections(Default::default(), window, cx, |s| {
13012                s.move_with(|map, selection| {
13013                    if selection.is_empty() {
13014                        let cursor = if action.ignore_newlines {
13015                            movement::next_word_end(map, selection.head())
13016                        } else {
13017                            movement::next_word_end_or_newline(map, selection.head())
13018                        };
13019                        selection.set_head(cursor, SelectionGoal::None);
13020                    }
13021                });
13022            });
13023            this.insert("", window, cx);
13024        });
13025    }
13026
13027    pub fn delete_to_next_subword_end(
13028        &mut self,
13029        _: &DeleteToNextSubwordEnd,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13034        self.transact(window, cx, |this, window, cx| {
13035            this.change_selections(Default::default(), window, cx, |s| {
13036                s.move_with(|map, selection| {
13037                    if selection.is_empty() {
13038                        let cursor = movement::next_subword_end(map, selection.head());
13039                        selection.set_head(cursor, SelectionGoal::None);
13040                    }
13041                });
13042            });
13043            this.insert("", window, cx);
13044        });
13045    }
13046
13047    pub fn move_to_beginning_of_line(
13048        &mut self,
13049        action: &MoveToBeginningOfLine,
13050        window: &mut Window,
13051        cx: &mut Context<Self>,
13052    ) {
13053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13054        self.change_selections(Default::default(), window, cx, |s| {
13055            s.move_cursors_with(|map, head, _| {
13056                (
13057                    movement::indented_line_beginning(
13058                        map,
13059                        head,
13060                        action.stop_at_soft_wraps,
13061                        action.stop_at_indent,
13062                    ),
13063                    SelectionGoal::None,
13064                )
13065            });
13066        })
13067    }
13068
13069    pub fn select_to_beginning_of_line(
13070        &mut self,
13071        action: &SelectToBeginningOfLine,
13072        window: &mut Window,
13073        cx: &mut Context<Self>,
13074    ) {
13075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13076        self.change_selections(Default::default(), window, cx, |s| {
13077            s.move_heads_with(|map, head, _| {
13078                (
13079                    movement::indented_line_beginning(
13080                        map,
13081                        head,
13082                        action.stop_at_soft_wraps,
13083                        action.stop_at_indent,
13084                    ),
13085                    SelectionGoal::None,
13086                )
13087            });
13088        });
13089    }
13090
13091    pub fn delete_to_beginning_of_line(
13092        &mut self,
13093        action: &DeleteToBeginningOfLine,
13094        window: &mut Window,
13095        cx: &mut Context<Self>,
13096    ) {
13097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13098        self.transact(window, cx, |this, window, cx| {
13099            this.change_selections(Default::default(), window, cx, |s| {
13100                s.move_with(|_, selection| {
13101                    selection.reversed = true;
13102                });
13103            });
13104
13105            this.select_to_beginning_of_line(
13106                &SelectToBeginningOfLine {
13107                    stop_at_soft_wraps: false,
13108                    stop_at_indent: action.stop_at_indent,
13109                },
13110                window,
13111                cx,
13112            );
13113            this.backspace(&Backspace, window, cx);
13114        });
13115    }
13116
13117    pub fn move_to_end_of_line(
13118        &mut self,
13119        action: &MoveToEndOfLine,
13120        window: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13124        self.change_selections(Default::default(), window, cx, |s| {
13125            s.move_cursors_with(|map, head, _| {
13126                (
13127                    movement::line_end(map, head, action.stop_at_soft_wraps),
13128                    SelectionGoal::None,
13129                )
13130            });
13131        })
13132    }
13133
13134    pub fn select_to_end_of_line(
13135        &mut self,
13136        action: &SelectToEndOfLine,
13137        window: &mut Window,
13138        cx: &mut Context<Self>,
13139    ) {
13140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13141        self.change_selections(Default::default(), window, cx, |s| {
13142            s.move_heads_with(|map, head, _| {
13143                (
13144                    movement::line_end(map, head, action.stop_at_soft_wraps),
13145                    SelectionGoal::None,
13146                )
13147            });
13148        })
13149    }
13150
13151    pub fn delete_to_end_of_line(
13152        &mut self,
13153        _: &DeleteToEndOfLine,
13154        window: &mut Window,
13155        cx: &mut Context<Self>,
13156    ) {
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13158        self.transact(window, cx, |this, window, cx| {
13159            this.select_to_end_of_line(
13160                &SelectToEndOfLine {
13161                    stop_at_soft_wraps: false,
13162                },
13163                window,
13164                cx,
13165            );
13166            this.delete(&Delete, window, cx);
13167        });
13168    }
13169
13170    pub fn cut_to_end_of_line(
13171        &mut self,
13172        _: &CutToEndOfLine,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) {
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13177        self.transact(window, cx, |this, window, cx| {
13178            this.select_to_end_of_line(
13179                &SelectToEndOfLine {
13180                    stop_at_soft_wraps: false,
13181                },
13182                window,
13183                cx,
13184            );
13185            this.cut(&Cut, window, cx);
13186        });
13187    }
13188
13189    pub fn move_to_start_of_paragraph(
13190        &mut self,
13191        _: &MoveToStartOfParagraph,
13192        window: &mut Window,
13193        cx: &mut Context<Self>,
13194    ) {
13195        if matches!(self.mode, EditorMode::SingleLine) {
13196            cx.propagate();
13197            return;
13198        }
13199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13200        self.change_selections(Default::default(), window, cx, |s| {
13201            s.move_with(|map, selection| {
13202                selection.collapse_to(
13203                    movement::start_of_paragraph(map, selection.head(), 1),
13204                    SelectionGoal::None,
13205                )
13206            });
13207        })
13208    }
13209
13210    pub fn move_to_end_of_paragraph(
13211        &mut self,
13212        _: &MoveToEndOfParagraph,
13213        window: &mut Window,
13214        cx: &mut Context<Self>,
13215    ) {
13216        if matches!(self.mode, EditorMode::SingleLine) {
13217            cx.propagate();
13218            return;
13219        }
13220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13221        self.change_selections(Default::default(), window, cx, |s| {
13222            s.move_with(|map, selection| {
13223                selection.collapse_to(
13224                    movement::end_of_paragraph(map, selection.head(), 1),
13225                    SelectionGoal::None,
13226                )
13227            });
13228        })
13229    }
13230
13231    pub fn select_to_start_of_paragraph(
13232        &mut self,
13233        _: &SelectToStartOfParagraph,
13234        window: &mut Window,
13235        cx: &mut Context<Self>,
13236    ) {
13237        if matches!(self.mode, EditorMode::SingleLine) {
13238            cx.propagate();
13239            return;
13240        }
13241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13242        self.change_selections(Default::default(), window, cx, |s| {
13243            s.move_heads_with(|map, head, _| {
13244                (
13245                    movement::start_of_paragraph(map, head, 1),
13246                    SelectionGoal::None,
13247                )
13248            });
13249        })
13250    }
13251
13252    pub fn select_to_end_of_paragraph(
13253        &mut self,
13254        _: &SelectToEndOfParagraph,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        if matches!(self.mode, EditorMode::SingleLine) {
13259            cx.propagate();
13260            return;
13261        }
13262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13263        self.change_selections(Default::default(), window, cx, |s| {
13264            s.move_heads_with(|map, head, _| {
13265                (
13266                    movement::end_of_paragraph(map, head, 1),
13267                    SelectionGoal::None,
13268                )
13269            });
13270        })
13271    }
13272
13273    pub fn move_to_start_of_excerpt(
13274        &mut self,
13275        _: &MoveToStartOfExcerpt,
13276        window: &mut Window,
13277        cx: &mut Context<Self>,
13278    ) {
13279        if matches!(self.mode, EditorMode::SingleLine) {
13280            cx.propagate();
13281            return;
13282        }
13283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13284        self.change_selections(Default::default(), window, cx, |s| {
13285            s.move_with(|map, selection| {
13286                selection.collapse_to(
13287                    movement::start_of_excerpt(
13288                        map,
13289                        selection.head(),
13290                        workspace::searchable::Direction::Prev,
13291                    ),
13292                    SelectionGoal::None,
13293                )
13294            });
13295        })
13296    }
13297
13298    pub fn move_to_start_of_next_excerpt(
13299        &mut self,
13300        _: &MoveToStartOfNextExcerpt,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        if matches!(self.mode, EditorMode::SingleLine) {
13305            cx.propagate();
13306            return;
13307        }
13308
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_with(|map, selection| {
13311                selection.collapse_to(
13312                    movement::start_of_excerpt(
13313                        map,
13314                        selection.head(),
13315                        workspace::searchable::Direction::Next,
13316                    ),
13317                    SelectionGoal::None,
13318                )
13319            });
13320        })
13321    }
13322
13323    pub fn move_to_end_of_excerpt(
13324        &mut self,
13325        _: &MoveToEndOfExcerpt,
13326        window: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) {
13329        if matches!(self.mode, EditorMode::SingleLine) {
13330            cx.propagate();
13331            return;
13332        }
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13334        self.change_selections(Default::default(), window, cx, |s| {
13335            s.move_with(|map, selection| {
13336                selection.collapse_to(
13337                    movement::end_of_excerpt(
13338                        map,
13339                        selection.head(),
13340                        workspace::searchable::Direction::Next,
13341                    ),
13342                    SelectionGoal::None,
13343                )
13344            });
13345        })
13346    }
13347
13348    pub fn move_to_end_of_previous_excerpt(
13349        &mut self,
13350        _: &MoveToEndOfPreviousExcerpt,
13351        window: &mut Window,
13352        cx: &mut Context<Self>,
13353    ) {
13354        if matches!(self.mode, EditorMode::SingleLine) {
13355            cx.propagate();
13356            return;
13357        }
13358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13359        self.change_selections(Default::default(), window, cx, |s| {
13360            s.move_with(|map, selection| {
13361                selection.collapse_to(
13362                    movement::end_of_excerpt(
13363                        map,
13364                        selection.head(),
13365                        workspace::searchable::Direction::Prev,
13366                    ),
13367                    SelectionGoal::None,
13368                )
13369            });
13370        })
13371    }
13372
13373    pub fn select_to_start_of_excerpt(
13374        &mut self,
13375        _: &SelectToStartOfExcerpt,
13376        window: &mut Window,
13377        cx: &mut Context<Self>,
13378    ) {
13379        if matches!(self.mode, EditorMode::SingleLine) {
13380            cx.propagate();
13381            return;
13382        }
13383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13384        self.change_selections(Default::default(), window, cx, |s| {
13385            s.move_heads_with(|map, head, _| {
13386                (
13387                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13388                    SelectionGoal::None,
13389                )
13390            });
13391        })
13392    }
13393
13394    pub fn select_to_start_of_next_excerpt(
13395        &mut self,
13396        _: &SelectToStartOfNextExcerpt,
13397        window: &mut Window,
13398        cx: &mut Context<Self>,
13399    ) {
13400        if matches!(self.mode, EditorMode::SingleLine) {
13401            cx.propagate();
13402            return;
13403        }
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.move_heads_with(|map, head, _| {
13407                (
13408                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13409                    SelectionGoal::None,
13410                )
13411            });
13412        })
13413    }
13414
13415    pub fn select_to_end_of_excerpt(
13416        &mut self,
13417        _: &SelectToEndOfExcerpt,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        if matches!(self.mode, EditorMode::SingleLine) {
13422            cx.propagate();
13423            return;
13424        }
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.move_heads_with(|map, head, _| {
13428                (
13429                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13430                    SelectionGoal::None,
13431                )
13432            });
13433        })
13434    }
13435
13436    pub fn select_to_end_of_previous_excerpt(
13437        &mut self,
13438        _: &SelectToEndOfPreviousExcerpt,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        if matches!(self.mode, EditorMode::SingleLine) {
13443            cx.propagate();
13444            return;
13445        }
13446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13447        self.change_selections(Default::default(), window, cx, |s| {
13448            s.move_heads_with(|map, head, _| {
13449                (
13450                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13451                    SelectionGoal::None,
13452                )
13453            });
13454        })
13455    }
13456
13457    pub fn move_to_beginning(
13458        &mut self,
13459        _: &MoveToBeginning,
13460        window: &mut Window,
13461        cx: &mut Context<Self>,
13462    ) {
13463        if matches!(self.mode, EditorMode::SingleLine) {
13464            cx.propagate();
13465            return;
13466        }
13467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13468        self.change_selections(Default::default(), window, cx, |s| {
13469            s.select_ranges(vec![0..0]);
13470        });
13471    }
13472
13473    pub fn select_to_beginning(
13474        &mut self,
13475        _: &SelectToBeginning,
13476        window: &mut Window,
13477        cx: &mut Context<Self>,
13478    ) {
13479        let mut selection = self.selections.last::<Point>(cx);
13480        selection.set_head(Point::zero(), SelectionGoal::None);
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13482        self.change_selections(Default::default(), window, cx, |s| {
13483            s.select(vec![selection]);
13484        });
13485    }
13486
13487    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13488        if matches!(self.mode, EditorMode::SingleLine) {
13489            cx.propagate();
13490            return;
13491        }
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        let cursor = self.buffer.read(cx).read(cx).len();
13494        self.change_selections(Default::default(), window, cx, |s| {
13495            s.select_ranges(vec![cursor..cursor])
13496        });
13497    }
13498
13499    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13500        self.nav_history = nav_history;
13501    }
13502
13503    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13504        self.nav_history.as_ref()
13505    }
13506
13507    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13508        self.push_to_nav_history(
13509            self.selections.newest_anchor().head(),
13510            None,
13511            false,
13512            true,
13513            cx,
13514        );
13515    }
13516
13517    fn push_to_nav_history(
13518        &mut self,
13519        cursor_anchor: Anchor,
13520        new_position: Option<Point>,
13521        is_deactivate: bool,
13522        always: bool,
13523        cx: &mut Context<Self>,
13524    ) {
13525        if let Some(nav_history) = self.nav_history.as_mut() {
13526            let buffer = self.buffer.read(cx).read(cx);
13527            let cursor_position = cursor_anchor.to_point(&buffer);
13528            let scroll_state = self.scroll_manager.anchor();
13529            let scroll_top_row = scroll_state.top_row(&buffer);
13530            drop(buffer);
13531
13532            if let Some(new_position) = new_position {
13533                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13534                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13535                    return;
13536                }
13537            }
13538
13539            nav_history.push(
13540                Some(NavigationData {
13541                    cursor_anchor,
13542                    cursor_position,
13543                    scroll_anchor: scroll_state,
13544                    scroll_top_row,
13545                }),
13546                cx,
13547            );
13548            cx.emit(EditorEvent::PushedToNavHistory {
13549                anchor: cursor_anchor,
13550                is_deactivate,
13551            })
13552        }
13553    }
13554
13555    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13557        let buffer = self.buffer.read(cx).snapshot(cx);
13558        let mut selection = self.selections.first::<usize>(cx);
13559        selection.set_head(buffer.len(), SelectionGoal::None);
13560        self.change_selections(Default::default(), window, cx, |s| {
13561            s.select(vec![selection]);
13562        });
13563    }
13564
13565    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13567        let end = self.buffer.read(cx).read(cx).len();
13568        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13569            s.select_ranges(vec![0..end]);
13570        });
13571    }
13572
13573    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13576        let mut selections = self.selections.all::<Point>(cx);
13577        let max_point = display_map.buffer_snapshot.max_point();
13578        for selection in &mut selections {
13579            let rows = selection.spanned_rows(true, &display_map);
13580            selection.start = Point::new(rows.start.0, 0);
13581            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13582            selection.reversed = false;
13583        }
13584        self.change_selections(Default::default(), window, cx, |s| {
13585            s.select(selections);
13586        });
13587    }
13588
13589    pub fn split_selection_into_lines(
13590        &mut self,
13591        action: &SplitSelectionIntoLines,
13592        window: &mut Window,
13593        cx: &mut Context<Self>,
13594    ) {
13595        let selections = self
13596            .selections
13597            .all::<Point>(cx)
13598            .into_iter()
13599            .map(|selection| selection.start..selection.end)
13600            .collect::<Vec<_>>();
13601        self.unfold_ranges(&selections, true, true, cx);
13602
13603        let mut new_selection_ranges = Vec::new();
13604        {
13605            let buffer = self.buffer.read(cx).read(cx);
13606            for selection in selections {
13607                for row in selection.start.row..selection.end.row {
13608                    let line_start = Point::new(row, 0);
13609                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13610
13611                    if action.keep_selections {
13612                        // Keep the selection range for each line
13613                        let selection_start = if row == selection.start.row {
13614                            selection.start
13615                        } else {
13616                            line_start
13617                        };
13618                        new_selection_ranges.push(selection_start..line_end);
13619                    } else {
13620                        // Collapse to cursor at end of line
13621                        new_selection_ranges.push(line_end..line_end);
13622                    }
13623                }
13624
13625                let is_multiline_selection = selection.start.row != selection.end.row;
13626                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13627                // so this action feels more ergonomic when paired with other selection operations
13628                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13629                if !should_skip_last {
13630                    if action.keep_selections {
13631                        if is_multiline_selection {
13632                            let line_start = Point::new(selection.end.row, 0);
13633                            new_selection_ranges.push(line_start..selection.end);
13634                        } else {
13635                            new_selection_ranges.push(selection.start..selection.end);
13636                        }
13637                    } else {
13638                        new_selection_ranges.push(selection.end..selection.end);
13639                    }
13640                }
13641            }
13642        }
13643        self.change_selections(Default::default(), window, cx, |s| {
13644            s.select_ranges(new_selection_ranges);
13645        });
13646    }
13647
13648    pub fn add_selection_above(
13649        &mut self,
13650        _: &AddSelectionAbove,
13651        window: &mut Window,
13652        cx: &mut Context<Self>,
13653    ) {
13654        self.add_selection(true, window, cx);
13655    }
13656
13657    pub fn add_selection_below(
13658        &mut self,
13659        _: &AddSelectionBelow,
13660        window: &mut Window,
13661        cx: &mut Context<Self>,
13662    ) {
13663        self.add_selection(false, window, cx);
13664    }
13665
13666    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13668
13669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13670        let all_selections = self.selections.all::<Point>(cx);
13671        let text_layout_details = self.text_layout_details(window);
13672
13673        let (mut columnar_selections, new_selections_to_columnarize) = {
13674            if let Some(state) = self.add_selections_state.as_ref() {
13675                let columnar_selection_ids: HashSet<_> = state
13676                    .groups
13677                    .iter()
13678                    .flat_map(|group| group.stack.iter())
13679                    .copied()
13680                    .collect();
13681
13682                all_selections
13683                    .into_iter()
13684                    .partition(|s| columnar_selection_ids.contains(&s.id))
13685            } else {
13686                (Vec::new(), all_selections)
13687            }
13688        };
13689
13690        let mut state = self
13691            .add_selections_state
13692            .take()
13693            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13694
13695        for selection in new_selections_to_columnarize {
13696            let range = selection.display_range(&display_map).sorted();
13697            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13698            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13699            let positions = start_x.min(end_x)..start_x.max(end_x);
13700            let mut stack = Vec::new();
13701            for row in range.start.row().0..=range.end.row().0 {
13702                if let Some(selection) = self.selections.build_columnar_selection(
13703                    &display_map,
13704                    DisplayRow(row),
13705                    &positions,
13706                    selection.reversed,
13707                    &text_layout_details,
13708                ) {
13709                    stack.push(selection.id);
13710                    columnar_selections.push(selection);
13711                }
13712            }
13713            if !stack.is_empty() {
13714                if above {
13715                    stack.reverse();
13716                }
13717                state.groups.push(AddSelectionsGroup { above, stack });
13718            }
13719        }
13720
13721        let mut final_selections = Vec::new();
13722        let end_row = if above {
13723            DisplayRow(0)
13724        } else {
13725            display_map.max_point().row()
13726        };
13727
13728        let mut last_added_item_per_group = HashMap::default();
13729        for group in state.groups.iter_mut() {
13730            if let Some(last_id) = group.stack.last() {
13731                last_added_item_per_group.insert(*last_id, group);
13732            }
13733        }
13734
13735        for selection in columnar_selections {
13736            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13737                if above == group.above {
13738                    let range = selection.display_range(&display_map).sorted();
13739                    debug_assert_eq!(range.start.row(), range.end.row());
13740                    let mut row = range.start.row();
13741                    let positions =
13742                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13743                            px(start)..px(end)
13744                        } else {
13745                            let start_x =
13746                                display_map.x_for_display_point(range.start, &text_layout_details);
13747                            let end_x =
13748                                display_map.x_for_display_point(range.end, &text_layout_details);
13749                            start_x.min(end_x)..start_x.max(end_x)
13750                        };
13751
13752                    let mut maybe_new_selection = None;
13753                    while row != end_row {
13754                        if above {
13755                            row.0 -= 1;
13756                        } else {
13757                            row.0 += 1;
13758                        }
13759                        if let Some(new_selection) = self.selections.build_columnar_selection(
13760                            &display_map,
13761                            row,
13762                            &positions,
13763                            selection.reversed,
13764                            &text_layout_details,
13765                        ) {
13766                            maybe_new_selection = Some(new_selection);
13767                            break;
13768                        }
13769                    }
13770
13771                    if let Some(new_selection) = maybe_new_selection {
13772                        group.stack.push(new_selection.id);
13773                        if above {
13774                            final_selections.push(new_selection);
13775                            final_selections.push(selection);
13776                        } else {
13777                            final_selections.push(selection);
13778                            final_selections.push(new_selection);
13779                        }
13780                    } else {
13781                        final_selections.push(selection);
13782                    }
13783                } else {
13784                    group.stack.pop();
13785                }
13786            } else {
13787                final_selections.push(selection);
13788            }
13789        }
13790
13791        self.change_selections(Default::default(), window, cx, |s| {
13792            s.select(final_selections);
13793        });
13794
13795        let final_selection_ids: HashSet<_> = self
13796            .selections
13797            .all::<Point>(cx)
13798            .iter()
13799            .map(|s| s.id)
13800            .collect();
13801        state.groups.retain_mut(|group| {
13802            // selections might get merged above so we remove invalid items from stacks
13803            group.stack.retain(|id| final_selection_ids.contains(id));
13804
13805            // single selection in stack can be treated as initial state
13806            group.stack.len() > 1
13807        });
13808
13809        if !state.groups.is_empty() {
13810            self.add_selections_state = Some(state);
13811        }
13812    }
13813
13814    fn select_match_ranges(
13815        &mut self,
13816        range: Range<usize>,
13817        reversed: bool,
13818        replace_newest: bool,
13819        auto_scroll: Option<Autoscroll>,
13820        window: &mut Window,
13821        cx: &mut Context<Editor>,
13822    ) {
13823        self.unfold_ranges(
13824            std::slice::from_ref(&range),
13825            false,
13826            auto_scroll.is_some(),
13827            cx,
13828        );
13829        let effects = if let Some(scroll) = auto_scroll {
13830            SelectionEffects::scroll(scroll)
13831        } else {
13832            SelectionEffects::no_scroll()
13833        };
13834        self.change_selections(effects, window, cx, |s| {
13835            if replace_newest {
13836                s.delete(s.newest_anchor().id);
13837            }
13838            if reversed {
13839                s.insert_range(range.end..range.start);
13840            } else {
13841                s.insert_range(range);
13842            }
13843        });
13844    }
13845
13846    pub fn select_next_match_internal(
13847        &mut self,
13848        display_map: &DisplaySnapshot,
13849        replace_newest: bool,
13850        autoscroll: Option<Autoscroll>,
13851        window: &mut Window,
13852        cx: &mut Context<Self>,
13853    ) -> Result<()> {
13854        let buffer = &display_map.buffer_snapshot;
13855        let mut selections = self.selections.all::<usize>(cx);
13856        if let Some(mut select_next_state) = self.select_next_state.take() {
13857            let query = &select_next_state.query;
13858            if !select_next_state.done {
13859                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13860                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13861                let mut next_selected_range = None;
13862
13863                let bytes_after_last_selection =
13864                    buffer.bytes_in_range(last_selection.end..buffer.len());
13865                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13866                let query_matches = query
13867                    .stream_find_iter(bytes_after_last_selection)
13868                    .map(|result| (last_selection.end, result))
13869                    .chain(
13870                        query
13871                            .stream_find_iter(bytes_before_first_selection)
13872                            .map(|result| (0, result)),
13873                    );
13874
13875                for (start_offset, query_match) in query_matches {
13876                    let query_match = query_match.unwrap(); // can only fail due to I/O
13877                    let offset_range =
13878                        start_offset + query_match.start()..start_offset + query_match.end();
13879
13880                    if !select_next_state.wordwise
13881                        || (!buffer.is_inside_word(offset_range.start, false)
13882                            && !buffer.is_inside_word(offset_range.end, false))
13883                    {
13884                        // TODO: This is n^2, because we might check all the selections
13885                        if !selections
13886                            .iter()
13887                            .any(|selection| selection.range().overlaps(&offset_range))
13888                        {
13889                            next_selected_range = Some(offset_range);
13890                            break;
13891                        }
13892                    }
13893                }
13894
13895                if let Some(next_selected_range) = next_selected_range {
13896                    self.select_match_ranges(
13897                        next_selected_range,
13898                        last_selection.reversed,
13899                        replace_newest,
13900                        autoscroll,
13901                        window,
13902                        cx,
13903                    );
13904                } else {
13905                    select_next_state.done = true;
13906                }
13907            }
13908
13909            self.select_next_state = Some(select_next_state);
13910        } else {
13911            let mut only_carets = true;
13912            let mut same_text_selected = true;
13913            let mut selected_text = None;
13914
13915            let mut selections_iter = selections.iter().peekable();
13916            while let Some(selection) = selections_iter.next() {
13917                if selection.start != selection.end {
13918                    only_carets = false;
13919                }
13920
13921                if same_text_selected {
13922                    if selected_text.is_none() {
13923                        selected_text =
13924                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13925                    }
13926
13927                    if let Some(next_selection) = selections_iter.peek() {
13928                        if next_selection.range().len() == selection.range().len() {
13929                            let next_selected_text = buffer
13930                                .text_for_range(next_selection.range())
13931                                .collect::<String>();
13932                            if Some(next_selected_text) != selected_text {
13933                                same_text_selected = false;
13934                                selected_text = None;
13935                            }
13936                        } else {
13937                            same_text_selected = false;
13938                            selected_text = None;
13939                        }
13940                    }
13941                }
13942            }
13943
13944            if only_carets {
13945                for selection in &mut selections {
13946                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13947                    selection.start = word_range.start;
13948                    selection.end = word_range.end;
13949                    selection.goal = SelectionGoal::None;
13950                    selection.reversed = false;
13951                    self.select_match_ranges(
13952                        selection.start..selection.end,
13953                        selection.reversed,
13954                        replace_newest,
13955                        autoscroll,
13956                        window,
13957                        cx,
13958                    );
13959                }
13960
13961                if selections.len() == 1 {
13962                    let selection = selections
13963                        .last()
13964                        .expect("ensured that there's only one selection");
13965                    let query = buffer
13966                        .text_for_range(selection.start..selection.end)
13967                        .collect::<String>();
13968                    let is_empty = query.is_empty();
13969                    let select_state = SelectNextState {
13970                        query: AhoCorasick::new(&[query])?,
13971                        wordwise: true,
13972                        done: is_empty,
13973                    };
13974                    self.select_next_state = Some(select_state);
13975                } else {
13976                    self.select_next_state = None;
13977                }
13978            } else if let Some(selected_text) = selected_text {
13979                self.select_next_state = Some(SelectNextState {
13980                    query: AhoCorasick::new(&[selected_text])?,
13981                    wordwise: false,
13982                    done: false,
13983                });
13984                self.select_next_match_internal(
13985                    display_map,
13986                    replace_newest,
13987                    autoscroll,
13988                    window,
13989                    cx,
13990                )?;
13991            }
13992        }
13993        Ok(())
13994    }
13995
13996    pub fn select_all_matches(
13997        &mut self,
13998        _action: &SelectAllMatches,
13999        window: &mut Window,
14000        cx: &mut Context<Self>,
14001    ) -> Result<()> {
14002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14003
14004        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14005
14006        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14007        let Some(select_next_state) = self.select_next_state.as_mut() else {
14008            return Ok(());
14009        };
14010        if select_next_state.done {
14011            return Ok(());
14012        }
14013
14014        let mut new_selections = Vec::new();
14015
14016        let reversed = self.selections.oldest::<usize>(cx).reversed;
14017        let buffer = &display_map.buffer_snapshot;
14018        let query_matches = select_next_state
14019            .query
14020            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14021
14022        for query_match in query_matches.into_iter() {
14023            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14024            let offset_range = if reversed {
14025                query_match.end()..query_match.start()
14026            } else {
14027                query_match.start()..query_match.end()
14028            };
14029
14030            if !select_next_state.wordwise
14031                || (!buffer.is_inside_word(offset_range.start, false)
14032                    && !buffer.is_inside_word(offset_range.end, false))
14033            {
14034                new_selections.push(offset_range.start..offset_range.end);
14035            }
14036        }
14037
14038        select_next_state.done = true;
14039
14040        if new_selections.is_empty() {
14041            log::error!("bug: new_selections is empty in select_all_matches");
14042            return Ok(());
14043        }
14044
14045        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14046        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14047            selections.select_ranges(new_selections)
14048        });
14049
14050        Ok(())
14051    }
14052
14053    pub fn select_next(
14054        &mut self,
14055        action: &SelectNext,
14056        window: &mut Window,
14057        cx: &mut Context<Self>,
14058    ) -> Result<()> {
14059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14060        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14061        self.select_next_match_internal(
14062            &display_map,
14063            action.replace_newest,
14064            Some(Autoscroll::newest()),
14065            window,
14066            cx,
14067        )?;
14068        Ok(())
14069    }
14070
14071    pub fn select_previous(
14072        &mut self,
14073        action: &SelectPrevious,
14074        window: &mut Window,
14075        cx: &mut Context<Self>,
14076    ) -> Result<()> {
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14079        let buffer = &display_map.buffer_snapshot;
14080        let mut selections = self.selections.all::<usize>(cx);
14081        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14082            let query = &select_prev_state.query;
14083            if !select_prev_state.done {
14084                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14085                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14086                let mut next_selected_range = None;
14087                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14088                let bytes_before_last_selection =
14089                    buffer.reversed_bytes_in_range(0..last_selection.start);
14090                let bytes_after_first_selection =
14091                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14092                let query_matches = query
14093                    .stream_find_iter(bytes_before_last_selection)
14094                    .map(|result| (last_selection.start, result))
14095                    .chain(
14096                        query
14097                            .stream_find_iter(bytes_after_first_selection)
14098                            .map(|result| (buffer.len(), result)),
14099                    );
14100                for (end_offset, query_match) in query_matches {
14101                    let query_match = query_match.unwrap(); // can only fail due to I/O
14102                    let offset_range =
14103                        end_offset - query_match.end()..end_offset - query_match.start();
14104
14105                    if !select_prev_state.wordwise
14106                        || (!buffer.is_inside_word(offset_range.start, false)
14107                            && !buffer.is_inside_word(offset_range.end, false))
14108                    {
14109                        next_selected_range = Some(offset_range);
14110                        break;
14111                    }
14112                }
14113
14114                if let Some(next_selected_range) = next_selected_range {
14115                    self.select_match_ranges(
14116                        next_selected_range,
14117                        last_selection.reversed,
14118                        action.replace_newest,
14119                        Some(Autoscroll::newest()),
14120                        window,
14121                        cx,
14122                    );
14123                } else {
14124                    select_prev_state.done = true;
14125                }
14126            }
14127
14128            self.select_prev_state = Some(select_prev_state);
14129        } else {
14130            let mut only_carets = true;
14131            let mut same_text_selected = true;
14132            let mut selected_text = None;
14133
14134            let mut selections_iter = selections.iter().peekable();
14135            while let Some(selection) = selections_iter.next() {
14136                if selection.start != selection.end {
14137                    only_carets = false;
14138                }
14139
14140                if same_text_selected {
14141                    if selected_text.is_none() {
14142                        selected_text =
14143                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14144                    }
14145
14146                    if let Some(next_selection) = selections_iter.peek() {
14147                        if next_selection.range().len() == selection.range().len() {
14148                            let next_selected_text = buffer
14149                                .text_for_range(next_selection.range())
14150                                .collect::<String>();
14151                            if Some(next_selected_text) != selected_text {
14152                                same_text_selected = false;
14153                                selected_text = None;
14154                            }
14155                        } else {
14156                            same_text_selected = false;
14157                            selected_text = None;
14158                        }
14159                    }
14160                }
14161            }
14162
14163            if only_carets {
14164                for selection in &mut selections {
14165                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14166                    selection.start = word_range.start;
14167                    selection.end = word_range.end;
14168                    selection.goal = SelectionGoal::None;
14169                    selection.reversed = false;
14170                    self.select_match_ranges(
14171                        selection.start..selection.end,
14172                        selection.reversed,
14173                        action.replace_newest,
14174                        Some(Autoscroll::newest()),
14175                        window,
14176                        cx,
14177                    );
14178                }
14179                if selections.len() == 1 {
14180                    let selection = selections
14181                        .last()
14182                        .expect("ensured that there's only one selection");
14183                    let query = buffer
14184                        .text_for_range(selection.start..selection.end)
14185                        .collect::<String>();
14186                    let is_empty = query.is_empty();
14187                    let select_state = SelectNextState {
14188                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14189                        wordwise: true,
14190                        done: is_empty,
14191                    };
14192                    self.select_prev_state = Some(select_state);
14193                } else {
14194                    self.select_prev_state = None;
14195                }
14196            } else if let Some(selected_text) = selected_text {
14197                self.select_prev_state = Some(SelectNextState {
14198                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14199                    wordwise: false,
14200                    done: false,
14201                });
14202                self.select_previous(action, window, cx)?;
14203            }
14204        }
14205        Ok(())
14206    }
14207
14208    pub fn find_next_match(
14209        &mut self,
14210        _: &FindNextMatch,
14211        window: &mut Window,
14212        cx: &mut Context<Self>,
14213    ) -> Result<()> {
14214        let selections = self.selections.disjoint_anchors();
14215        match selections.first() {
14216            Some(first) if selections.len() >= 2 => {
14217                self.change_selections(Default::default(), window, cx, |s| {
14218                    s.select_ranges([first.range()]);
14219                });
14220            }
14221            _ => self.select_next(
14222                &SelectNext {
14223                    replace_newest: true,
14224                },
14225                window,
14226                cx,
14227            )?,
14228        }
14229        Ok(())
14230    }
14231
14232    pub fn find_previous_match(
14233        &mut self,
14234        _: &FindPreviousMatch,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) -> Result<()> {
14238        let selections = self.selections.disjoint_anchors();
14239        match selections.last() {
14240            Some(last) if selections.len() >= 2 => {
14241                self.change_selections(Default::default(), window, cx, |s| {
14242                    s.select_ranges([last.range()]);
14243                });
14244            }
14245            _ => self.select_previous(
14246                &SelectPrevious {
14247                    replace_newest: true,
14248                },
14249                window,
14250                cx,
14251            )?,
14252        }
14253        Ok(())
14254    }
14255
14256    pub fn toggle_comments(
14257        &mut self,
14258        action: &ToggleComments,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) {
14262        if self.read_only(cx) {
14263            return;
14264        }
14265        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14266        let text_layout_details = &self.text_layout_details(window);
14267        self.transact(window, cx, |this, window, cx| {
14268            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14269            let mut edits = Vec::new();
14270            let mut selection_edit_ranges = Vec::new();
14271            let mut last_toggled_row = None;
14272            let snapshot = this.buffer.read(cx).read(cx);
14273            let empty_str: Arc<str> = Arc::default();
14274            let mut suffixes_inserted = Vec::new();
14275            let ignore_indent = action.ignore_indent;
14276
14277            fn comment_prefix_range(
14278                snapshot: &MultiBufferSnapshot,
14279                row: MultiBufferRow,
14280                comment_prefix: &str,
14281                comment_prefix_whitespace: &str,
14282                ignore_indent: bool,
14283            ) -> Range<Point> {
14284                let indent_size = if ignore_indent {
14285                    0
14286                } else {
14287                    snapshot.indent_size_for_line(row).len
14288                };
14289
14290                let start = Point::new(row.0, indent_size);
14291
14292                let mut line_bytes = snapshot
14293                    .bytes_in_range(start..snapshot.max_point())
14294                    .flatten()
14295                    .copied();
14296
14297                // If this line currently begins with the line comment prefix, then record
14298                // the range containing the prefix.
14299                if line_bytes
14300                    .by_ref()
14301                    .take(comment_prefix.len())
14302                    .eq(comment_prefix.bytes())
14303                {
14304                    // Include any whitespace that matches the comment prefix.
14305                    let matching_whitespace_len = line_bytes
14306                        .zip(comment_prefix_whitespace.bytes())
14307                        .take_while(|(a, b)| a == b)
14308                        .count() as u32;
14309                    let end = Point::new(
14310                        start.row,
14311                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14312                    );
14313                    start..end
14314                } else {
14315                    start..start
14316                }
14317            }
14318
14319            fn comment_suffix_range(
14320                snapshot: &MultiBufferSnapshot,
14321                row: MultiBufferRow,
14322                comment_suffix: &str,
14323                comment_suffix_has_leading_space: bool,
14324            ) -> Range<Point> {
14325                let end = Point::new(row.0, snapshot.line_len(row));
14326                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14327
14328                let mut line_end_bytes = snapshot
14329                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14330                    .flatten()
14331                    .copied();
14332
14333                let leading_space_len = if suffix_start_column > 0
14334                    && line_end_bytes.next() == Some(b' ')
14335                    && comment_suffix_has_leading_space
14336                {
14337                    1
14338                } else {
14339                    0
14340                };
14341
14342                // If this line currently begins with the line comment prefix, then record
14343                // the range containing the prefix.
14344                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14345                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14346                    start..end
14347                } else {
14348                    end..end
14349                }
14350            }
14351
14352            // TODO: Handle selections that cross excerpts
14353            for selection in &mut selections {
14354                let start_column = snapshot
14355                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14356                    .len;
14357                let language = if let Some(language) =
14358                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14359                {
14360                    language
14361                } else {
14362                    continue;
14363                };
14364
14365                selection_edit_ranges.clear();
14366
14367                // If multiple selections contain a given row, avoid processing that
14368                // row more than once.
14369                let mut start_row = MultiBufferRow(selection.start.row);
14370                if last_toggled_row == Some(start_row) {
14371                    start_row = start_row.next_row();
14372                }
14373                let end_row =
14374                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14375                        MultiBufferRow(selection.end.row - 1)
14376                    } else {
14377                        MultiBufferRow(selection.end.row)
14378                    };
14379                last_toggled_row = Some(end_row);
14380
14381                if start_row > end_row {
14382                    continue;
14383                }
14384
14385                // If the language has line comments, toggle those.
14386                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14387
14388                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14389                if ignore_indent {
14390                    full_comment_prefixes = full_comment_prefixes
14391                        .into_iter()
14392                        .map(|s| Arc::from(s.trim_end()))
14393                        .collect();
14394                }
14395
14396                if !full_comment_prefixes.is_empty() {
14397                    let first_prefix = full_comment_prefixes
14398                        .first()
14399                        .expect("prefixes is non-empty");
14400                    let prefix_trimmed_lengths = full_comment_prefixes
14401                        .iter()
14402                        .map(|p| p.trim_end_matches(' ').len())
14403                        .collect::<SmallVec<[usize; 4]>>();
14404
14405                    let mut all_selection_lines_are_comments = true;
14406
14407                    for row in start_row.0..=end_row.0 {
14408                        let row = MultiBufferRow(row);
14409                        if start_row < end_row && snapshot.is_line_blank(row) {
14410                            continue;
14411                        }
14412
14413                        let prefix_range = full_comment_prefixes
14414                            .iter()
14415                            .zip(prefix_trimmed_lengths.iter().copied())
14416                            .map(|(prefix, trimmed_prefix_len)| {
14417                                comment_prefix_range(
14418                                    snapshot.deref(),
14419                                    row,
14420                                    &prefix[..trimmed_prefix_len],
14421                                    &prefix[trimmed_prefix_len..],
14422                                    ignore_indent,
14423                                )
14424                            })
14425                            .max_by_key(|range| range.end.column - range.start.column)
14426                            .expect("prefixes is non-empty");
14427
14428                        if prefix_range.is_empty() {
14429                            all_selection_lines_are_comments = false;
14430                        }
14431
14432                        selection_edit_ranges.push(prefix_range);
14433                    }
14434
14435                    if all_selection_lines_are_comments {
14436                        edits.extend(
14437                            selection_edit_ranges
14438                                .iter()
14439                                .cloned()
14440                                .map(|range| (range, empty_str.clone())),
14441                        );
14442                    } else {
14443                        let min_column = selection_edit_ranges
14444                            .iter()
14445                            .map(|range| range.start.column)
14446                            .min()
14447                            .unwrap_or(0);
14448                        edits.extend(selection_edit_ranges.iter().map(|range| {
14449                            let position = Point::new(range.start.row, min_column);
14450                            (position..position, first_prefix.clone())
14451                        }));
14452                    }
14453                } else if let Some(BlockCommentConfig {
14454                    start: full_comment_prefix,
14455                    end: comment_suffix,
14456                    ..
14457                }) = language.block_comment()
14458                {
14459                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14460                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14461                    let prefix_range = comment_prefix_range(
14462                        snapshot.deref(),
14463                        start_row,
14464                        comment_prefix,
14465                        comment_prefix_whitespace,
14466                        ignore_indent,
14467                    );
14468                    let suffix_range = comment_suffix_range(
14469                        snapshot.deref(),
14470                        end_row,
14471                        comment_suffix.trim_start_matches(' '),
14472                        comment_suffix.starts_with(' '),
14473                    );
14474
14475                    if prefix_range.is_empty() || suffix_range.is_empty() {
14476                        edits.push((
14477                            prefix_range.start..prefix_range.start,
14478                            full_comment_prefix.clone(),
14479                        ));
14480                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14481                        suffixes_inserted.push((end_row, comment_suffix.len()));
14482                    } else {
14483                        edits.push((prefix_range, empty_str.clone()));
14484                        edits.push((suffix_range, empty_str.clone()));
14485                    }
14486                } else {
14487                    continue;
14488                }
14489            }
14490
14491            drop(snapshot);
14492            this.buffer.update(cx, |buffer, cx| {
14493                buffer.edit(edits, None, cx);
14494            });
14495
14496            // Adjust selections so that they end before any comment suffixes that
14497            // were inserted.
14498            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14499            let mut selections = this.selections.all::<Point>(cx);
14500            let snapshot = this.buffer.read(cx).read(cx);
14501            for selection in &mut selections {
14502                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14503                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14504                        Ordering::Less => {
14505                            suffixes_inserted.next();
14506                            continue;
14507                        }
14508                        Ordering::Greater => break,
14509                        Ordering::Equal => {
14510                            if selection.end.column == snapshot.line_len(row) {
14511                                if selection.is_empty() {
14512                                    selection.start.column -= suffix_len as u32;
14513                                }
14514                                selection.end.column -= suffix_len as u32;
14515                            }
14516                            break;
14517                        }
14518                    }
14519                }
14520            }
14521
14522            drop(snapshot);
14523            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14524
14525            let selections = this.selections.all::<Point>(cx);
14526            let selections_on_single_row = selections.windows(2).all(|selections| {
14527                selections[0].start.row == selections[1].start.row
14528                    && selections[0].end.row == selections[1].end.row
14529                    && selections[0].start.row == selections[0].end.row
14530            });
14531            let selections_selecting = selections
14532                .iter()
14533                .any(|selection| selection.start != selection.end);
14534            let advance_downwards = action.advance_downwards
14535                && selections_on_single_row
14536                && !selections_selecting
14537                && !matches!(this.mode, EditorMode::SingleLine);
14538
14539            if advance_downwards {
14540                let snapshot = this.buffer.read(cx).snapshot(cx);
14541
14542                this.change_selections(Default::default(), window, cx, |s| {
14543                    s.move_cursors_with(|display_snapshot, display_point, _| {
14544                        let mut point = display_point.to_point(display_snapshot);
14545                        point.row += 1;
14546                        point = snapshot.clip_point(point, Bias::Left);
14547                        let display_point = point.to_display_point(display_snapshot);
14548                        let goal = SelectionGoal::HorizontalPosition(
14549                            display_snapshot
14550                                .x_for_display_point(display_point, text_layout_details)
14551                                .into(),
14552                        );
14553                        (display_point, goal)
14554                    })
14555                });
14556            }
14557        });
14558    }
14559
14560    pub fn select_enclosing_symbol(
14561        &mut self,
14562        _: &SelectEnclosingSymbol,
14563        window: &mut Window,
14564        cx: &mut Context<Self>,
14565    ) {
14566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14567
14568        let buffer = self.buffer.read(cx).snapshot(cx);
14569        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14570
14571        fn update_selection(
14572            selection: &Selection<usize>,
14573            buffer_snap: &MultiBufferSnapshot,
14574        ) -> Option<Selection<usize>> {
14575            let cursor = selection.head();
14576            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14577            for symbol in symbols.iter().rev() {
14578                let start = symbol.range.start.to_offset(buffer_snap);
14579                let end = symbol.range.end.to_offset(buffer_snap);
14580                let new_range = start..end;
14581                if start < selection.start || end > selection.end {
14582                    return Some(Selection {
14583                        id: selection.id,
14584                        start: new_range.start,
14585                        end: new_range.end,
14586                        goal: SelectionGoal::None,
14587                        reversed: selection.reversed,
14588                    });
14589                }
14590            }
14591            None
14592        }
14593
14594        let mut selected_larger_symbol = false;
14595        let new_selections = old_selections
14596            .iter()
14597            .map(|selection| match update_selection(selection, &buffer) {
14598                Some(new_selection) => {
14599                    if new_selection.range() != selection.range() {
14600                        selected_larger_symbol = true;
14601                    }
14602                    new_selection
14603                }
14604                None => selection.clone(),
14605            })
14606            .collect::<Vec<_>>();
14607
14608        if selected_larger_symbol {
14609            self.change_selections(Default::default(), window, cx, |s| {
14610                s.select(new_selections);
14611            });
14612        }
14613    }
14614
14615    pub fn select_larger_syntax_node(
14616        &mut self,
14617        _: &SelectLargerSyntaxNode,
14618        window: &mut Window,
14619        cx: &mut Context<Self>,
14620    ) {
14621        let Some(visible_row_count) = self.visible_row_count() else {
14622            return;
14623        };
14624        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14625        if old_selections.is_empty() {
14626            return;
14627        }
14628
14629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14630
14631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14632        let buffer = self.buffer.read(cx).snapshot(cx);
14633
14634        let mut selected_larger_node = false;
14635        let mut new_selections = old_selections
14636            .iter()
14637            .map(|selection| {
14638                let old_range = selection.start..selection.end;
14639
14640                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14641                    // manually select word at selection
14642                    if ["string_content", "inline"].contains(&node.kind()) {
14643                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14644                        // ignore if word is already selected
14645                        if !word_range.is_empty() && old_range != word_range {
14646                            let (last_word_range, _) =
14647                                buffer.surrounding_word(old_range.end, false);
14648                            // only select word if start and end point belongs to same word
14649                            if word_range == last_word_range {
14650                                selected_larger_node = true;
14651                                return Selection {
14652                                    id: selection.id,
14653                                    start: word_range.start,
14654                                    end: word_range.end,
14655                                    goal: SelectionGoal::None,
14656                                    reversed: selection.reversed,
14657                                };
14658                            }
14659                        }
14660                    }
14661                }
14662
14663                let mut new_range = old_range.clone();
14664                while let Some((_node, containing_range)) =
14665                    buffer.syntax_ancestor(new_range.clone())
14666                {
14667                    new_range = match containing_range {
14668                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14669                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14670                    };
14671                    if !display_map.intersects_fold(new_range.start)
14672                        && !display_map.intersects_fold(new_range.end)
14673                    {
14674                        break;
14675                    }
14676                }
14677
14678                selected_larger_node |= new_range != old_range;
14679                Selection {
14680                    id: selection.id,
14681                    start: new_range.start,
14682                    end: new_range.end,
14683                    goal: SelectionGoal::None,
14684                    reversed: selection.reversed,
14685                }
14686            })
14687            .collect::<Vec<_>>();
14688
14689        if !selected_larger_node {
14690            return; // don't put this call in the history
14691        }
14692
14693        // scroll based on transformation done to the last selection created by the user
14694        let (last_old, last_new) = old_selections
14695            .last()
14696            .zip(new_selections.last().cloned())
14697            .expect("old_selections isn't empty");
14698
14699        // revert selection
14700        let is_selection_reversed = {
14701            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14702            new_selections.last_mut().expect("checked above").reversed =
14703                should_newest_selection_be_reversed;
14704            should_newest_selection_be_reversed
14705        };
14706
14707        if selected_larger_node {
14708            self.select_syntax_node_history.disable_clearing = true;
14709            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14710                s.select(new_selections.clone());
14711            });
14712            self.select_syntax_node_history.disable_clearing = false;
14713        }
14714
14715        let start_row = last_new.start.to_display_point(&display_map).row().0;
14716        let end_row = last_new.end.to_display_point(&display_map).row().0;
14717        let selection_height = end_row - start_row + 1;
14718        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14719
14720        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14721        let scroll_behavior = if fits_on_the_screen {
14722            self.request_autoscroll(Autoscroll::fit(), cx);
14723            SelectSyntaxNodeScrollBehavior::FitSelection
14724        } else if is_selection_reversed {
14725            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14726            SelectSyntaxNodeScrollBehavior::CursorTop
14727        } else {
14728            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14729            SelectSyntaxNodeScrollBehavior::CursorBottom
14730        };
14731
14732        self.select_syntax_node_history.push((
14733            old_selections,
14734            scroll_behavior,
14735            is_selection_reversed,
14736        ));
14737    }
14738
14739    pub fn select_smaller_syntax_node(
14740        &mut self,
14741        _: &SelectSmallerSyntaxNode,
14742        window: &mut Window,
14743        cx: &mut Context<Self>,
14744    ) {
14745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14746
14747        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14748            self.select_syntax_node_history.pop()
14749        {
14750            if let Some(selection) = selections.last_mut() {
14751                selection.reversed = is_selection_reversed;
14752            }
14753
14754            self.select_syntax_node_history.disable_clearing = true;
14755            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14756                s.select(selections.to_vec());
14757            });
14758            self.select_syntax_node_history.disable_clearing = false;
14759
14760            match scroll_behavior {
14761                SelectSyntaxNodeScrollBehavior::CursorTop => {
14762                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14763                }
14764                SelectSyntaxNodeScrollBehavior::FitSelection => {
14765                    self.request_autoscroll(Autoscroll::fit(), cx);
14766                }
14767                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14768                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14769                }
14770            }
14771        }
14772    }
14773
14774    pub fn unwrap_syntax_node(
14775        &mut self,
14776        _: &UnwrapSyntaxNode,
14777        window: &mut Window,
14778        cx: &mut Context<Self>,
14779    ) {
14780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14781
14782        let buffer = self.buffer.read(cx).snapshot(cx);
14783        let selections = self
14784            .selections
14785            .all::<usize>(cx)
14786            .into_iter()
14787            // subtracting the offset requires sorting
14788            .sorted_by_key(|i| i.start);
14789
14790        let full_edits = selections
14791            .into_iter()
14792            .filter_map(|selection| {
14793                // Only requires two branches once if-let-chains stabilize (#53667)
14794                let child = if !selection.is_empty() {
14795                    selection.range()
14796                } else if let Some((_, ancestor_range)) =
14797                    buffer.syntax_ancestor(selection.start..selection.end)
14798                {
14799                    match ancestor_range {
14800                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14801                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14802                    }
14803                } else {
14804                    selection.range()
14805                };
14806
14807                let mut parent = child.clone();
14808                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14809                    parent = match ancestor_range {
14810                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14811                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14812                    };
14813                    if parent.start < child.start || parent.end > child.end {
14814                        break;
14815                    }
14816                }
14817
14818                if parent == child {
14819                    return None;
14820                }
14821                let text = buffer.text_for_range(child).collect::<String>();
14822                Some((selection.id, parent, text))
14823            })
14824            .collect::<Vec<_>>();
14825
14826        self.transact(window, cx, |this, window, cx| {
14827            this.buffer.update(cx, |buffer, cx| {
14828                buffer.edit(
14829                    full_edits
14830                        .iter()
14831                        .map(|(_, p, t)| (p.clone(), t.clone()))
14832                        .collect::<Vec<_>>(),
14833                    None,
14834                    cx,
14835                );
14836            });
14837            this.change_selections(Default::default(), window, cx, |s| {
14838                let mut offset = 0;
14839                let mut selections = vec![];
14840                for (id, parent, text) in full_edits {
14841                    let start = parent.start - offset;
14842                    offset += parent.len() - text.len();
14843                    selections.push(Selection {
14844                        id,
14845                        start,
14846                        end: start + text.len(),
14847                        reversed: false,
14848                        goal: Default::default(),
14849                    });
14850                }
14851                s.select(selections);
14852            });
14853        });
14854    }
14855
14856    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14857        if !EditorSettings::get_global(cx).gutter.runnables {
14858            self.clear_tasks();
14859            return Task::ready(());
14860        }
14861        let project = self.project().map(Entity::downgrade);
14862        let task_sources = self.lsp_task_sources(cx);
14863        let multi_buffer = self.buffer.downgrade();
14864        cx.spawn_in(window, async move |editor, cx| {
14865            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14866            let Some(project) = project.and_then(|p| p.upgrade()) else {
14867                return;
14868            };
14869            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14870                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14871            }) else {
14872                return;
14873            };
14874
14875            let hide_runnables = project
14876                .update(cx, |project, _| project.is_via_collab())
14877                .unwrap_or(true);
14878            if hide_runnables {
14879                return;
14880            }
14881            let new_rows =
14882                cx.background_spawn({
14883                    let snapshot = display_snapshot.clone();
14884                    async move {
14885                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14886                    }
14887                })
14888                    .await;
14889            let Ok(lsp_tasks) =
14890                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14891            else {
14892                return;
14893            };
14894            let lsp_tasks = lsp_tasks.await;
14895
14896            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14897                lsp_tasks
14898                    .into_iter()
14899                    .flat_map(|(kind, tasks)| {
14900                        tasks.into_iter().filter_map(move |(location, task)| {
14901                            Some((kind.clone(), location?, task))
14902                        })
14903                    })
14904                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14905                        let buffer = location.target.buffer;
14906                        let buffer_snapshot = buffer.read(cx).snapshot();
14907                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14908                            |(excerpt_id, snapshot, _)| {
14909                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14910                                    display_snapshot
14911                                        .buffer_snapshot
14912                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14913                                } else {
14914                                    None
14915                                }
14916                            },
14917                        );
14918                        if let Some(offset) = offset {
14919                            let task_buffer_range =
14920                                location.target.range.to_point(&buffer_snapshot);
14921                            let context_buffer_range =
14922                                task_buffer_range.to_offset(&buffer_snapshot);
14923                            let context_range = BufferOffset(context_buffer_range.start)
14924                                ..BufferOffset(context_buffer_range.end);
14925
14926                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14927                                .or_insert_with(|| RunnableTasks {
14928                                    templates: Vec::new(),
14929                                    offset,
14930                                    column: task_buffer_range.start.column,
14931                                    extra_variables: HashMap::default(),
14932                                    context_range,
14933                                })
14934                                .templates
14935                                .push((kind, task.original_task().clone()));
14936                        }
14937
14938                        acc
14939                    })
14940            }) else {
14941                return;
14942            };
14943
14944            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14945                buffer.language_settings(cx).tasks.prefer_lsp
14946            }) else {
14947                return;
14948            };
14949
14950            let rows = Self::runnable_rows(
14951                project,
14952                display_snapshot,
14953                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14954                new_rows,
14955                cx.clone(),
14956            )
14957            .await;
14958            editor
14959                .update(cx, |editor, _| {
14960                    editor.clear_tasks();
14961                    for (key, mut value) in rows {
14962                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14963                            value.templates.extend(lsp_tasks.templates);
14964                        }
14965
14966                        editor.insert_tasks(key, value);
14967                    }
14968                    for (key, value) in lsp_tasks_by_rows {
14969                        editor.insert_tasks(key, value);
14970                    }
14971                })
14972                .ok();
14973        })
14974    }
14975    fn fetch_runnable_ranges(
14976        snapshot: &DisplaySnapshot,
14977        range: Range<Anchor>,
14978    ) -> Vec<language::RunnableRange> {
14979        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14980    }
14981
14982    fn runnable_rows(
14983        project: Entity<Project>,
14984        snapshot: DisplaySnapshot,
14985        prefer_lsp: bool,
14986        runnable_ranges: Vec<RunnableRange>,
14987        cx: AsyncWindowContext,
14988    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14989        cx.spawn(async move |cx| {
14990            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14991            for mut runnable in runnable_ranges {
14992                let Some(tasks) = cx
14993                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14994                    .ok()
14995                else {
14996                    continue;
14997                };
14998                let mut tasks = tasks.await;
14999
15000                if prefer_lsp {
15001                    tasks.retain(|(task_kind, _)| {
15002                        !matches!(task_kind, TaskSourceKind::Language { .. })
15003                    });
15004                }
15005                if tasks.is_empty() {
15006                    continue;
15007                }
15008
15009                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15010                let Some(row) = snapshot
15011                    .buffer_snapshot
15012                    .buffer_line_for_row(MultiBufferRow(point.row))
15013                    .map(|(_, range)| range.start.row)
15014                else {
15015                    continue;
15016                };
15017
15018                let context_range =
15019                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15020                runnable_rows.push((
15021                    (runnable.buffer_id, row),
15022                    RunnableTasks {
15023                        templates: tasks,
15024                        offset: snapshot
15025                            .buffer_snapshot
15026                            .anchor_before(runnable.run_range.start),
15027                        context_range,
15028                        column: point.column,
15029                        extra_variables: runnable.extra_captures,
15030                    },
15031                ));
15032            }
15033            runnable_rows
15034        })
15035    }
15036
15037    fn templates_with_tags(
15038        project: &Entity<Project>,
15039        runnable: &mut Runnable,
15040        cx: &mut App,
15041    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15042        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15043            let (worktree_id, file) = project
15044                .buffer_for_id(runnable.buffer, cx)
15045                .and_then(|buffer| buffer.read(cx).file())
15046                .map(|file| (file.worktree_id(cx), file.clone()))
15047                .unzip();
15048
15049            (
15050                project.task_store().read(cx).task_inventory().cloned(),
15051                worktree_id,
15052                file,
15053            )
15054        });
15055
15056        let tags = mem::take(&mut runnable.tags);
15057        let language = runnable.language.clone();
15058        cx.spawn(async move |cx| {
15059            let mut templates_with_tags = Vec::new();
15060            if let Some(inventory) = inventory {
15061                for RunnableTag(tag) in tags {
15062                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15063                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15064                    }) else {
15065                        return templates_with_tags;
15066                    };
15067                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15068                        move |(_, template)| {
15069                            template.tags.iter().any(|source_tag| source_tag == &tag)
15070                        },
15071                    ));
15072                }
15073            }
15074            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15075
15076            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15077                // Strongest source wins; if we have worktree tag binding, prefer that to
15078                // global and language bindings;
15079                // if we have a global binding, prefer that to language binding.
15080                let first_mismatch = templates_with_tags
15081                    .iter()
15082                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15083                if let Some(index) = first_mismatch {
15084                    templates_with_tags.truncate(index);
15085                }
15086            }
15087
15088            templates_with_tags
15089        })
15090    }
15091
15092    pub fn move_to_enclosing_bracket(
15093        &mut self,
15094        _: &MoveToEnclosingBracket,
15095        window: &mut Window,
15096        cx: &mut Context<Self>,
15097    ) {
15098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15099        self.change_selections(Default::default(), window, cx, |s| {
15100            s.move_offsets_with(|snapshot, selection| {
15101                let Some(enclosing_bracket_ranges) =
15102                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15103                else {
15104                    return;
15105                };
15106
15107                let mut best_length = usize::MAX;
15108                let mut best_inside = false;
15109                let mut best_in_bracket_range = false;
15110                let mut best_destination = None;
15111                for (open, close) in enclosing_bracket_ranges {
15112                    let close = close.to_inclusive();
15113                    let length = close.end() - open.start;
15114                    let inside = selection.start >= open.end && selection.end <= *close.start();
15115                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15116                        || close.contains(&selection.head());
15117
15118                    // If best is next to a bracket and current isn't, skip
15119                    if !in_bracket_range && best_in_bracket_range {
15120                        continue;
15121                    }
15122
15123                    // Prefer smaller lengths unless best is inside and current isn't
15124                    if length > best_length && (best_inside || !inside) {
15125                        continue;
15126                    }
15127
15128                    best_length = length;
15129                    best_inside = inside;
15130                    best_in_bracket_range = in_bracket_range;
15131                    best_destination = Some(
15132                        if close.contains(&selection.start) && close.contains(&selection.end) {
15133                            if inside { open.end } else { open.start }
15134                        } else if inside {
15135                            *close.start()
15136                        } else {
15137                            *close.end()
15138                        },
15139                    );
15140                }
15141
15142                if let Some(destination) = best_destination {
15143                    selection.collapse_to(destination, SelectionGoal::None);
15144                }
15145            })
15146        });
15147    }
15148
15149    pub fn undo_selection(
15150        &mut self,
15151        _: &UndoSelection,
15152        window: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) {
15155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15156        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15157            self.selection_history.mode = SelectionHistoryMode::Undoing;
15158            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15159                this.end_selection(window, cx);
15160                this.change_selections(
15161                    SelectionEffects::scroll(Autoscroll::newest()),
15162                    window,
15163                    cx,
15164                    |s| s.select_anchors(entry.selections.to_vec()),
15165                );
15166            });
15167            self.selection_history.mode = SelectionHistoryMode::Normal;
15168
15169            self.select_next_state = entry.select_next_state;
15170            self.select_prev_state = entry.select_prev_state;
15171            self.add_selections_state = entry.add_selections_state;
15172        }
15173    }
15174
15175    pub fn redo_selection(
15176        &mut self,
15177        _: &RedoSelection,
15178        window: &mut Window,
15179        cx: &mut Context<Self>,
15180    ) {
15181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15182        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15183            self.selection_history.mode = SelectionHistoryMode::Redoing;
15184            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15185                this.end_selection(window, cx);
15186                this.change_selections(
15187                    SelectionEffects::scroll(Autoscroll::newest()),
15188                    window,
15189                    cx,
15190                    |s| s.select_anchors(entry.selections.to_vec()),
15191                );
15192            });
15193            self.selection_history.mode = SelectionHistoryMode::Normal;
15194
15195            self.select_next_state = entry.select_next_state;
15196            self.select_prev_state = entry.select_prev_state;
15197            self.add_selections_state = entry.add_selections_state;
15198        }
15199    }
15200
15201    pub fn expand_excerpts(
15202        &mut self,
15203        action: &ExpandExcerpts,
15204        _: &mut Window,
15205        cx: &mut Context<Self>,
15206    ) {
15207        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15208    }
15209
15210    pub fn expand_excerpts_down(
15211        &mut self,
15212        action: &ExpandExcerptsDown,
15213        _: &mut Window,
15214        cx: &mut Context<Self>,
15215    ) {
15216        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15217    }
15218
15219    pub fn expand_excerpts_up(
15220        &mut self,
15221        action: &ExpandExcerptsUp,
15222        _: &mut Window,
15223        cx: &mut Context<Self>,
15224    ) {
15225        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15226    }
15227
15228    pub fn expand_excerpts_for_direction(
15229        &mut self,
15230        lines: u32,
15231        direction: ExpandExcerptDirection,
15232
15233        cx: &mut Context<Self>,
15234    ) {
15235        let selections = self.selections.disjoint_anchors();
15236
15237        let lines = if lines == 0 {
15238            EditorSettings::get_global(cx).expand_excerpt_lines
15239        } else {
15240            lines
15241        };
15242
15243        self.buffer.update(cx, |buffer, cx| {
15244            let snapshot = buffer.snapshot(cx);
15245            let mut excerpt_ids = selections
15246                .iter()
15247                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15248                .collect::<Vec<_>>();
15249            excerpt_ids.sort();
15250            excerpt_ids.dedup();
15251            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15252        })
15253    }
15254
15255    pub fn expand_excerpt(
15256        &mut self,
15257        excerpt: ExcerptId,
15258        direction: ExpandExcerptDirection,
15259        window: &mut Window,
15260        cx: &mut Context<Self>,
15261    ) {
15262        let current_scroll_position = self.scroll_position(cx);
15263        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15264        let mut should_scroll_up = false;
15265
15266        if direction == ExpandExcerptDirection::Down {
15267            let multi_buffer = self.buffer.read(cx);
15268            let snapshot = multi_buffer.snapshot(cx);
15269            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15270                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15271                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15272            {
15273                let buffer_snapshot = buffer.read(cx).snapshot();
15274                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15275                let last_row = buffer_snapshot.max_point().row;
15276                let lines_below = last_row.saturating_sub(excerpt_end_row);
15277                should_scroll_up = lines_below >= lines_to_expand;
15278            }
15279        }
15280
15281        self.buffer.update(cx, |buffer, cx| {
15282            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15283        });
15284
15285        if should_scroll_up {
15286            let new_scroll_position =
15287                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15288            self.set_scroll_position(new_scroll_position, window, cx);
15289        }
15290    }
15291
15292    pub fn go_to_singleton_buffer_point(
15293        &mut self,
15294        point: Point,
15295        window: &mut Window,
15296        cx: &mut Context<Self>,
15297    ) {
15298        self.go_to_singleton_buffer_range(point..point, window, cx);
15299    }
15300
15301    pub fn go_to_singleton_buffer_range(
15302        &mut self,
15303        range: Range<Point>,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) {
15307        let multibuffer = self.buffer().read(cx);
15308        let Some(buffer) = multibuffer.as_singleton() else {
15309            return;
15310        };
15311        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15312            return;
15313        };
15314        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15315            return;
15316        };
15317        self.change_selections(
15318            SelectionEffects::default().nav_history(true),
15319            window,
15320            cx,
15321            |s| s.select_anchor_ranges([start..end]),
15322        );
15323    }
15324
15325    pub fn go_to_diagnostic(
15326        &mut self,
15327        action: &GoToDiagnostic,
15328        window: &mut Window,
15329        cx: &mut Context<Self>,
15330    ) {
15331        if !self.diagnostics_enabled() {
15332            return;
15333        }
15334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15335        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15336    }
15337
15338    pub fn go_to_prev_diagnostic(
15339        &mut self,
15340        action: &GoToPreviousDiagnostic,
15341        window: &mut Window,
15342        cx: &mut Context<Self>,
15343    ) {
15344        if !self.diagnostics_enabled() {
15345            return;
15346        }
15347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15348        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15349    }
15350
15351    pub fn go_to_diagnostic_impl(
15352        &mut self,
15353        direction: Direction,
15354        severity: GoToDiagnosticSeverityFilter,
15355        window: &mut Window,
15356        cx: &mut Context<Self>,
15357    ) {
15358        let buffer = self.buffer.read(cx).snapshot(cx);
15359        let selection = self.selections.newest::<usize>(cx);
15360
15361        let mut active_group_id = None;
15362        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15363            && active_group.active_range.start.to_offset(&buffer) == selection.start
15364        {
15365            active_group_id = Some(active_group.group_id);
15366        }
15367
15368        fn filtered(
15369            snapshot: EditorSnapshot,
15370            severity: GoToDiagnosticSeverityFilter,
15371            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15372        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15373            diagnostics
15374                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15375                .filter(|entry| entry.range.start != entry.range.end)
15376                .filter(|entry| !entry.diagnostic.is_unnecessary)
15377                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15378        }
15379
15380        let snapshot = self.snapshot(window, cx);
15381        let before = filtered(
15382            snapshot.clone(),
15383            severity,
15384            buffer
15385                .diagnostics_in_range(0..selection.start)
15386                .filter(|entry| entry.range.start <= selection.start),
15387        );
15388        let after = filtered(
15389            snapshot,
15390            severity,
15391            buffer
15392                .diagnostics_in_range(selection.start..buffer.len())
15393                .filter(|entry| entry.range.start >= selection.start),
15394        );
15395
15396        let mut found: Option<DiagnosticEntry<usize>> = None;
15397        if direction == Direction::Prev {
15398            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15399            {
15400                for diagnostic in prev_diagnostics.into_iter().rev() {
15401                    if diagnostic.range.start != selection.start
15402                        || active_group_id
15403                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15404                    {
15405                        found = Some(diagnostic);
15406                        break 'outer;
15407                    }
15408                }
15409            }
15410        } else {
15411            for diagnostic in after.chain(before) {
15412                if diagnostic.range.start != selection.start
15413                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15414                {
15415                    found = Some(diagnostic);
15416                    break;
15417                }
15418            }
15419        }
15420        let Some(next_diagnostic) = found else {
15421            return;
15422        };
15423
15424        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15425        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15426            return;
15427        };
15428        self.change_selections(Default::default(), window, cx, |s| {
15429            s.select_ranges(vec![
15430                next_diagnostic.range.start..next_diagnostic.range.start,
15431            ])
15432        });
15433        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15434        self.refresh_edit_prediction(false, true, window, cx);
15435    }
15436
15437    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15439        let snapshot = self.snapshot(window, cx);
15440        let selection = self.selections.newest::<Point>(cx);
15441        self.go_to_hunk_before_or_after_position(
15442            &snapshot,
15443            selection.head(),
15444            Direction::Next,
15445            window,
15446            cx,
15447        );
15448    }
15449
15450    pub fn go_to_hunk_before_or_after_position(
15451        &mut self,
15452        snapshot: &EditorSnapshot,
15453        position: Point,
15454        direction: Direction,
15455        window: &mut Window,
15456        cx: &mut Context<Editor>,
15457    ) {
15458        let row = if direction == Direction::Next {
15459            self.hunk_after_position(snapshot, position)
15460                .map(|hunk| hunk.row_range.start)
15461        } else {
15462            self.hunk_before_position(snapshot, position)
15463        };
15464
15465        if let Some(row) = row {
15466            let destination = Point::new(row.0, 0);
15467            let autoscroll = Autoscroll::center();
15468
15469            self.unfold_ranges(&[destination..destination], false, false, cx);
15470            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15471                s.select_ranges([destination..destination]);
15472            });
15473        }
15474    }
15475
15476    fn hunk_after_position(
15477        &mut self,
15478        snapshot: &EditorSnapshot,
15479        position: Point,
15480    ) -> Option<MultiBufferDiffHunk> {
15481        snapshot
15482            .buffer_snapshot
15483            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15484            .find(|hunk| hunk.row_range.start.0 > position.row)
15485            .or_else(|| {
15486                snapshot
15487                    .buffer_snapshot
15488                    .diff_hunks_in_range(Point::zero()..position)
15489                    .find(|hunk| hunk.row_range.end.0 < position.row)
15490            })
15491    }
15492
15493    fn go_to_prev_hunk(
15494        &mut self,
15495        _: &GoToPreviousHunk,
15496        window: &mut Window,
15497        cx: &mut Context<Self>,
15498    ) {
15499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15500        let snapshot = self.snapshot(window, cx);
15501        let selection = self.selections.newest::<Point>(cx);
15502        self.go_to_hunk_before_or_after_position(
15503            &snapshot,
15504            selection.head(),
15505            Direction::Prev,
15506            window,
15507            cx,
15508        );
15509    }
15510
15511    fn hunk_before_position(
15512        &mut self,
15513        snapshot: &EditorSnapshot,
15514        position: Point,
15515    ) -> Option<MultiBufferRow> {
15516        snapshot
15517            .buffer_snapshot
15518            .diff_hunk_before(position)
15519            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15520    }
15521
15522    fn go_to_next_change(
15523        &mut self,
15524        _: &GoToNextChange,
15525        window: &mut Window,
15526        cx: &mut Context<Self>,
15527    ) {
15528        if let Some(selections) = self
15529            .change_list
15530            .next_change(1, Direction::Next)
15531            .map(|s| s.to_vec())
15532        {
15533            self.change_selections(Default::default(), window, cx, |s| {
15534                let map = s.display_map();
15535                s.select_display_ranges(selections.iter().map(|a| {
15536                    let point = a.to_display_point(&map);
15537                    point..point
15538                }))
15539            })
15540        }
15541    }
15542
15543    fn go_to_previous_change(
15544        &mut self,
15545        _: &GoToPreviousChange,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) {
15549        if let Some(selections) = self
15550            .change_list
15551            .next_change(1, Direction::Prev)
15552            .map(|s| s.to_vec())
15553        {
15554            self.change_selections(Default::default(), window, cx, |s| {
15555                let map = s.display_map();
15556                s.select_display_ranges(selections.iter().map(|a| {
15557                    let point = a.to_display_point(&map);
15558                    point..point
15559                }))
15560            })
15561        }
15562    }
15563
15564    fn go_to_line<T: 'static>(
15565        &mut self,
15566        position: Anchor,
15567        highlight_color: Option<Hsla>,
15568        window: &mut Window,
15569        cx: &mut Context<Self>,
15570    ) {
15571        let snapshot = self.snapshot(window, cx).display_snapshot;
15572        let position = position.to_point(&snapshot.buffer_snapshot);
15573        let start = snapshot
15574            .buffer_snapshot
15575            .clip_point(Point::new(position.row, 0), Bias::Left);
15576        let end = start + Point::new(1, 0);
15577        let start = snapshot.buffer_snapshot.anchor_before(start);
15578        let end = snapshot.buffer_snapshot.anchor_before(end);
15579
15580        self.highlight_rows::<T>(
15581            start..end,
15582            highlight_color
15583                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15584            Default::default(),
15585            cx,
15586        );
15587
15588        if self.buffer.read(cx).is_singleton() {
15589            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15590        }
15591    }
15592
15593    pub fn go_to_definition(
15594        &mut self,
15595        _: &GoToDefinition,
15596        window: &mut Window,
15597        cx: &mut Context<Self>,
15598    ) -> Task<Result<Navigated>> {
15599        let definition =
15600            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15601        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15602        cx.spawn_in(window, async move |editor, cx| {
15603            if definition.await? == Navigated::Yes {
15604                return Ok(Navigated::Yes);
15605            }
15606            match fallback_strategy {
15607                GoToDefinitionFallback::None => Ok(Navigated::No),
15608                GoToDefinitionFallback::FindAllReferences => {
15609                    match editor.update_in(cx, |editor, window, cx| {
15610                        editor.find_all_references(&FindAllReferences, window, cx)
15611                    })? {
15612                        Some(references) => references.await,
15613                        None => Ok(Navigated::No),
15614                    }
15615                }
15616            }
15617        })
15618    }
15619
15620    pub fn go_to_declaration(
15621        &mut self,
15622        _: &GoToDeclaration,
15623        window: &mut Window,
15624        cx: &mut Context<Self>,
15625    ) -> Task<Result<Navigated>> {
15626        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15627    }
15628
15629    pub fn go_to_declaration_split(
15630        &mut self,
15631        _: &GoToDeclaration,
15632        window: &mut Window,
15633        cx: &mut Context<Self>,
15634    ) -> Task<Result<Navigated>> {
15635        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15636    }
15637
15638    pub fn go_to_implementation(
15639        &mut self,
15640        _: &GoToImplementation,
15641        window: &mut Window,
15642        cx: &mut Context<Self>,
15643    ) -> Task<Result<Navigated>> {
15644        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15645    }
15646
15647    pub fn go_to_implementation_split(
15648        &mut self,
15649        _: &GoToImplementationSplit,
15650        window: &mut Window,
15651        cx: &mut Context<Self>,
15652    ) -> Task<Result<Navigated>> {
15653        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15654    }
15655
15656    pub fn go_to_type_definition(
15657        &mut self,
15658        _: &GoToTypeDefinition,
15659        window: &mut Window,
15660        cx: &mut Context<Self>,
15661    ) -> Task<Result<Navigated>> {
15662        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15663    }
15664
15665    pub fn go_to_definition_split(
15666        &mut self,
15667        _: &GoToDefinitionSplit,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) -> Task<Result<Navigated>> {
15671        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15672    }
15673
15674    pub fn go_to_type_definition_split(
15675        &mut self,
15676        _: &GoToTypeDefinitionSplit,
15677        window: &mut Window,
15678        cx: &mut Context<Self>,
15679    ) -> Task<Result<Navigated>> {
15680        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15681    }
15682
15683    fn go_to_definition_of_kind(
15684        &mut self,
15685        kind: GotoDefinitionKind,
15686        split: bool,
15687        window: &mut Window,
15688        cx: &mut Context<Self>,
15689    ) -> Task<Result<Navigated>> {
15690        let Some(provider) = self.semantics_provider.clone() else {
15691            return Task::ready(Ok(Navigated::No));
15692        };
15693        let head = self.selections.newest::<usize>(cx).head();
15694        let buffer = self.buffer.read(cx);
15695        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15696            return Task::ready(Ok(Navigated::No));
15697        };
15698        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15699            return Task::ready(Ok(Navigated::No));
15700        };
15701
15702        cx.spawn_in(window, async move |editor, cx| {
15703            let Some(definitions) = definitions.await? else {
15704                return Ok(Navigated::No);
15705            };
15706            let navigated = editor
15707                .update_in(cx, |editor, window, cx| {
15708                    editor.navigate_to_hover_links(
15709                        Some(kind),
15710                        definitions
15711                            .into_iter()
15712                            .filter(|location| {
15713                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15714                            })
15715                            .map(HoverLink::Text)
15716                            .collect::<Vec<_>>(),
15717                        split,
15718                        window,
15719                        cx,
15720                    )
15721                })?
15722                .await?;
15723            anyhow::Ok(navigated)
15724        })
15725    }
15726
15727    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15728        let selection = self.selections.newest_anchor();
15729        let head = selection.head();
15730        let tail = selection.tail();
15731
15732        let Some((buffer, start_position)) =
15733            self.buffer.read(cx).text_anchor_for_position(head, cx)
15734        else {
15735            return;
15736        };
15737
15738        let end_position = if head != tail {
15739            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15740                return;
15741            };
15742            Some(pos)
15743        } else {
15744            None
15745        };
15746
15747        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15748            let url = if let Some(end_pos) = end_position {
15749                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15750            } else {
15751                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15752            };
15753
15754            if let Some(url) = url {
15755                editor.update(cx, |_, cx| {
15756                    cx.open_url(&url);
15757                })
15758            } else {
15759                Ok(())
15760            }
15761        });
15762
15763        url_finder.detach();
15764    }
15765
15766    pub fn open_selected_filename(
15767        &mut self,
15768        _: &OpenSelectedFilename,
15769        window: &mut Window,
15770        cx: &mut Context<Self>,
15771    ) {
15772        let Some(workspace) = self.workspace() else {
15773            return;
15774        };
15775
15776        let position = self.selections.newest_anchor().head();
15777
15778        let Some((buffer, buffer_position)) =
15779            self.buffer.read(cx).text_anchor_for_position(position, cx)
15780        else {
15781            return;
15782        };
15783
15784        let project = self.project.clone();
15785
15786        cx.spawn_in(window, async move |_, cx| {
15787            let result = find_file(&buffer, project, buffer_position, cx).await;
15788
15789            if let Some((_, path)) = result {
15790                workspace
15791                    .update_in(cx, |workspace, window, cx| {
15792                        workspace.open_resolved_path(path, window, cx)
15793                    })?
15794                    .await?;
15795            }
15796            anyhow::Ok(())
15797        })
15798        .detach();
15799    }
15800
15801    pub(crate) fn navigate_to_hover_links(
15802        &mut self,
15803        kind: Option<GotoDefinitionKind>,
15804        definitions: Vec<HoverLink>,
15805        split: bool,
15806        window: &mut Window,
15807        cx: &mut Context<Editor>,
15808    ) -> Task<Result<Navigated>> {
15809        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15810        let mut first_url_or_file = None;
15811        let definitions: Vec<_> = definitions
15812            .into_iter()
15813            .filter_map(|def| match def {
15814                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15815                HoverLink::InlayHint(lsp_location, server_id) => {
15816                    let computation =
15817                        self.compute_target_location(lsp_location, server_id, window, cx);
15818                    Some(cx.background_spawn(computation))
15819                }
15820                HoverLink::Url(url) => {
15821                    first_url_or_file = Some(Either::Left(url));
15822                    None
15823                }
15824                HoverLink::File(path) => {
15825                    first_url_or_file = Some(Either::Right(path));
15826                    None
15827                }
15828            })
15829            .collect();
15830
15831        let workspace = self.workspace();
15832
15833        cx.spawn_in(window, async move |editor, acx| {
15834            let mut locations: Vec<Location> = future::join_all(definitions)
15835                .await
15836                .into_iter()
15837                .filter_map(|location| location.transpose())
15838                .collect::<Result<_>>()
15839                .context("location tasks")?;
15840
15841            if locations.len() > 1 {
15842                let Some(workspace) = workspace else {
15843                    return Ok(Navigated::No);
15844                };
15845
15846                let tab_kind = match kind {
15847                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15848                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15849                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15850                    Some(GotoDefinitionKind::Type) => "Types",
15851                };
15852                let title = editor
15853                    .update_in(acx, |_, _, cx| {
15854                        let target = locations
15855                            .iter()
15856                            .map(|location| {
15857                                location
15858                                    .buffer
15859                                    .read(cx)
15860                                    .text_for_range(location.range.clone())
15861                                    .collect::<String>()
15862                            })
15863                            .filter(|text| !text.contains('\n'))
15864                            .unique()
15865                            .take(3)
15866                            .join(", ");
15867                        if target.is_empty() {
15868                            tab_kind.to_owned()
15869                        } else {
15870                            format!("{tab_kind} for {target}")
15871                        }
15872                    })
15873                    .context("buffer title")?;
15874
15875                let opened = workspace
15876                    .update_in(acx, |workspace, window, cx| {
15877                        Self::open_locations_in_multibuffer(
15878                            workspace,
15879                            locations,
15880                            title,
15881                            split,
15882                            MultibufferSelectionMode::First,
15883                            window,
15884                            cx,
15885                        )
15886                    })
15887                    .is_ok();
15888
15889                anyhow::Ok(Navigated::from_bool(opened))
15890            } else if locations.is_empty() {
15891                // If there is one definition, just open it directly
15892                match first_url_or_file {
15893                    Some(Either::Left(url)) => {
15894                        acx.update(|_, cx| cx.open_url(&url))?;
15895                        Ok(Navigated::Yes)
15896                    }
15897                    Some(Either::Right(path)) => {
15898                        let Some(workspace) = workspace else {
15899                            return Ok(Navigated::No);
15900                        };
15901
15902                        workspace
15903                            .update_in(acx, |workspace, window, cx| {
15904                                workspace.open_resolved_path(path, window, cx)
15905                            })?
15906                            .await?;
15907                        Ok(Navigated::Yes)
15908                    }
15909                    None => Ok(Navigated::No),
15910                }
15911            } else {
15912                let Some(workspace) = workspace else {
15913                    return Ok(Navigated::No);
15914                };
15915
15916                let target = locations.pop().unwrap();
15917                editor.update_in(acx, |editor, window, cx| {
15918                    let pane = workspace.read(cx).active_pane().clone();
15919
15920                    let range = target.range.to_point(target.buffer.read(cx));
15921                    let range = editor.range_for_match(&range);
15922                    let range = collapse_multiline_range(range);
15923
15924                    if !split
15925                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15926                    {
15927                        editor.go_to_singleton_buffer_range(range, window, cx);
15928                    } else {
15929                        window.defer(cx, move |window, cx| {
15930                            let target_editor: Entity<Self> =
15931                                workspace.update(cx, |workspace, cx| {
15932                                    let pane = if split {
15933                                        workspace.adjacent_pane(window, cx)
15934                                    } else {
15935                                        workspace.active_pane().clone()
15936                                    };
15937
15938                                    workspace.open_project_item(
15939                                        pane,
15940                                        target.buffer.clone(),
15941                                        true,
15942                                        true,
15943                                        window,
15944                                        cx,
15945                                    )
15946                                });
15947                            target_editor.update(cx, |target_editor, cx| {
15948                                // When selecting a definition in a different buffer, disable the nav history
15949                                // to avoid creating a history entry at the previous cursor location.
15950                                pane.update(cx, |pane, _| pane.disable_history());
15951                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15952                                pane.update(cx, |pane, _| pane.enable_history());
15953                            });
15954                        });
15955                    }
15956                    Navigated::Yes
15957                })
15958            }
15959        })
15960    }
15961
15962    fn compute_target_location(
15963        &self,
15964        lsp_location: lsp::Location,
15965        server_id: LanguageServerId,
15966        window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) -> Task<anyhow::Result<Option<Location>>> {
15969        let Some(project) = self.project.clone() else {
15970            return Task::ready(Ok(None));
15971        };
15972
15973        cx.spawn_in(window, async move |editor, cx| {
15974            let location_task = editor.update(cx, |_, cx| {
15975                project.update(cx, |project, cx| {
15976                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
15977                })
15978            })?;
15979            let location = Some({
15980                let target_buffer_handle = location_task.await.context("open local buffer")?;
15981                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15982                    let target_start = target_buffer
15983                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15984                    let target_end = target_buffer
15985                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15986                    target_buffer.anchor_after(target_start)
15987                        ..target_buffer.anchor_before(target_end)
15988                })?;
15989                Location {
15990                    buffer: target_buffer_handle,
15991                    range,
15992                }
15993            });
15994            Ok(location)
15995        })
15996    }
15997
15998    pub fn find_all_references(
15999        &mut self,
16000        _: &FindAllReferences,
16001        window: &mut Window,
16002        cx: &mut Context<Self>,
16003    ) -> Option<Task<Result<Navigated>>> {
16004        let selection = self.selections.newest::<usize>(cx);
16005        let multi_buffer = self.buffer.read(cx);
16006        let head = selection.head();
16007
16008        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16009        let head_anchor = multi_buffer_snapshot.anchor_at(
16010            head,
16011            if head < selection.tail() {
16012                Bias::Right
16013            } else {
16014                Bias::Left
16015            },
16016        );
16017
16018        match self
16019            .find_all_references_task_sources
16020            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16021        {
16022            Ok(_) => {
16023                log::info!(
16024                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16025                );
16026                return None;
16027            }
16028            Err(i) => {
16029                self.find_all_references_task_sources.insert(i, head_anchor);
16030            }
16031        }
16032
16033        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16034        let workspace = self.workspace()?;
16035        let project = workspace.read(cx).project().clone();
16036        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16037        Some(cx.spawn_in(window, async move |editor, cx| {
16038            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16039                if let Ok(i) = editor
16040                    .find_all_references_task_sources
16041                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16042                {
16043                    editor.find_all_references_task_sources.remove(i);
16044                }
16045            });
16046
16047            let Some(locations) = references.await? else {
16048                return anyhow::Ok(Navigated::No);
16049            };
16050            if locations.is_empty() {
16051                return anyhow::Ok(Navigated::No);
16052            }
16053
16054            workspace.update_in(cx, |workspace, window, cx| {
16055                let target = locations
16056                    .iter()
16057                    .map(|location| {
16058                        location
16059                            .buffer
16060                            .read(cx)
16061                            .text_for_range(location.range.clone())
16062                            .collect::<String>()
16063                    })
16064                    .filter(|text| !text.contains('\n'))
16065                    .unique()
16066                    .take(3)
16067                    .join(", ");
16068                let title = if target.is_empty() {
16069                    "References".to_owned()
16070                } else {
16071                    format!("References to {target}")
16072                };
16073                Self::open_locations_in_multibuffer(
16074                    workspace,
16075                    locations,
16076                    title,
16077                    false,
16078                    MultibufferSelectionMode::First,
16079                    window,
16080                    cx,
16081                );
16082                Navigated::Yes
16083            })
16084        }))
16085    }
16086
16087    /// Opens a multibuffer with the given project locations in it
16088    pub fn open_locations_in_multibuffer(
16089        workspace: &mut Workspace,
16090        mut locations: Vec<Location>,
16091        title: String,
16092        split: bool,
16093        multibuffer_selection_mode: MultibufferSelectionMode,
16094        window: &mut Window,
16095        cx: &mut Context<Workspace>,
16096    ) {
16097        if locations.is_empty() {
16098            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16099            return;
16100        }
16101
16102        // If there are multiple definitions, open them in a multibuffer
16103        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16104        let mut locations = locations.into_iter().peekable();
16105        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16106        let capability = workspace.project().read(cx).capability();
16107
16108        let excerpt_buffer = cx.new(|cx| {
16109            let mut multibuffer = MultiBuffer::new(capability);
16110            while let Some(location) = locations.next() {
16111                let buffer = location.buffer.read(cx);
16112                let mut ranges_for_buffer = Vec::new();
16113                let range = location.range.to_point(buffer);
16114                ranges_for_buffer.push(range.clone());
16115
16116                while let Some(next_location) = locations.peek() {
16117                    if next_location.buffer == location.buffer {
16118                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16119                        locations.next();
16120                    } else {
16121                        break;
16122                    }
16123                }
16124
16125                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16126                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16127                    PathKey::for_buffer(&location.buffer, cx),
16128                    location.buffer.clone(),
16129                    ranges_for_buffer,
16130                    DEFAULT_MULTIBUFFER_CONTEXT,
16131                    cx,
16132                );
16133                ranges.extend(new_ranges)
16134            }
16135
16136            multibuffer.with_title(title)
16137        });
16138
16139        let editor = cx.new(|cx| {
16140            Editor::for_multibuffer(
16141                excerpt_buffer,
16142                Some(workspace.project().clone()),
16143                window,
16144                cx,
16145            )
16146        });
16147        editor.update(cx, |editor, cx| {
16148            match multibuffer_selection_mode {
16149                MultibufferSelectionMode::First => {
16150                    if let Some(first_range) = ranges.first() {
16151                        editor.change_selections(
16152                            SelectionEffects::no_scroll(),
16153                            window,
16154                            cx,
16155                            |selections| {
16156                                selections.clear_disjoint();
16157                                selections
16158                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16159                            },
16160                        );
16161                    }
16162                    editor.highlight_background::<Self>(
16163                        &ranges,
16164                        |theme| theme.colors().editor_highlighted_line_background,
16165                        cx,
16166                    );
16167                }
16168                MultibufferSelectionMode::All => {
16169                    editor.change_selections(
16170                        SelectionEffects::no_scroll(),
16171                        window,
16172                        cx,
16173                        |selections| {
16174                            selections.clear_disjoint();
16175                            selections.select_anchor_ranges(ranges);
16176                        },
16177                    );
16178                }
16179            }
16180            editor.register_buffers_with_language_servers(cx);
16181        });
16182
16183        let item = Box::new(editor);
16184        let item_id = item.item_id();
16185
16186        if split {
16187            workspace.split_item(SplitDirection::Right, item, window, cx);
16188        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16189            let (preview_item_id, preview_item_idx) =
16190                workspace.active_pane().read_with(cx, |pane, _| {
16191                    (pane.preview_item_id(), pane.preview_item_idx())
16192                });
16193
16194            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16195
16196            if let Some(preview_item_id) = preview_item_id {
16197                workspace.active_pane().update(cx, |pane, cx| {
16198                    pane.remove_item(preview_item_id, false, false, window, cx);
16199                });
16200            }
16201        } else {
16202            workspace.add_item_to_active_pane(item, None, true, window, cx);
16203        }
16204        workspace.active_pane().update(cx, |pane, cx| {
16205            pane.set_preview_item_id(Some(item_id), cx);
16206        });
16207    }
16208
16209    pub fn rename(
16210        &mut self,
16211        _: &Rename,
16212        window: &mut Window,
16213        cx: &mut Context<Self>,
16214    ) -> Option<Task<Result<()>>> {
16215        use language::ToOffset as _;
16216
16217        let provider = self.semantics_provider.clone()?;
16218        let selection = self.selections.newest_anchor().clone();
16219        let (cursor_buffer, cursor_buffer_position) = self
16220            .buffer
16221            .read(cx)
16222            .text_anchor_for_position(selection.head(), cx)?;
16223        let (tail_buffer, cursor_buffer_position_end) = self
16224            .buffer
16225            .read(cx)
16226            .text_anchor_for_position(selection.tail(), cx)?;
16227        if tail_buffer != cursor_buffer {
16228            return None;
16229        }
16230
16231        let snapshot = cursor_buffer.read(cx).snapshot();
16232        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16233        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16234        let prepare_rename = provider
16235            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16236            .unwrap_or_else(|| Task::ready(Ok(None)));
16237        drop(snapshot);
16238
16239        Some(cx.spawn_in(window, async move |this, cx| {
16240            let rename_range = if let Some(range) = prepare_rename.await? {
16241                Some(range)
16242            } else {
16243                this.update(cx, |this, cx| {
16244                    let buffer = this.buffer.read(cx).snapshot(cx);
16245                    let mut buffer_highlights = this
16246                        .document_highlights_for_position(selection.head(), &buffer)
16247                        .filter(|highlight| {
16248                            highlight.start.excerpt_id == selection.head().excerpt_id
16249                                && highlight.end.excerpt_id == selection.head().excerpt_id
16250                        });
16251                    buffer_highlights
16252                        .next()
16253                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16254                })?
16255            };
16256            if let Some(rename_range) = rename_range {
16257                this.update_in(cx, |this, window, cx| {
16258                    let snapshot = cursor_buffer.read(cx).snapshot();
16259                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16260                    let cursor_offset_in_rename_range =
16261                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16262                    let cursor_offset_in_rename_range_end =
16263                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16264
16265                    this.take_rename(false, window, cx);
16266                    let buffer = this.buffer.read(cx).read(cx);
16267                    let cursor_offset = selection.head().to_offset(&buffer);
16268                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16269                    let rename_end = rename_start + rename_buffer_range.len();
16270                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16271                    let mut old_highlight_id = None;
16272                    let old_name: Arc<str> = buffer
16273                        .chunks(rename_start..rename_end, true)
16274                        .map(|chunk| {
16275                            if old_highlight_id.is_none() {
16276                                old_highlight_id = chunk.syntax_highlight_id;
16277                            }
16278                            chunk.text
16279                        })
16280                        .collect::<String>()
16281                        .into();
16282
16283                    drop(buffer);
16284
16285                    // Position the selection in the rename editor so that it matches the current selection.
16286                    this.show_local_selections = false;
16287                    let rename_editor = cx.new(|cx| {
16288                        let mut editor = Editor::single_line(window, cx);
16289                        editor.buffer.update(cx, |buffer, cx| {
16290                            buffer.edit([(0..0, old_name.clone())], None, cx)
16291                        });
16292                        let rename_selection_range = match cursor_offset_in_rename_range
16293                            .cmp(&cursor_offset_in_rename_range_end)
16294                        {
16295                            Ordering::Equal => {
16296                                editor.select_all(&SelectAll, window, cx);
16297                                return editor;
16298                            }
16299                            Ordering::Less => {
16300                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16301                            }
16302                            Ordering::Greater => {
16303                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16304                            }
16305                        };
16306                        if rename_selection_range.end > old_name.len() {
16307                            editor.select_all(&SelectAll, window, cx);
16308                        } else {
16309                            editor.change_selections(Default::default(), window, cx, |s| {
16310                                s.select_ranges([rename_selection_range]);
16311                            });
16312                        }
16313                        editor
16314                    });
16315                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16316                        if e == &EditorEvent::Focused {
16317                            cx.emit(EditorEvent::FocusedIn)
16318                        }
16319                    })
16320                    .detach();
16321
16322                    let write_highlights =
16323                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16324                    let read_highlights =
16325                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16326                    let ranges = write_highlights
16327                        .iter()
16328                        .flat_map(|(_, ranges)| ranges.iter())
16329                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16330                        .cloned()
16331                        .collect();
16332
16333                    this.highlight_text::<Rename>(
16334                        ranges,
16335                        HighlightStyle {
16336                            fade_out: Some(0.6),
16337                            ..Default::default()
16338                        },
16339                        cx,
16340                    );
16341                    let rename_focus_handle = rename_editor.focus_handle(cx);
16342                    window.focus(&rename_focus_handle);
16343                    let block_id = this.insert_blocks(
16344                        [BlockProperties {
16345                            style: BlockStyle::Flex,
16346                            placement: BlockPlacement::Below(range.start),
16347                            height: Some(1),
16348                            render: Arc::new({
16349                                let rename_editor = rename_editor.clone();
16350                                move |cx: &mut BlockContext| {
16351                                    let mut text_style = cx.editor_style.text.clone();
16352                                    if let Some(highlight_style) = old_highlight_id
16353                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16354                                    {
16355                                        text_style = text_style.highlight(highlight_style);
16356                                    }
16357                                    div()
16358                                        .block_mouse_except_scroll()
16359                                        .pl(cx.anchor_x)
16360                                        .child(EditorElement::new(
16361                                            &rename_editor,
16362                                            EditorStyle {
16363                                                background: cx.theme().system().transparent,
16364                                                local_player: cx.editor_style.local_player,
16365                                                text: text_style,
16366                                                scrollbar_width: cx.editor_style.scrollbar_width,
16367                                                syntax: cx.editor_style.syntax.clone(),
16368                                                status: cx.editor_style.status.clone(),
16369                                                inlay_hints_style: HighlightStyle {
16370                                                    font_weight: Some(FontWeight::BOLD),
16371                                                    ..make_inlay_hints_style(cx.app)
16372                                                },
16373                                                edit_prediction_styles: make_suggestion_styles(
16374                                                    cx.app,
16375                                                ),
16376                                                ..EditorStyle::default()
16377                                            },
16378                                        ))
16379                                        .into_any_element()
16380                                }
16381                            }),
16382                            priority: 0,
16383                        }],
16384                        Some(Autoscroll::fit()),
16385                        cx,
16386                    )[0];
16387                    this.pending_rename = Some(RenameState {
16388                        range,
16389                        old_name,
16390                        editor: rename_editor,
16391                        block_id,
16392                    });
16393                })?;
16394            }
16395
16396            Ok(())
16397        }))
16398    }
16399
16400    pub fn confirm_rename(
16401        &mut self,
16402        _: &ConfirmRename,
16403        window: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) -> Option<Task<Result<()>>> {
16406        let rename = self.take_rename(false, window, cx)?;
16407        let workspace = self.workspace()?.downgrade();
16408        let (buffer, start) = self
16409            .buffer
16410            .read(cx)
16411            .text_anchor_for_position(rename.range.start, cx)?;
16412        let (end_buffer, _) = self
16413            .buffer
16414            .read(cx)
16415            .text_anchor_for_position(rename.range.end, cx)?;
16416        if buffer != end_buffer {
16417            return None;
16418        }
16419
16420        let old_name = rename.old_name;
16421        let new_name = rename.editor.read(cx).text(cx);
16422
16423        let rename = self.semantics_provider.as_ref()?.perform_rename(
16424            &buffer,
16425            start,
16426            new_name.clone(),
16427            cx,
16428        )?;
16429
16430        Some(cx.spawn_in(window, async move |editor, cx| {
16431            let project_transaction = rename.await?;
16432            Self::open_project_transaction(
16433                &editor,
16434                workspace,
16435                project_transaction,
16436                format!("Rename: {}{}", old_name, new_name),
16437                cx,
16438            )
16439            .await?;
16440
16441            editor.update(cx, |editor, cx| {
16442                editor.refresh_document_highlights(cx);
16443            })?;
16444            Ok(())
16445        }))
16446    }
16447
16448    fn take_rename(
16449        &mut self,
16450        moving_cursor: bool,
16451        window: &mut Window,
16452        cx: &mut Context<Self>,
16453    ) -> Option<RenameState> {
16454        let rename = self.pending_rename.take()?;
16455        if rename.editor.focus_handle(cx).is_focused(window) {
16456            window.focus(&self.focus_handle);
16457        }
16458
16459        self.remove_blocks(
16460            [rename.block_id].into_iter().collect(),
16461            Some(Autoscroll::fit()),
16462            cx,
16463        );
16464        self.clear_highlights::<Rename>(cx);
16465        self.show_local_selections = true;
16466
16467        if moving_cursor {
16468            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16469                editor.selections.newest::<usize>(cx).head()
16470            });
16471
16472            // Update the selection to match the position of the selection inside
16473            // the rename editor.
16474            let snapshot = self.buffer.read(cx).read(cx);
16475            let rename_range = rename.range.to_offset(&snapshot);
16476            let cursor_in_editor = snapshot
16477                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16478                .min(rename_range.end);
16479            drop(snapshot);
16480
16481            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16482                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16483            });
16484        } else {
16485            self.refresh_document_highlights(cx);
16486        }
16487
16488        Some(rename)
16489    }
16490
16491    pub fn pending_rename(&self) -> Option<&RenameState> {
16492        self.pending_rename.as_ref()
16493    }
16494
16495    fn format(
16496        &mut self,
16497        _: &Format,
16498        window: &mut Window,
16499        cx: &mut Context<Self>,
16500    ) -> Option<Task<Result<()>>> {
16501        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16502
16503        let project = match &self.project {
16504            Some(project) => project.clone(),
16505            None => return None,
16506        };
16507
16508        Some(self.perform_format(
16509            project,
16510            FormatTrigger::Manual,
16511            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16512            window,
16513            cx,
16514        ))
16515    }
16516
16517    fn format_selections(
16518        &mut self,
16519        _: &FormatSelections,
16520        window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) -> Option<Task<Result<()>>> {
16523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16524
16525        let project = match &self.project {
16526            Some(project) => project.clone(),
16527            None => return None,
16528        };
16529
16530        let ranges = self
16531            .selections
16532            .all_adjusted(cx)
16533            .into_iter()
16534            .map(|selection| selection.range())
16535            .collect_vec();
16536
16537        Some(self.perform_format(
16538            project,
16539            FormatTrigger::Manual,
16540            FormatTarget::Ranges(ranges),
16541            window,
16542            cx,
16543        ))
16544    }
16545
16546    fn perform_format(
16547        &mut self,
16548        project: Entity<Project>,
16549        trigger: FormatTrigger,
16550        target: FormatTarget,
16551        window: &mut Window,
16552        cx: &mut Context<Self>,
16553    ) -> Task<Result<()>> {
16554        let buffer = self.buffer.clone();
16555        let (buffers, target) = match target {
16556            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16557            FormatTarget::Ranges(selection_ranges) => {
16558                let multi_buffer = buffer.read(cx);
16559                let snapshot = multi_buffer.read(cx);
16560                let mut buffers = HashSet::default();
16561                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16562                    BTreeMap::new();
16563                for selection_range in selection_ranges {
16564                    for (buffer, buffer_range, _) in
16565                        snapshot.range_to_buffer_ranges(selection_range)
16566                    {
16567                        let buffer_id = buffer.remote_id();
16568                        let start = buffer.anchor_before(buffer_range.start);
16569                        let end = buffer.anchor_after(buffer_range.end);
16570                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16571                        buffer_id_to_ranges
16572                            .entry(buffer_id)
16573                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16574                            .or_insert_with(|| vec![start..end]);
16575                    }
16576                }
16577                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16578            }
16579        };
16580
16581        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16582        let selections_prev = transaction_id_prev
16583            .and_then(|transaction_id_prev| {
16584                // default to selections as they were after the last edit, if we have them,
16585                // instead of how they are now.
16586                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16587                // will take you back to where you made the last edit, instead of staying where you scrolled
16588                self.selection_history
16589                    .transaction(transaction_id_prev)
16590                    .map(|t| t.0.clone())
16591            })
16592            .unwrap_or_else(|| self.selections.disjoint_anchors());
16593
16594        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16595        let format = project.update(cx, |project, cx| {
16596            project.format(buffers, target, true, trigger, cx)
16597        });
16598
16599        cx.spawn_in(window, async move |editor, cx| {
16600            let transaction = futures::select_biased! {
16601                transaction = format.log_err().fuse() => transaction,
16602                () = timeout => {
16603                    log::warn!("timed out waiting for formatting");
16604                    None
16605                }
16606            };
16607
16608            buffer
16609                .update(cx, |buffer, cx| {
16610                    if let Some(transaction) = transaction
16611                        && !buffer.is_singleton()
16612                    {
16613                        buffer.push_transaction(&transaction.0, cx);
16614                    }
16615                    cx.notify();
16616                })
16617                .ok();
16618
16619            if let Some(transaction_id_now) =
16620                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16621            {
16622                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16623                if has_new_transaction {
16624                    _ = editor.update(cx, |editor, _| {
16625                        editor
16626                            .selection_history
16627                            .insert_transaction(transaction_id_now, selections_prev);
16628                    });
16629                }
16630            }
16631
16632            Ok(())
16633        })
16634    }
16635
16636    fn organize_imports(
16637        &mut self,
16638        _: &OrganizeImports,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) -> Option<Task<Result<()>>> {
16642        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16643        let project = match &self.project {
16644            Some(project) => project.clone(),
16645            None => return None,
16646        };
16647        Some(self.perform_code_action_kind(
16648            project,
16649            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16650            window,
16651            cx,
16652        ))
16653    }
16654
16655    fn perform_code_action_kind(
16656        &mut self,
16657        project: Entity<Project>,
16658        kind: CodeActionKind,
16659        window: &mut Window,
16660        cx: &mut Context<Self>,
16661    ) -> Task<Result<()>> {
16662        let buffer = self.buffer.clone();
16663        let buffers = buffer.read(cx).all_buffers();
16664        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16665        let apply_action = project.update(cx, |project, cx| {
16666            project.apply_code_action_kind(buffers, kind, true, cx)
16667        });
16668        cx.spawn_in(window, async move |_, cx| {
16669            let transaction = futures::select_biased! {
16670                () = timeout => {
16671                    log::warn!("timed out waiting for executing code action");
16672                    None
16673                }
16674                transaction = apply_action.log_err().fuse() => transaction,
16675            };
16676            buffer
16677                .update(cx, |buffer, cx| {
16678                    // check if we need this
16679                    if let Some(transaction) = transaction
16680                        && !buffer.is_singleton()
16681                    {
16682                        buffer.push_transaction(&transaction.0, cx);
16683                    }
16684                    cx.notify();
16685                })
16686                .ok();
16687            Ok(())
16688        })
16689    }
16690
16691    pub fn restart_language_server(
16692        &mut self,
16693        _: &RestartLanguageServer,
16694        _: &mut Window,
16695        cx: &mut Context<Self>,
16696    ) {
16697        if let Some(project) = self.project.clone() {
16698            self.buffer.update(cx, |multi_buffer, cx| {
16699                project.update(cx, |project, cx| {
16700                    project.restart_language_servers_for_buffers(
16701                        multi_buffer.all_buffers().into_iter().collect(),
16702                        HashSet::default(),
16703                        cx,
16704                    );
16705                });
16706            })
16707        }
16708    }
16709
16710    pub fn stop_language_server(
16711        &mut self,
16712        _: &StopLanguageServer,
16713        _: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) {
16716        if let Some(project) = self.project.clone() {
16717            self.buffer.update(cx, |multi_buffer, cx| {
16718                project.update(cx, |project, cx| {
16719                    project.stop_language_servers_for_buffers(
16720                        multi_buffer.all_buffers().into_iter().collect(),
16721                        HashSet::default(),
16722                        cx,
16723                    );
16724                    cx.emit(project::Event::RefreshInlayHints);
16725                });
16726            });
16727        }
16728    }
16729
16730    fn cancel_language_server_work(
16731        workspace: &mut Workspace,
16732        _: &actions::CancelLanguageServerWork,
16733        _: &mut Window,
16734        cx: &mut Context<Workspace>,
16735    ) {
16736        let project = workspace.project();
16737        let buffers = workspace
16738            .active_item(cx)
16739            .and_then(|item| item.act_as::<Editor>(cx))
16740            .map_or(HashSet::default(), |editor| {
16741                editor.read(cx).buffer.read(cx).all_buffers()
16742            });
16743        project.update(cx, |project, cx| {
16744            project.cancel_language_server_work_for_buffers(buffers, cx);
16745        });
16746    }
16747
16748    fn show_character_palette(
16749        &mut self,
16750        _: &ShowCharacterPalette,
16751        window: &mut Window,
16752        _: &mut Context<Self>,
16753    ) {
16754        window.show_character_palette();
16755    }
16756
16757    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16758        if !self.diagnostics_enabled() {
16759            return;
16760        }
16761
16762        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16763            let buffer = self.buffer.read(cx).snapshot(cx);
16764            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16765            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16766            let is_valid = buffer
16767                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16768                .any(|entry| {
16769                    entry.diagnostic.is_primary
16770                        && !entry.range.is_empty()
16771                        && entry.range.start == primary_range_start
16772                        && entry.diagnostic.message == active_diagnostics.active_message
16773                });
16774
16775            if !is_valid {
16776                self.dismiss_diagnostics(cx);
16777            }
16778        }
16779    }
16780
16781    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16782        match &self.active_diagnostics {
16783            ActiveDiagnostic::Group(group) => Some(group),
16784            _ => None,
16785        }
16786    }
16787
16788    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16789        if !self.diagnostics_enabled() {
16790            return;
16791        }
16792        self.dismiss_diagnostics(cx);
16793        self.active_diagnostics = ActiveDiagnostic::All;
16794    }
16795
16796    fn activate_diagnostics(
16797        &mut self,
16798        buffer_id: BufferId,
16799        diagnostic: DiagnosticEntry<usize>,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) {
16803        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16804            return;
16805        }
16806        self.dismiss_diagnostics(cx);
16807        let snapshot = self.snapshot(window, cx);
16808        let buffer = self.buffer.read(cx).snapshot(cx);
16809        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16810            return;
16811        };
16812
16813        let diagnostic_group = buffer
16814            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16815            .collect::<Vec<_>>();
16816
16817        let blocks =
16818            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16819
16820        let blocks = self.display_map.update(cx, |display_map, cx| {
16821            display_map.insert_blocks(blocks, cx).into_iter().collect()
16822        });
16823        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16824            active_range: buffer.anchor_before(diagnostic.range.start)
16825                ..buffer.anchor_after(diagnostic.range.end),
16826            active_message: diagnostic.diagnostic.message.clone(),
16827            group_id: diagnostic.diagnostic.group_id,
16828            blocks,
16829        });
16830        cx.notify();
16831    }
16832
16833    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16834        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16835            return;
16836        };
16837
16838        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16839        if let ActiveDiagnostic::Group(group) = prev {
16840            self.display_map.update(cx, |display_map, cx| {
16841                display_map.remove_blocks(group.blocks, cx);
16842            });
16843            cx.notify();
16844        }
16845    }
16846
16847    /// Disable inline diagnostics rendering for this editor.
16848    pub fn disable_inline_diagnostics(&mut self) {
16849        self.inline_diagnostics_enabled = false;
16850        self.inline_diagnostics_update = Task::ready(());
16851        self.inline_diagnostics.clear();
16852    }
16853
16854    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16855        self.diagnostics_enabled = false;
16856        self.dismiss_diagnostics(cx);
16857        self.inline_diagnostics_update = Task::ready(());
16858        self.inline_diagnostics.clear();
16859    }
16860
16861    pub fn diagnostics_enabled(&self) -> bool {
16862        self.diagnostics_enabled && self.mode.is_full()
16863    }
16864
16865    pub fn inline_diagnostics_enabled(&self) -> bool {
16866        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16867    }
16868
16869    pub fn show_inline_diagnostics(&self) -> bool {
16870        self.show_inline_diagnostics
16871    }
16872
16873    pub fn toggle_inline_diagnostics(
16874        &mut self,
16875        _: &ToggleInlineDiagnostics,
16876        window: &mut Window,
16877        cx: &mut Context<Editor>,
16878    ) {
16879        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16880        self.refresh_inline_diagnostics(false, window, cx);
16881    }
16882
16883    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16884        self.diagnostics_max_severity = severity;
16885        self.display_map.update(cx, |display_map, _| {
16886            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16887        });
16888    }
16889
16890    pub fn toggle_diagnostics(
16891        &mut self,
16892        _: &ToggleDiagnostics,
16893        window: &mut Window,
16894        cx: &mut Context<Editor>,
16895    ) {
16896        if !self.diagnostics_enabled() {
16897            return;
16898        }
16899
16900        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16901            EditorSettings::get_global(cx)
16902                .diagnostics_max_severity
16903                .filter(|severity| severity != &DiagnosticSeverity::Off)
16904                .unwrap_or(DiagnosticSeverity::Hint)
16905        } else {
16906            DiagnosticSeverity::Off
16907        };
16908        self.set_max_diagnostics_severity(new_severity, cx);
16909        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16910            self.active_diagnostics = ActiveDiagnostic::None;
16911            self.inline_diagnostics_update = Task::ready(());
16912            self.inline_diagnostics.clear();
16913        } else {
16914            self.refresh_inline_diagnostics(false, window, cx);
16915        }
16916
16917        cx.notify();
16918    }
16919
16920    pub fn toggle_minimap(
16921        &mut self,
16922        _: &ToggleMinimap,
16923        window: &mut Window,
16924        cx: &mut Context<Editor>,
16925    ) {
16926        if self.supports_minimap(cx) {
16927            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16928        }
16929    }
16930
16931    fn refresh_inline_diagnostics(
16932        &mut self,
16933        debounce: bool,
16934        window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) {
16937        let max_severity = ProjectSettings::get_global(cx)
16938            .diagnostics
16939            .inline
16940            .max_severity
16941            .unwrap_or(self.diagnostics_max_severity);
16942
16943        if !self.inline_diagnostics_enabled()
16944            || !self.show_inline_diagnostics
16945            || max_severity == DiagnosticSeverity::Off
16946        {
16947            self.inline_diagnostics_update = Task::ready(());
16948            self.inline_diagnostics.clear();
16949            return;
16950        }
16951
16952        let debounce_ms = ProjectSettings::get_global(cx)
16953            .diagnostics
16954            .inline
16955            .update_debounce_ms;
16956        let debounce = if debounce && debounce_ms > 0 {
16957            Some(Duration::from_millis(debounce_ms))
16958        } else {
16959            None
16960        };
16961        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16962            if let Some(debounce) = debounce {
16963                cx.background_executor().timer(debounce).await;
16964            }
16965            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16966                editor
16967                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16968                    .ok()
16969            }) else {
16970                return;
16971            };
16972
16973            let new_inline_diagnostics = cx
16974                .background_spawn(async move {
16975                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16976                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16977                        let message = diagnostic_entry
16978                            .diagnostic
16979                            .message
16980                            .split_once('\n')
16981                            .map(|(line, _)| line)
16982                            .map(SharedString::new)
16983                            .unwrap_or_else(|| {
16984                                SharedString::from(diagnostic_entry.diagnostic.message)
16985                            });
16986                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16987                        let (Ok(i) | Err(i)) = inline_diagnostics
16988                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16989                        inline_diagnostics.insert(
16990                            i,
16991                            (
16992                                start_anchor,
16993                                InlineDiagnostic {
16994                                    message,
16995                                    group_id: diagnostic_entry.diagnostic.group_id,
16996                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16997                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16998                                    severity: diagnostic_entry.diagnostic.severity,
16999                                },
17000                            ),
17001                        );
17002                    }
17003                    inline_diagnostics
17004                })
17005                .await;
17006
17007            editor
17008                .update(cx, |editor, cx| {
17009                    editor.inline_diagnostics = new_inline_diagnostics;
17010                    cx.notify();
17011                })
17012                .ok();
17013        });
17014    }
17015
17016    fn pull_diagnostics(
17017        &mut self,
17018        buffer_id: Option<BufferId>,
17019        window: &Window,
17020        cx: &mut Context<Self>,
17021    ) -> Option<()> {
17022        if !self.mode().is_full() {
17023            return None;
17024        }
17025        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17026            .diagnostics
17027            .lsp_pull_diagnostics;
17028        if !pull_diagnostics_settings.enabled {
17029            return None;
17030        }
17031        let project = self.project()?.downgrade();
17032        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17033        let mut buffers = self.buffer.read(cx).all_buffers();
17034        if let Some(buffer_id) = buffer_id {
17035            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17036        }
17037
17038        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17039            cx.background_executor().timer(debounce).await;
17040
17041            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17042                buffers
17043                    .into_iter()
17044                    .filter_map(|buffer| {
17045                        project
17046                            .update(cx, |project, cx| {
17047                                project.lsp_store().update(cx, |lsp_store, cx| {
17048                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17049                                })
17050                            })
17051                            .ok()
17052                    })
17053                    .collect::<FuturesUnordered<_>>()
17054            }) else {
17055                return;
17056            };
17057
17058            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17059                match pull_task {
17060                    Ok(()) => {
17061                        if editor
17062                            .update_in(cx, |editor, window, cx| {
17063                                editor.update_diagnostics_state(window, cx);
17064                            })
17065                            .is_err()
17066                        {
17067                            return;
17068                        }
17069                    }
17070                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17071                }
17072            }
17073        });
17074
17075        Some(())
17076    }
17077
17078    pub fn set_selections_from_remote(
17079        &mut self,
17080        selections: Vec<Selection<Anchor>>,
17081        pending_selection: Option<Selection<Anchor>>,
17082        window: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) {
17085        let old_cursor_position = self.selections.newest_anchor().head();
17086        self.selections.change_with(cx, |s| {
17087            s.select_anchors(selections);
17088            if let Some(pending_selection) = pending_selection {
17089                s.set_pending(pending_selection, SelectMode::Character);
17090            } else {
17091                s.clear_pending();
17092            }
17093        });
17094        self.selections_did_change(
17095            false,
17096            &old_cursor_position,
17097            SelectionEffects::default(),
17098            window,
17099            cx,
17100        );
17101    }
17102
17103    pub fn transact(
17104        &mut self,
17105        window: &mut Window,
17106        cx: &mut Context<Self>,
17107        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17108    ) -> Option<TransactionId> {
17109        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17110            this.start_transaction_at(Instant::now(), window, cx);
17111            update(this, window, cx);
17112            this.end_transaction_at(Instant::now(), cx)
17113        })
17114    }
17115
17116    pub fn start_transaction_at(
17117        &mut self,
17118        now: Instant,
17119        window: &mut Window,
17120        cx: &mut Context<Self>,
17121    ) -> Option<TransactionId> {
17122        self.end_selection(window, cx);
17123        if let Some(tx_id) = self
17124            .buffer
17125            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17126        {
17127            self.selection_history
17128                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17129            cx.emit(EditorEvent::TransactionBegun {
17130                transaction_id: tx_id,
17131            });
17132            Some(tx_id)
17133        } else {
17134            None
17135        }
17136    }
17137
17138    pub fn end_transaction_at(
17139        &mut self,
17140        now: Instant,
17141        cx: &mut Context<Self>,
17142    ) -> Option<TransactionId> {
17143        if let Some(transaction_id) = self
17144            .buffer
17145            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17146        {
17147            if let Some((_, end_selections)) =
17148                self.selection_history.transaction_mut(transaction_id)
17149            {
17150                *end_selections = Some(self.selections.disjoint_anchors());
17151            } else {
17152                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17153            }
17154
17155            cx.emit(EditorEvent::Edited { transaction_id });
17156            Some(transaction_id)
17157        } else {
17158            None
17159        }
17160    }
17161
17162    pub fn modify_transaction_selection_history(
17163        &mut self,
17164        transaction_id: TransactionId,
17165        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17166    ) -> bool {
17167        self.selection_history
17168            .transaction_mut(transaction_id)
17169            .map(modify)
17170            .is_some()
17171    }
17172
17173    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17174        if self.selection_mark_mode {
17175            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17176                s.move_with(|_, sel| {
17177                    sel.collapse_to(sel.head(), SelectionGoal::None);
17178                });
17179            })
17180        }
17181        self.selection_mark_mode = true;
17182        cx.notify();
17183    }
17184
17185    pub fn swap_selection_ends(
17186        &mut self,
17187        _: &actions::SwapSelectionEnds,
17188        window: &mut Window,
17189        cx: &mut Context<Self>,
17190    ) {
17191        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17192            s.move_with(|_, sel| {
17193                if sel.start != sel.end {
17194                    sel.reversed = !sel.reversed
17195                }
17196            });
17197        });
17198        self.request_autoscroll(Autoscroll::newest(), cx);
17199        cx.notify();
17200    }
17201
17202    pub fn toggle_focus(
17203        workspace: &mut Workspace,
17204        _: &actions::ToggleFocus,
17205        window: &mut Window,
17206        cx: &mut Context<Workspace>,
17207    ) {
17208        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17209            return;
17210        };
17211        workspace.activate_item(&item, true, true, window, cx);
17212    }
17213
17214    pub fn toggle_fold(
17215        &mut self,
17216        _: &actions::ToggleFold,
17217        window: &mut Window,
17218        cx: &mut Context<Self>,
17219    ) {
17220        if self.is_singleton(cx) {
17221            let selection = self.selections.newest::<Point>(cx);
17222
17223            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17224            let range = if selection.is_empty() {
17225                let point = selection.head().to_display_point(&display_map);
17226                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17227                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17228                    .to_point(&display_map);
17229                start..end
17230            } else {
17231                selection.range()
17232            };
17233            if display_map.folds_in_range(range).next().is_some() {
17234                self.unfold_lines(&Default::default(), window, cx)
17235            } else {
17236                self.fold(&Default::default(), window, cx)
17237            }
17238        } else {
17239            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17240            let buffer_ids: HashSet<_> = self
17241                .selections
17242                .disjoint_anchor_ranges()
17243                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17244                .collect();
17245
17246            let should_unfold = buffer_ids
17247                .iter()
17248                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17249
17250            for buffer_id in buffer_ids {
17251                if should_unfold {
17252                    self.unfold_buffer(buffer_id, cx);
17253                } else {
17254                    self.fold_buffer(buffer_id, cx);
17255                }
17256            }
17257        }
17258    }
17259
17260    pub fn toggle_fold_recursive(
17261        &mut self,
17262        _: &actions::ToggleFoldRecursive,
17263        window: &mut Window,
17264        cx: &mut Context<Self>,
17265    ) {
17266        let selection = self.selections.newest::<Point>(cx);
17267
17268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17269        let range = if selection.is_empty() {
17270            let point = selection.head().to_display_point(&display_map);
17271            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17272            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17273                .to_point(&display_map);
17274            start..end
17275        } else {
17276            selection.range()
17277        };
17278        if display_map.folds_in_range(range).next().is_some() {
17279            self.unfold_recursive(&Default::default(), window, cx)
17280        } else {
17281            self.fold_recursive(&Default::default(), window, cx)
17282        }
17283    }
17284
17285    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17286        if self.is_singleton(cx) {
17287            let mut to_fold = Vec::new();
17288            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17289            let selections = self.selections.all_adjusted(cx);
17290
17291            for selection in selections {
17292                let range = selection.range().sorted();
17293                let buffer_start_row = range.start.row;
17294
17295                if range.start.row != range.end.row {
17296                    let mut found = false;
17297                    let mut row = range.start.row;
17298                    while row <= range.end.row {
17299                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17300                        {
17301                            found = true;
17302                            row = crease.range().end.row + 1;
17303                            to_fold.push(crease);
17304                        } else {
17305                            row += 1
17306                        }
17307                    }
17308                    if found {
17309                        continue;
17310                    }
17311                }
17312
17313                for row in (0..=range.start.row).rev() {
17314                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17315                        && crease.range().end.row >= buffer_start_row
17316                    {
17317                        to_fold.push(crease);
17318                        if row <= range.start.row {
17319                            break;
17320                        }
17321                    }
17322                }
17323            }
17324
17325            self.fold_creases(to_fold, true, window, cx);
17326        } else {
17327            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17328            let buffer_ids = self
17329                .selections
17330                .disjoint_anchor_ranges()
17331                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17332                .collect::<HashSet<_>>();
17333            for buffer_id in buffer_ids {
17334                self.fold_buffer(buffer_id, cx);
17335            }
17336        }
17337    }
17338
17339    pub fn toggle_fold_all(
17340        &mut self,
17341        _: &actions::ToggleFoldAll,
17342        window: &mut Window,
17343        cx: &mut Context<Self>,
17344    ) {
17345        if self.buffer.read(cx).is_singleton() {
17346            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17347            let has_folds = display_map
17348                .folds_in_range(0..display_map.buffer_snapshot.len())
17349                .next()
17350                .is_some();
17351
17352            if has_folds {
17353                self.unfold_all(&actions::UnfoldAll, window, cx);
17354            } else {
17355                self.fold_all(&actions::FoldAll, window, cx);
17356            }
17357        } else {
17358            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17359            let should_unfold = buffer_ids
17360                .iter()
17361                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17362
17363            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17364                editor
17365                    .update_in(cx, |editor, _, cx| {
17366                        for buffer_id in buffer_ids {
17367                            if should_unfold {
17368                                editor.unfold_buffer(buffer_id, cx);
17369                            } else {
17370                                editor.fold_buffer(buffer_id, cx);
17371                            }
17372                        }
17373                    })
17374                    .ok();
17375            });
17376        }
17377    }
17378
17379    fn fold_at_level(
17380        &mut self,
17381        fold_at: &FoldAtLevel,
17382        window: &mut Window,
17383        cx: &mut Context<Self>,
17384    ) {
17385        if !self.buffer.read(cx).is_singleton() {
17386            return;
17387        }
17388
17389        let fold_at_level = fold_at.0;
17390        let snapshot = self.buffer.read(cx).snapshot(cx);
17391        let mut to_fold = Vec::new();
17392        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17393
17394        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17395            while start_row < end_row {
17396                match self
17397                    .snapshot(window, cx)
17398                    .crease_for_buffer_row(MultiBufferRow(start_row))
17399                {
17400                    Some(crease) => {
17401                        let nested_start_row = crease.range().start.row + 1;
17402                        let nested_end_row = crease.range().end.row;
17403
17404                        if current_level < fold_at_level {
17405                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17406                        } else if current_level == fold_at_level {
17407                            to_fold.push(crease);
17408                        }
17409
17410                        start_row = nested_end_row + 1;
17411                    }
17412                    None => start_row += 1,
17413                }
17414            }
17415        }
17416
17417        self.fold_creases(to_fold, true, window, cx);
17418    }
17419
17420    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17421        if self.buffer.read(cx).is_singleton() {
17422            let mut fold_ranges = Vec::new();
17423            let snapshot = self.buffer.read(cx).snapshot(cx);
17424
17425            for row in 0..snapshot.max_row().0 {
17426                if let Some(foldable_range) = self
17427                    .snapshot(window, cx)
17428                    .crease_for_buffer_row(MultiBufferRow(row))
17429                {
17430                    fold_ranges.push(foldable_range);
17431                }
17432            }
17433
17434            self.fold_creases(fold_ranges, true, window, cx);
17435        } else {
17436            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17437                editor
17438                    .update_in(cx, |editor, _, cx| {
17439                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17440                            editor.fold_buffer(buffer_id, cx);
17441                        }
17442                    })
17443                    .ok();
17444            });
17445        }
17446    }
17447
17448    pub fn fold_function_bodies(
17449        &mut self,
17450        _: &actions::FoldFunctionBodies,
17451        window: &mut Window,
17452        cx: &mut Context<Self>,
17453    ) {
17454        let snapshot = self.buffer.read(cx).snapshot(cx);
17455
17456        let ranges = snapshot
17457            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17458            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17459            .collect::<Vec<_>>();
17460
17461        let creases = ranges
17462            .into_iter()
17463            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17464            .collect();
17465
17466        self.fold_creases(creases, true, window, cx);
17467    }
17468
17469    pub fn fold_recursive(
17470        &mut self,
17471        _: &actions::FoldRecursive,
17472        window: &mut Window,
17473        cx: &mut Context<Self>,
17474    ) {
17475        let mut to_fold = Vec::new();
17476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17477        let selections = self.selections.all_adjusted(cx);
17478
17479        for selection in selections {
17480            let range = selection.range().sorted();
17481            let buffer_start_row = range.start.row;
17482
17483            if range.start.row != range.end.row {
17484                let mut found = false;
17485                for row in range.start.row..=range.end.row {
17486                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17487                        found = true;
17488                        to_fold.push(crease);
17489                    }
17490                }
17491                if found {
17492                    continue;
17493                }
17494            }
17495
17496            for row in (0..=range.start.row).rev() {
17497                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17498                    if crease.range().end.row >= buffer_start_row {
17499                        to_fold.push(crease);
17500                    } else {
17501                        break;
17502                    }
17503                }
17504            }
17505        }
17506
17507        self.fold_creases(to_fold, true, window, cx);
17508    }
17509
17510    pub fn fold_at(
17511        &mut self,
17512        buffer_row: MultiBufferRow,
17513        window: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) {
17516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17517
17518        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17519            let autoscroll = self
17520                .selections
17521                .all::<Point>(cx)
17522                .iter()
17523                .any(|selection| crease.range().overlaps(&selection.range()));
17524
17525            self.fold_creases(vec![crease], autoscroll, window, cx);
17526        }
17527    }
17528
17529    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17530        if self.is_singleton(cx) {
17531            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17532            let buffer = &display_map.buffer_snapshot;
17533            let selections = self.selections.all::<Point>(cx);
17534            let ranges = selections
17535                .iter()
17536                .map(|s| {
17537                    let range = s.display_range(&display_map).sorted();
17538                    let mut start = range.start.to_point(&display_map);
17539                    let mut end = range.end.to_point(&display_map);
17540                    start.column = 0;
17541                    end.column = buffer.line_len(MultiBufferRow(end.row));
17542                    start..end
17543                })
17544                .collect::<Vec<_>>();
17545
17546            self.unfold_ranges(&ranges, true, true, cx);
17547        } else {
17548            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17549            let buffer_ids = self
17550                .selections
17551                .disjoint_anchor_ranges()
17552                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17553                .collect::<HashSet<_>>();
17554            for buffer_id in buffer_ids {
17555                self.unfold_buffer(buffer_id, cx);
17556            }
17557        }
17558    }
17559
17560    pub fn unfold_recursive(
17561        &mut self,
17562        _: &UnfoldRecursive,
17563        _window: &mut Window,
17564        cx: &mut Context<Self>,
17565    ) {
17566        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17567        let selections = self.selections.all::<Point>(cx);
17568        let ranges = selections
17569            .iter()
17570            .map(|s| {
17571                let mut range = s.display_range(&display_map).sorted();
17572                *range.start.column_mut() = 0;
17573                *range.end.column_mut() = display_map.line_len(range.end.row());
17574                let start = range.start.to_point(&display_map);
17575                let end = range.end.to_point(&display_map);
17576                start..end
17577            })
17578            .collect::<Vec<_>>();
17579
17580        self.unfold_ranges(&ranges, true, true, cx);
17581    }
17582
17583    pub fn unfold_at(
17584        &mut self,
17585        buffer_row: MultiBufferRow,
17586        _window: &mut Window,
17587        cx: &mut Context<Self>,
17588    ) {
17589        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17590
17591        let intersection_range = Point::new(buffer_row.0, 0)
17592            ..Point::new(
17593                buffer_row.0,
17594                display_map.buffer_snapshot.line_len(buffer_row),
17595            );
17596
17597        let autoscroll = self
17598            .selections
17599            .all::<Point>(cx)
17600            .iter()
17601            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17602
17603        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17604    }
17605
17606    pub fn unfold_all(
17607        &mut self,
17608        _: &actions::UnfoldAll,
17609        _window: &mut Window,
17610        cx: &mut Context<Self>,
17611    ) {
17612        if self.buffer.read(cx).is_singleton() {
17613            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17614            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17615        } else {
17616            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17617                editor
17618                    .update(cx, |editor, cx| {
17619                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17620                            editor.unfold_buffer(buffer_id, cx);
17621                        }
17622                    })
17623                    .ok();
17624            });
17625        }
17626    }
17627
17628    pub fn fold_selected_ranges(
17629        &mut self,
17630        _: &FoldSelectedRanges,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        let selections = self.selections.all_adjusted(cx);
17635        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17636        let ranges = selections
17637            .into_iter()
17638            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17639            .collect::<Vec<_>>();
17640        self.fold_creases(ranges, true, window, cx);
17641    }
17642
17643    pub fn fold_ranges<T: ToOffset + Clone>(
17644        &mut self,
17645        ranges: Vec<Range<T>>,
17646        auto_scroll: bool,
17647        window: &mut Window,
17648        cx: &mut Context<Self>,
17649    ) {
17650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17651        let ranges = ranges
17652            .into_iter()
17653            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17654            .collect::<Vec<_>>();
17655        self.fold_creases(ranges, auto_scroll, window, cx);
17656    }
17657
17658    pub fn fold_creases<T: ToOffset + Clone>(
17659        &mut self,
17660        creases: Vec<Crease<T>>,
17661        auto_scroll: bool,
17662        _window: &mut Window,
17663        cx: &mut Context<Self>,
17664    ) {
17665        if creases.is_empty() {
17666            return;
17667        }
17668
17669        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17670
17671        if auto_scroll {
17672            self.request_autoscroll(Autoscroll::fit(), cx);
17673        }
17674
17675        cx.notify();
17676
17677        self.scrollbar_marker_state.dirty = true;
17678        self.folds_did_change(cx);
17679    }
17680
17681    /// Removes any folds whose ranges intersect any of the given ranges.
17682    pub fn unfold_ranges<T: ToOffset + Clone>(
17683        &mut self,
17684        ranges: &[Range<T>],
17685        inclusive: bool,
17686        auto_scroll: bool,
17687        cx: &mut Context<Self>,
17688    ) {
17689        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17690            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17691        });
17692        self.folds_did_change(cx);
17693    }
17694
17695    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17696        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17697            return;
17698        }
17699        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17700        self.display_map.update(cx, |display_map, cx| {
17701            display_map.fold_buffers([buffer_id], cx)
17702        });
17703        cx.emit(EditorEvent::BufferFoldToggled {
17704            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17705            folded: true,
17706        });
17707        cx.notify();
17708    }
17709
17710    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17711        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17712            return;
17713        }
17714        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17715        self.display_map.update(cx, |display_map, cx| {
17716            display_map.unfold_buffers([buffer_id], cx);
17717        });
17718        cx.emit(EditorEvent::BufferFoldToggled {
17719            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17720            folded: false,
17721        });
17722        cx.notify();
17723    }
17724
17725    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17726        self.display_map.read(cx).is_buffer_folded(buffer)
17727    }
17728
17729    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17730        self.display_map.read(cx).folded_buffers()
17731    }
17732
17733    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17734        self.display_map.update(cx, |display_map, cx| {
17735            display_map.disable_header_for_buffer(buffer_id, cx);
17736        });
17737        cx.notify();
17738    }
17739
17740    /// Removes any folds with the given ranges.
17741    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17742        &mut self,
17743        ranges: &[Range<T>],
17744        type_id: TypeId,
17745        auto_scroll: bool,
17746        cx: &mut Context<Self>,
17747    ) {
17748        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17749            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17750        });
17751        self.folds_did_change(cx);
17752    }
17753
17754    fn remove_folds_with<T: ToOffset + Clone>(
17755        &mut self,
17756        ranges: &[Range<T>],
17757        auto_scroll: bool,
17758        cx: &mut Context<Self>,
17759        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17760    ) {
17761        if ranges.is_empty() {
17762            return;
17763        }
17764
17765        let mut buffers_affected = HashSet::default();
17766        let multi_buffer = self.buffer().read(cx);
17767        for range in ranges {
17768            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17769                buffers_affected.insert(buffer.read(cx).remote_id());
17770            };
17771        }
17772
17773        self.display_map.update(cx, update);
17774
17775        if auto_scroll {
17776            self.request_autoscroll(Autoscroll::fit(), cx);
17777        }
17778
17779        cx.notify();
17780        self.scrollbar_marker_state.dirty = true;
17781        self.active_indent_guides_state.dirty = true;
17782    }
17783
17784    pub fn update_renderer_widths(
17785        &mut self,
17786        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17787        cx: &mut Context<Self>,
17788    ) -> bool {
17789        self.display_map
17790            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17791    }
17792
17793    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17794        self.display_map.read(cx).fold_placeholder.clone()
17795    }
17796
17797    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17798        self.buffer.update(cx, |buffer, cx| {
17799            buffer.set_all_diff_hunks_expanded(cx);
17800        });
17801    }
17802
17803    pub fn expand_all_diff_hunks(
17804        &mut self,
17805        _: &ExpandAllDiffHunks,
17806        _window: &mut Window,
17807        cx: &mut Context<Self>,
17808    ) {
17809        self.buffer.update(cx, |buffer, cx| {
17810            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17811        });
17812    }
17813
17814    pub fn toggle_selected_diff_hunks(
17815        &mut self,
17816        _: &ToggleSelectedDiffHunks,
17817        _window: &mut Window,
17818        cx: &mut Context<Self>,
17819    ) {
17820        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17821        self.toggle_diff_hunks_in_ranges(ranges, cx);
17822    }
17823
17824    pub fn diff_hunks_in_ranges<'a>(
17825        &'a self,
17826        ranges: &'a [Range<Anchor>],
17827        buffer: &'a MultiBufferSnapshot,
17828    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17829        ranges.iter().flat_map(move |range| {
17830            let end_excerpt_id = range.end.excerpt_id;
17831            let range = range.to_point(buffer);
17832            let mut peek_end = range.end;
17833            if range.end.row < buffer.max_row().0 {
17834                peek_end = Point::new(range.end.row + 1, 0);
17835            }
17836            buffer
17837                .diff_hunks_in_range(range.start..peek_end)
17838                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17839        })
17840    }
17841
17842    pub fn has_stageable_diff_hunks_in_ranges(
17843        &self,
17844        ranges: &[Range<Anchor>],
17845        snapshot: &MultiBufferSnapshot,
17846    ) -> bool {
17847        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17848        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17849    }
17850
17851    pub fn toggle_staged_selected_diff_hunks(
17852        &mut self,
17853        _: &::git::ToggleStaged,
17854        _: &mut Window,
17855        cx: &mut Context<Self>,
17856    ) {
17857        let snapshot = self.buffer.read(cx).snapshot(cx);
17858        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17859        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17860        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17861    }
17862
17863    pub fn set_render_diff_hunk_controls(
17864        &mut self,
17865        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17866        cx: &mut Context<Self>,
17867    ) {
17868        self.render_diff_hunk_controls = render_diff_hunk_controls;
17869        cx.notify();
17870    }
17871
17872    pub fn stage_and_next(
17873        &mut self,
17874        _: &::git::StageAndNext,
17875        window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        self.do_stage_or_unstage_and_next(true, window, cx);
17879    }
17880
17881    pub fn unstage_and_next(
17882        &mut self,
17883        _: &::git::UnstageAndNext,
17884        window: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        self.do_stage_or_unstage_and_next(false, window, cx);
17888    }
17889
17890    pub fn stage_or_unstage_diff_hunks(
17891        &mut self,
17892        stage: bool,
17893        ranges: Vec<Range<Anchor>>,
17894        cx: &mut Context<Self>,
17895    ) {
17896        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17897        cx.spawn(async move |this, cx| {
17898            task.await?;
17899            this.update(cx, |this, cx| {
17900                let snapshot = this.buffer.read(cx).snapshot(cx);
17901                let chunk_by = this
17902                    .diff_hunks_in_ranges(&ranges, &snapshot)
17903                    .chunk_by(|hunk| hunk.buffer_id);
17904                for (buffer_id, hunks) in &chunk_by {
17905                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17906                }
17907            })
17908        })
17909        .detach_and_log_err(cx);
17910    }
17911
17912    fn save_buffers_for_ranges_if_needed(
17913        &mut self,
17914        ranges: &[Range<Anchor>],
17915        cx: &mut Context<Editor>,
17916    ) -> Task<Result<()>> {
17917        let multibuffer = self.buffer.read(cx);
17918        let snapshot = multibuffer.read(cx);
17919        let buffer_ids: HashSet<_> = ranges
17920            .iter()
17921            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17922            .collect();
17923        drop(snapshot);
17924
17925        let mut buffers = HashSet::default();
17926        for buffer_id in buffer_ids {
17927            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17928                let buffer = buffer_entity.read(cx);
17929                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17930                {
17931                    buffers.insert(buffer_entity);
17932                }
17933            }
17934        }
17935
17936        if let Some(project) = &self.project {
17937            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17938        } else {
17939            Task::ready(Ok(()))
17940        }
17941    }
17942
17943    fn do_stage_or_unstage_and_next(
17944        &mut self,
17945        stage: bool,
17946        window: &mut Window,
17947        cx: &mut Context<Self>,
17948    ) {
17949        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17950
17951        if ranges.iter().any(|range| range.start != range.end) {
17952            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17953            return;
17954        }
17955
17956        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17957        let snapshot = self.snapshot(window, cx);
17958        let position = self.selections.newest::<Point>(cx).head();
17959        let mut row = snapshot
17960            .buffer_snapshot
17961            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17962            .find(|hunk| hunk.row_range.start.0 > position.row)
17963            .map(|hunk| hunk.row_range.start);
17964
17965        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17966        // Outside of the project diff editor, wrap around to the beginning.
17967        if !all_diff_hunks_expanded {
17968            row = row.or_else(|| {
17969                snapshot
17970                    .buffer_snapshot
17971                    .diff_hunks_in_range(Point::zero()..position)
17972                    .find(|hunk| hunk.row_range.end.0 < position.row)
17973                    .map(|hunk| hunk.row_range.start)
17974            });
17975        }
17976
17977        if let Some(row) = row {
17978            let destination = Point::new(row.0, 0);
17979            let autoscroll = Autoscroll::center();
17980
17981            self.unfold_ranges(&[destination..destination], false, false, cx);
17982            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17983                s.select_ranges([destination..destination]);
17984            });
17985        }
17986    }
17987
17988    fn do_stage_or_unstage(
17989        &self,
17990        stage: bool,
17991        buffer_id: BufferId,
17992        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17993        cx: &mut App,
17994    ) -> Option<()> {
17995        let project = self.project()?;
17996        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17997        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17998        let buffer_snapshot = buffer.read(cx).snapshot();
17999        let file_exists = buffer_snapshot
18000            .file()
18001            .is_some_and(|file| file.disk_state().exists());
18002        diff.update(cx, |diff, cx| {
18003            diff.stage_or_unstage_hunks(
18004                stage,
18005                &hunks
18006                    .map(|hunk| buffer_diff::DiffHunk {
18007                        buffer_range: hunk.buffer_range,
18008                        diff_base_byte_range: hunk.diff_base_byte_range,
18009                        secondary_status: hunk.secondary_status,
18010                        range: Point::zero()..Point::zero(), // unused
18011                    })
18012                    .collect::<Vec<_>>(),
18013                &buffer_snapshot,
18014                file_exists,
18015                cx,
18016            )
18017        });
18018        None
18019    }
18020
18021    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18022        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18023        self.buffer
18024            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18025    }
18026
18027    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18028        self.buffer.update(cx, |buffer, cx| {
18029            let ranges = vec![Anchor::min()..Anchor::max()];
18030            if !buffer.all_diff_hunks_expanded()
18031                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18032            {
18033                buffer.collapse_diff_hunks(ranges, cx);
18034                true
18035            } else {
18036                false
18037            }
18038        })
18039    }
18040
18041    fn toggle_diff_hunks_in_ranges(
18042        &mut self,
18043        ranges: Vec<Range<Anchor>>,
18044        cx: &mut Context<Editor>,
18045    ) {
18046        self.buffer.update(cx, |buffer, cx| {
18047            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18048            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18049        })
18050    }
18051
18052    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18053        self.buffer.update(cx, |buffer, cx| {
18054            let snapshot = buffer.snapshot(cx);
18055            let excerpt_id = range.end.excerpt_id;
18056            let point_range = range.to_point(&snapshot);
18057            let expand = !buffer.single_hunk_is_expanded(range, cx);
18058            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18059        })
18060    }
18061
18062    pub(crate) fn apply_all_diff_hunks(
18063        &mut self,
18064        _: &ApplyAllDiffHunks,
18065        window: &mut Window,
18066        cx: &mut Context<Self>,
18067    ) {
18068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18069
18070        let buffers = self.buffer.read(cx).all_buffers();
18071        for branch_buffer in buffers {
18072            branch_buffer.update(cx, |branch_buffer, cx| {
18073                branch_buffer.merge_into_base(Vec::new(), cx);
18074            });
18075        }
18076
18077        if let Some(project) = self.project.clone() {
18078            self.save(
18079                SaveOptions {
18080                    format: true,
18081                    autosave: false,
18082                },
18083                project,
18084                window,
18085                cx,
18086            )
18087            .detach_and_log_err(cx);
18088        }
18089    }
18090
18091    pub(crate) fn apply_selected_diff_hunks(
18092        &mut self,
18093        _: &ApplyDiffHunk,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18098        let snapshot = self.snapshot(window, cx);
18099        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18100        let mut ranges_by_buffer = HashMap::default();
18101        self.transact(window, cx, |editor, _window, cx| {
18102            for hunk in hunks {
18103                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18104                    ranges_by_buffer
18105                        .entry(buffer.clone())
18106                        .or_insert_with(Vec::new)
18107                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18108                }
18109            }
18110
18111            for (buffer, ranges) in ranges_by_buffer {
18112                buffer.update(cx, |buffer, cx| {
18113                    buffer.merge_into_base(ranges, cx);
18114                });
18115            }
18116        });
18117
18118        if let Some(project) = self.project.clone() {
18119            self.save(
18120                SaveOptions {
18121                    format: true,
18122                    autosave: false,
18123                },
18124                project,
18125                window,
18126                cx,
18127            )
18128            .detach_and_log_err(cx);
18129        }
18130    }
18131
18132    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18133        if hovered != self.gutter_hovered {
18134            self.gutter_hovered = hovered;
18135            cx.notify();
18136        }
18137    }
18138
18139    pub fn insert_blocks(
18140        &mut self,
18141        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18142        autoscroll: Option<Autoscroll>,
18143        cx: &mut Context<Self>,
18144    ) -> Vec<CustomBlockId> {
18145        let blocks = self
18146            .display_map
18147            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18148        if let Some(autoscroll) = autoscroll {
18149            self.request_autoscroll(autoscroll, cx);
18150        }
18151        cx.notify();
18152        blocks
18153    }
18154
18155    pub fn resize_blocks(
18156        &mut self,
18157        heights: HashMap<CustomBlockId, u32>,
18158        autoscroll: Option<Autoscroll>,
18159        cx: &mut Context<Self>,
18160    ) {
18161        self.display_map
18162            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18163        if let Some(autoscroll) = autoscroll {
18164            self.request_autoscroll(autoscroll, cx);
18165        }
18166        cx.notify();
18167    }
18168
18169    pub fn replace_blocks(
18170        &mut self,
18171        renderers: HashMap<CustomBlockId, RenderBlock>,
18172        autoscroll: Option<Autoscroll>,
18173        cx: &mut Context<Self>,
18174    ) {
18175        self.display_map
18176            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18177        if let Some(autoscroll) = autoscroll {
18178            self.request_autoscroll(autoscroll, cx);
18179        }
18180        cx.notify();
18181    }
18182
18183    pub fn remove_blocks(
18184        &mut self,
18185        block_ids: HashSet<CustomBlockId>,
18186        autoscroll: Option<Autoscroll>,
18187        cx: &mut Context<Self>,
18188    ) {
18189        self.display_map.update(cx, |display_map, cx| {
18190            display_map.remove_blocks(block_ids, cx)
18191        });
18192        if let Some(autoscroll) = autoscroll {
18193            self.request_autoscroll(autoscroll, cx);
18194        }
18195        cx.notify();
18196    }
18197
18198    pub fn row_for_block(
18199        &self,
18200        block_id: CustomBlockId,
18201        cx: &mut Context<Self>,
18202    ) -> Option<DisplayRow> {
18203        self.display_map
18204            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18205    }
18206
18207    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18208        self.focused_block = Some(focused_block);
18209    }
18210
18211    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18212        self.focused_block.take()
18213    }
18214
18215    pub fn insert_creases(
18216        &mut self,
18217        creases: impl IntoIterator<Item = Crease<Anchor>>,
18218        cx: &mut Context<Self>,
18219    ) -> Vec<CreaseId> {
18220        self.display_map
18221            .update(cx, |map, cx| map.insert_creases(creases, cx))
18222    }
18223
18224    pub fn remove_creases(
18225        &mut self,
18226        ids: impl IntoIterator<Item = CreaseId>,
18227        cx: &mut Context<Self>,
18228    ) -> Vec<(CreaseId, Range<Anchor>)> {
18229        self.display_map
18230            .update(cx, |map, cx| map.remove_creases(ids, cx))
18231    }
18232
18233    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18234        self.display_map
18235            .update(cx, |map, cx| map.snapshot(cx))
18236            .longest_row()
18237    }
18238
18239    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18240        self.display_map
18241            .update(cx, |map, cx| map.snapshot(cx))
18242            .max_point()
18243    }
18244
18245    pub fn text(&self, cx: &App) -> String {
18246        self.buffer.read(cx).read(cx).text()
18247    }
18248
18249    pub fn is_empty(&self, cx: &App) -> bool {
18250        self.buffer.read(cx).read(cx).is_empty()
18251    }
18252
18253    pub fn text_option(&self, cx: &App) -> Option<String> {
18254        let text = self.text(cx);
18255        let text = text.trim();
18256
18257        if text.is_empty() {
18258            return None;
18259        }
18260
18261        Some(text.to_string())
18262    }
18263
18264    pub fn set_text(
18265        &mut self,
18266        text: impl Into<Arc<str>>,
18267        window: &mut Window,
18268        cx: &mut Context<Self>,
18269    ) {
18270        self.transact(window, cx, |this, _, cx| {
18271            this.buffer
18272                .read(cx)
18273                .as_singleton()
18274                .expect("you can only call set_text on editors for singleton buffers")
18275                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18276        });
18277    }
18278
18279    pub fn display_text(&self, cx: &mut App) -> String {
18280        self.display_map
18281            .update(cx, |map, cx| map.snapshot(cx))
18282            .text()
18283    }
18284
18285    fn create_minimap(
18286        &self,
18287        minimap_settings: MinimapSettings,
18288        window: &mut Window,
18289        cx: &mut Context<Self>,
18290    ) -> Option<Entity<Self>> {
18291        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18292            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18293    }
18294
18295    fn initialize_new_minimap(
18296        &self,
18297        minimap_settings: MinimapSettings,
18298        window: &mut Window,
18299        cx: &mut Context<Self>,
18300    ) -> Entity<Self> {
18301        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18302
18303        let mut minimap = Editor::new_internal(
18304            EditorMode::Minimap {
18305                parent: cx.weak_entity(),
18306            },
18307            self.buffer.clone(),
18308            None,
18309            Some(self.display_map.clone()),
18310            window,
18311            cx,
18312        );
18313        minimap.scroll_manager.clone_state(&self.scroll_manager);
18314        minimap.set_text_style_refinement(TextStyleRefinement {
18315            font_size: Some(MINIMAP_FONT_SIZE),
18316            font_weight: Some(MINIMAP_FONT_WEIGHT),
18317            ..Default::default()
18318        });
18319        minimap.update_minimap_configuration(minimap_settings, cx);
18320        cx.new(|_| minimap)
18321    }
18322
18323    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18324        let current_line_highlight = minimap_settings
18325            .current_line_highlight
18326            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18327        self.set_current_line_highlight(Some(current_line_highlight));
18328    }
18329
18330    pub fn minimap(&self) -> Option<&Entity<Self>> {
18331        self.minimap
18332            .as_ref()
18333            .filter(|_| self.minimap_visibility.visible())
18334    }
18335
18336    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18337        let mut wrap_guides = smallvec![];
18338
18339        if self.show_wrap_guides == Some(false) {
18340            return wrap_guides;
18341        }
18342
18343        let settings = self.buffer.read(cx).language_settings(cx);
18344        if settings.show_wrap_guides {
18345            match self.soft_wrap_mode(cx) {
18346                SoftWrap::Column(soft_wrap) => {
18347                    wrap_guides.push((soft_wrap as usize, true));
18348                }
18349                SoftWrap::Bounded(soft_wrap) => {
18350                    wrap_guides.push((soft_wrap as usize, true));
18351                }
18352                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18353            }
18354            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18355        }
18356
18357        wrap_guides
18358    }
18359
18360    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18361        let settings = self.buffer.read(cx).language_settings(cx);
18362        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18363        match mode {
18364            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18365                SoftWrap::None
18366            }
18367            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18368            language_settings::SoftWrap::PreferredLineLength => {
18369                SoftWrap::Column(settings.preferred_line_length)
18370            }
18371            language_settings::SoftWrap::Bounded => {
18372                SoftWrap::Bounded(settings.preferred_line_length)
18373            }
18374        }
18375    }
18376
18377    pub fn set_soft_wrap_mode(
18378        &mut self,
18379        mode: language_settings::SoftWrap,
18380
18381        cx: &mut Context<Self>,
18382    ) {
18383        self.soft_wrap_mode_override = Some(mode);
18384        cx.notify();
18385    }
18386
18387    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18388        self.hard_wrap = hard_wrap;
18389        cx.notify();
18390    }
18391
18392    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18393        self.text_style_refinement = Some(style);
18394    }
18395
18396    /// called by the Element so we know what style we were most recently rendered with.
18397    pub(crate) fn set_style(
18398        &mut self,
18399        style: EditorStyle,
18400        window: &mut Window,
18401        cx: &mut Context<Self>,
18402    ) {
18403        // We intentionally do not inform the display map about the minimap style
18404        // so that wrapping is not recalculated and stays consistent for the editor
18405        // and its linked minimap.
18406        if !self.mode.is_minimap() {
18407            let rem_size = window.rem_size();
18408            self.display_map.update(cx, |map, cx| {
18409                map.set_font(
18410                    style.text.font(),
18411                    style.text.font_size.to_pixels(rem_size),
18412                    cx,
18413                )
18414            });
18415        }
18416        self.style = Some(style);
18417    }
18418
18419    pub fn style(&self) -> Option<&EditorStyle> {
18420        self.style.as_ref()
18421    }
18422
18423    // Called by the element. This method is not designed to be called outside of the editor
18424    // element's layout code because it does not notify when rewrapping is computed synchronously.
18425    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18426        self.display_map
18427            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18428    }
18429
18430    pub fn set_soft_wrap(&mut self) {
18431        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18432    }
18433
18434    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18435        if self.soft_wrap_mode_override.is_some() {
18436            self.soft_wrap_mode_override.take();
18437        } else {
18438            let soft_wrap = match self.soft_wrap_mode(cx) {
18439                SoftWrap::GitDiff => return,
18440                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18441                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18442                    language_settings::SoftWrap::None
18443                }
18444            };
18445            self.soft_wrap_mode_override = Some(soft_wrap);
18446        }
18447        cx.notify();
18448    }
18449
18450    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18451        let Some(workspace) = self.workspace() else {
18452            return;
18453        };
18454        let fs = workspace.read(cx).app_state().fs.clone();
18455        let current_show = TabBarSettings::get_global(cx).show;
18456        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18457            setting.show = Some(!current_show);
18458        });
18459    }
18460
18461    pub fn toggle_indent_guides(
18462        &mut self,
18463        _: &ToggleIndentGuides,
18464        _: &mut Window,
18465        cx: &mut Context<Self>,
18466    ) {
18467        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18468            self.buffer
18469                .read(cx)
18470                .language_settings(cx)
18471                .indent_guides
18472                .enabled
18473        });
18474        self.show_indent_guides = Some(!currently_enabled);
18475        cx.notify();
18476    }
18477
18478    fn should_show_indent_guides(&self) -> Option<bool> {
18479        self.show_indent_guides
18480    }
18481
18482    pub fn toggle_line_numbers(
18483        &mut self,
18484        _: &ToggleLineNumbers,
18485        _: &mut Window,
18486        cx: &mut Context<Self>,
18487    ) {
18488        let mut editor_settings = EditorSettings::get_global(cx).clone();
18489        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18490        EditorSettings::override_global(editor_settings, cx);
18491    }
18492
18493    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18494        if let Some(show_line_numbers) = self.show_line_numbers {
18495            return show_line_numbers;
18496        }
18497        EditorSettings::get_global(cx).gutter.line_numbers
18498    }
18499
18500    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18501        self.use_relative_line_numbers
18502            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18503    }
18504
18505    pub fn toggle_relative_line_numbers(
18506        &mut self,
18507        _: &ToggleRelativeLineNumbers,
18508        _: &mut Window,
18509        cx: &mut Context<Self>,
18510    ) {
18511        let is_relative = self.should_use_relative_line_numbers(cx);
18512        self.set_relative_line_number(Some(!is_relative), cx)
18513    }
18514
18515    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18516        self.use_relative_line_numbers = is_relative;
18517        cx.notify();
18518    }
18519
18520    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18521        self.show_gutter = show_gutter;
18522        cx.notify();
18523    }
18524
18525    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18526        self.show_scrollbars = ScrollbarAxes {
18527            horizontal: show,
18528            vertical: show,
18529        };
18530        cx.notify();
18531    }
18532
18533    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18534        self.show_scrollbars.vertical = show;
18535        cx.notify();
18536    }
18537
18538    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18539        self.show_scrollbars.horizontal = show;
18540        cx.notify();
18541    }
18542
18543    pub fn set_minimap_visibility(
18544        &mut self,
18545        minimap_visibility: MinimapVisibility,
18546        window: &mut Window,
18547        cx: &mut Context<Self>,
18548    ) {
18549        if self.minimap_visibility != minimap_visibility {
18550            if minimap_visibility.visible() && self.minimap.is_none() {
18551                let minimap_settings = EditorSettings::get_global(cx).minimap;
18552                self.minimap =
18553                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18554            }
18555            self.minimap_visibility = minimap_visibility;
18556            cx.notify();
18557        }
18558    }
18559
18560    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18561        self.set_show_scrollbars(false, cx);
18562        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18563    }
18564
18565    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18566        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18567    }
18568
18569    /// Normally the text in full mode and auto height editors is padded on the
18570    /// left side by roughly half a character width for improved hit testing.
18571    ///
18572    /// Use this method to disable this for cases where this is not wanted (e.g.
18573    /// if you want to align the editor text with some other text above or below)
18574    /// or if you want to add this padding to single-line editors.
18575    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18576        self.offset_content = offset_content;
18577        cx.notify();
18578    }
18579
18580    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18581        self.show_line_numbers = Some(show_line_numbers);
18582        cx.notify();
18583    }
18584
18585    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18586        self.disable_expand_excerpt_buttons = true;
18587        cx.notify();
18588    }
18589
18590    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18591        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18592        cx.notify();
18593    }
18594
18595    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18596        self.show_code_actions = Some(show_code_actions);
18597        cx.notify();
18598    }
18599
18600    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18601        self.show_runnables = Some(show_runnables);
18602        cx.notify();
18603    }
18604
18605    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18606        self.show_breakpoints = Some(show_breakpoints);
18607        cx.notify();
18608    }
18609
18610    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18611        if self.display_map.read(cx).masked != masked {
18612            self.display_map.update(cx, |map, _| map.masked = masked);
18613        }
18614        cx.notify()
18615    }
18616
18617    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18618        self.show_wrap_guides = Some(show_wrap_guides);
18619        cx.notify();
18620    }
18621
18622    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18623        self.show_indent_guides = Some(show_indent_guides);
18624        cx.notify();
18625    }
18626
18627    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18628        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18629            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18630                && let Some(dir) = file.abs_path(cx).parent()
18631            {
18632                return Some(dir.to_owned());
18633            }
18634
18635            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18636                return Some(project_path.path.to_path_buf());
18637            }
18638        }
18639
18640        None
18641    }
18642
18643    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18644        self.active_excerpt(cx)?
18645            .1
18646            .read(cx)
18647            .file()
18648            .and_then(|f| f.as_local())
18649    }
18650
18651    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18652        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18653            let buffer = buffer.read(cx);
18654            if let Some(project_path) = buffer.project_path(cx) {
18655                let project = self.project()?.read(cx);
18656                project.absolute_path(&project_path, cx)
18657            } else {
18658                buffer
18659                    .file()
18660                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18661            }
18662        })
18663    }
18664
18665    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18666        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18667            let project_path = buffer.read(cx).project_path(cx)?;
18668            let project = self.project()?.read(cx);
18669            let entry = project.entry_for_path(&project_path, cx)?;
18670            let path = entry.path.to_path_buf();
18671            Some(path)
18672        })
18673    }
18674
18675    pub fn reveal_in_finder(
18676        &mut self,
18677        _: &RevealInFileManager,
18678        _window: &mut Window,
18679        cx: &mut Context<Self>,
18680    ) {
18681        if let Some(target) = self.target_file(cx) {
18682            cx.reveal_path(&target.abs_path(cx));
18683        }
18684    }
18685
18686    pub fn copy_path(
18687        &mut self,
18688        _: &zed_actions::workspace::CopyPath,
18689        _window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        if let Some(path) = self.target_file_abs_path(cx)
18693            && let Some(path) = path.to_str()
18694        {
18695            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18696        }
18697    }
18698
18699    pub fn copy_relative_path(
18700        &mut self,
18701        _: &zed_actions::workspace::CopyRelativePath,
18702        _window: &mut Window,
18703        cx: &mut Context<Self>,
18704    ) {
18705        if let Some(path) = self.target_file_path(cx)
18706            && let Some(path) = path.to_str()
18707        {
18708            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18709        }
18710    }
18711
18712    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18713        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18714            buffer.read(cx).project_path(cx)
18715        } else {
18716            None
18717        }
18718    }
18719
18720    // Returns true if the editor handled a go-to-line request
18721    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18722        maybe!({
18723            let breakpoint_store = self.breakpoint_store.as_ref()?;
18724
18725            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18726            else {
18727                self.clear_row_highlights::<ActiveDebugLine>();
18728                return None;
18729            };
18730
18731            let position = active_stack_frame.position;
18732            let buffer_id = position.buffer_id?;
18733            let snapshot = self
18734                .project
18735                .as_ref()?
18736                .read(cx)
18737                .buffer_for_id(buffer_id, cx)?
18738                .read(cx)
18739                .snapshot();
18740
18741            let mut handled = false;
18742            for (id, ExcerptRange { context, .. }) in
18743                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18744            {
18745                if context.start.cmp(&position, &snapshot).is_ge()
18746                    || context.end.cmp(&position, &snapshot).is_lt()
18747                {
18748                    continue;
18749                }
18750                let snapshot = self.buffer.read(cx).snapshot(cx);
18751                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18752
18753                handled = true;
18754                self.clear_row_highlights::<ActiveDebugLine>();
18755
18756                self.go_to_line::<ActiveDebugLine>(
18757                    multibuffer_anchor,
18758                    Some(cx.theme().colors().editor_debugger_active_line_background),
18759                    window,
18760                    cx,
18761                );
18762
18763                cx.notify();
18764            }
18765
18766            handled.then_some(())
18767        })
18768        .is_some()
18769    }
18770
18771    pub fn copy_file_name_without_extension(
18772        &mut self,
18773        _: &CopyFileNameWithoutExtension,
18774        _: &mut Window,
18775        cx: &mut Context<Self>,
18776    ) {
18777        if let Some(file) = self.target_file(cx)
18778            && let Some(file_stem) = file.path().file_stem()
18779            && let Some(name) = file_stem.to_str()
18780        {
18781            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18782        }
18783    }
18784
18785    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18786        if let Some(file) = self.target_file(cx)
18787            && let Some(file_name) = file.path().file_name()
18788            && let Some(name) = file_name.to_str()
18789        {
18790            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18791        }
18792    }
18793
18794    pub fn toggle_git_blame(
18795        &mut self,
18796        _: &::git::Blame,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18801
18802        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18803            self.start_git_blame(true, window, cx);
18804        }
18805
18806        cx.notify();
18807    }
18808
18809    pub fn toggle_git_blame_inline(
18810        &mut self,
18811        _: &ToggleGitBlameInline,
18812        window: &mut Window,
18813        cx: &mut Context<Self>,
18814    ) {
18815        self.toggle_git_blame_inline_internal(true, window, cx);
18816        cx.notify();
18817    }
18818
18819    pub fn open_git_blame_commit(
18820        &mut self,
18821        _: &OpenGitBlameCommit,
18822        window: &mut Window,
18823        cx: &mut Context<Self>,
18824    ) {
18825        self.open_git_blame_commit_internal(window, cx);
18826    }
18827
18828    fn open_git_blame_commit_internal(
18829        &mut self,
18830        window: &mut Window,
18831        cx: &mut Context<Self>,
18832    ) -> Option<()> {
18833        let blame = self.blame.as_ref()?;
18834        let snapshot = self.snapshot(window, cx);
18835        let cursor = self.selections.newest::<Point>(cx).head();
18836        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18837        let blame_entry = blame
18838            .update(cx, |blame, cx| {
18839                blame
18840                    .blame_for_rows(
18841                        &[RowInfo {
18842                            buffer_id: Some(buffer.remote_id()),
18843                            buffer_row: Some(point.row),
18844                            ..Default::default()
18845                        }],
18846                        cx,
18847                    )
18848                    .next()
18849            })
18850            .flatten()?;
18851        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18852        let repo = blame.read(cx).repository(cx)?;
18853        let workspace = self.workspace()?.downgrade();
18854        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18855        None
18856    }
18857
18858    pub fn git_blame_inline_enabled(&self) -> bool {
18859        self.git_blame_inline_enabled
18860    }
18861
18862    pub fn toggle_selection_menu(
18863        &mut self,
18864        _: &ToggleSelectionMenu,
18865        _: &mut Window,
18866        cx: &mut Context<Self>,
18867    ) {
18868        self.show_selection_menu = self
18869            .show_selection_menu
18870            .map(|show_selections_menu| !show_selections_menu)
18871            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18872
18873        cx.notify();
18874    }
18875
18876    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18877        self.show_selection_menu
18878            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18879    }
18880
18881    fn start_git_blame(
18882        &mut self,
18883        user_triggered: bool,
18884        window: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) {
18887        if let Some(project) = self.project() {
18888            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18889                return;
18890            };
18891
18892            if buffer.read(cx).file().is_none() {
18893                return;
18894            }
18895
18896            let focused = self.focus_handle(cx).contains_focused(window, cx);
18897
18898            let project = project.clone();
18899            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18900            self.blame_subscription =
18901                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18902            self.blame = Some(blame);
18903        }
18904    }
18905
18906    fn toggle_git_blame_inline_internal(
18907        &mut self,
18908        user_triggered: bool,
18909        window: &mut Window,
18910        cx: &mut Context<Self>,
18911    ) {
18912        if self.git_blame_inline_enabled {
18913            self.git_blame_inline_enabled = false;
18914            self.show_git_blame_inline = false;
18915            self.show_git_blame_inline_delay_task.take();
18916        } else {
18917            self.git_blame_inline_enabled = true;
18918            self.start_git_blame_inline(user_triggered, window, cx);
18919        }
18920
18921        cx.notify();
18922    }
18923
18924    fn start_git_blame_inline(
18925        &mut self,
18926        user_triggered: bool,
18927        window: &mut Window,
18928        cx: &mut Context<Self>,
18929    ) {
18930        self.start_git_blame(user_triggered, window, cx);
18931
18932        if ProjectSettings::get_global(cx)
18933            .git
18934            .inline_blame_delay()
18935            .is_some()
18936        {
18937            self.start_inline_blame_timer(window, cx);
18938        } else {
18939            self.show_git_blame_inline = true
18940        }
18941    }
18942
18943    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18944        self.blame.as_ref()
18945    }
18946
18947    pub fn show_git_blame_gutter(&self) -> bool {
18948        self.show_git_blame_gutter
18949    }
18950
18951    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18952        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18953    }
18954
18955    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18956        self.show_git_blame_inline
18957            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18958            && !self.newest_selection_head_on_empty_line(cx)
18959            && self.has_blame_entries(cx)
18960    }
18961
18962    fn has_blame_entries(&self, cx: &App) -> bool {
18963        self.blame()
18964            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18965    }
18966
18967    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18968        let cursor_anchor = self.selections.newest_anchor().head();
18969
18970        let snapshot = self.buffer.read(cx).snapshot(cx);
18971        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18972
18973        snapshot.line_len(buffer_row) == 0
18974    }
18975
18976    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18977        let buffer_and_selection = maybe!({
18978            let selection = self.selections.newest::<Point>(cx);
18979            let selection_range = selection.range();
18980
18981            let multi_buffer = self.buffer().read(cx);
18982            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18983            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18984
18985            let (buffer, range, _) = if selection.reversed {
18986                buffer_ranges.first()
18987            } else {
18988                buffer_ranges.last()
18989            }?;
18990
18991            let selection = text::ToPoint::to_point(&range.start, buffer).row
18992                ..text::ToPoint::to_point(&range.end, buffer).row;
18993            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
18994        });
18995
18996        let Some((buffer, selection)) = buffer_and_selection else {
18997            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18998        };
18999
19000        let Some(project) = self.project() else {
19001            return Task::ready(Err(anyhow!("editor does not have project")));
19002        };
19003
19004        project.update(cx, |project, cx| {
19005            project.get_permalink_to_line(&buffer, selection, cx)
19006        })
19007    }
19008
19009    pub fn copy_permalink_to_line(
19010        &mut self,
19011        _: &CopyPermalinkToLine,
19012        window: &mut Window,
19013        cx: &mut Context<Self>,
19014    ) {
19015        let permalink_task = self.get_permalink_to_line(cx);
19016        let workspace = self.workspace();
19017
19018        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19019            Ok(permalink) => {
19020                cx.update(|_, cx| {
19021                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19022                })
19023                .ok();
19024            }
19025            Err(err) => {
19026                let message = format!("Failed to copy permalink: {err}");
19027
19028                anyhow::Result::<()>::Err(err).log_err();
19029
19030                if let Some(workspace) = workspace {
19031                    workspace
19032                        .update_in(cx, |workspace, _, cx| {
19033                            struct CopyPermalinkToLine;
19034
19035                            workspace.show_toast(
19036                                Toast::new(
19037                                    NotificationId::unique::<CopyPermalinkToLine>(),
19038                                    message,
19039                                ),
19040                                cx,
19041                            )
19042                        })
19043                        .ok();
19044                }
19045            }
19046        })
19047        .detach();
19048    }
19049
19050    pub fn copy_file_location(
19051        &mut self,
19052        _: &CopyFileLocation,
19053        _: &mut Window,
19054        cx: &mut Context<Self>,
19055    ) {
19056        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19057        if let Some(file) = self.target_file(cx)
19058            && let Some(path) = file.path().to_str()
19059        {
19060            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19061        }
19062    }
19063
19064    pub fn open_permalink_to_line(
19065        &mut self,
19066        _: &OpenPermalinkToLine,
19067        window: &mut Window,
19068        cx: &mut Context<Self>,
19069    ) {
19070        let permalink_task = self.get_permalink_to_line(cx);
19071        let workspace = self.workspace();
19072
19073        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19074            Ok(permalink) => {
19075                cx.update(|_, cx| {
19076                    cx.open_url(permalink.as_ref());
19077                })
19078                .ok();
19079            }
19080            Err(err) => {
19081                let message = format!("Failed to open permalink: {err}");
19082
19083                anyhow::Result::<()>::Err(err).log_err();
19084
19085                if let Some(workspace) = workspace {
19086                    workspace
19087                        .update(cx, |workspace, cx| {
19088                            struct OpenPermalinkToLine;
19089
19090                            workspace.show_toast(
19091                                Toast::new(
19092                                    NotificationId::unique::<OpenPermalinkToLine>(),
19093                                    message,
19094                                ),
19095                                cx,
19096                            )
19097                        })
19098                        .ok();
19099                }
19100            }
19101        })
19102        .detach();
19103    }
19104
19105    pub fn insert_uuid_v4(
19106        &mut self,
19107        _: &InsertUuidV4,
19108        window: &mut Window,
19109        cx: &mut Context<Self>,
19110    ) {
19111        self.insert_uuid(UuidVersion::V4, window, cx);
19112    }
19113
19114    pub fn insert_uuid_v7(
19115        &mut self,
19116        _: &InsertUuidV7,
19117        window: &mut Window,
19118        cx: &mut Context<Self>,
19119    ) {
19120        self.insert_uuid(UuidVersion::V7, window, cx);
19121    }
19122
19123    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19124        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19125        self.transact(window, cx, |this, window, cx| {
19126            let edits = this
19127                .selections
19128                .all::<Point>(cx)
19129                .into_iter()
19130                .map(|selection| {
19131                    let uuid = match version {
19132                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19133                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19134                    };
19135
19136                    (selection.range(), uuid.to_string())
19137                });
19138            this.edit(edits, cx);
19139            this.refresh_edit_prediction(true, false, window, cx);
19140        });
19141    }
19142
19143    pub fn open_selections_in_multibuffer(
19144        &mut self,
19145        _: &OpenSelectionsInMultibuffer,
19146        window: &mut Window,
19147        cx: &mut Context<Self>,
19148    ) {
19149        let multibuffer = self.buffer.read(cx);
19150
19151        let Some(buffer) = multibuffer.as_singleton() else {
19152            return;
19153        };
19154
19155        let Some(workspace) = self.workspace() else {
19156            return;
19157        };
19158
19159        let title = multibuffer.title(cx).to_string();
19160
19161        let locations = self
19162            .selections
19163            .all_anchors(cx)
19164            .iter()
19165            .map(|selection| Location {
19166                buffer: buffer.clone(),
19167                range: selection.start.text_anchor..selection.end.text_anchor,
19168            })
19169            .collect::<Vec<_>>();
19170
19171        cx.spawn_in(window, async move |_, cx| {
19172            workspace.update_in(cx, |workspace, window, cx| {
19173                Self::open_locations_in_multibuffer(
19174                    workspace,
19175                    locations,
19176                    format!("Selections for '{title}'"),
19177                    false,
19178                    MultibufferSelectionMode::All,
19179                    window,
19180                    cx,
19181                );
19182            })
19183        })
19184        .detach();
19185    }
19186
19187    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19188    /// last highlight added will be used.
19189    ///
19190    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19191    pub fn highlight_rows<T: 'static>(
19192        &mut self,
19193        range: Range<Anchor>,
19194        color: Hsla,
19195        options: RowHighlightOptions,
19196        cx: &mut Context<Self>,
19197    ) {
19198        let snapshot = self.buffer().read(cx).snapshot(cx);
19199        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19200        let ix = row_highlights.binary_search_by(|highlight| {
19201            Ordering::Equal
19202                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19203                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19204        });
19205
19206        if let Err(mut ix) = ix {
19207            let index = post_inc(&mut self.highlight_order);
19208
19209            // If this range intersects with the preceding highlight, then merge it with
19210            // the preceding highlight. Otherwise insert a new highlight.
19211            let mut merged = false;
19212            if ix > 0 {
19213                let prev_highlight = &mut row_highlights[ix - 1];
19214                if prev_highlight
19215                    .range
19216                    .end
19217                    .cmp(&range.start, &snapshot)
19218                    .is_ge()
19219                {
19220                    ix -= 1;
19221                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19222                        prev_highlight.range.end = range.end;
19223                    }
19224                    merged = true;
19225                    prev_highlight.index = index;
19226                    prev_highlight.color = color;
19227                    prev_highlight.options = options;
19228                }
19229            }
19230
19231            if !merged {
19232                row_highlights.insert(
19233                    ix,
19234                    RowHighlight {
19235                        range,
19236                        index,
19237                        color,
19238                        options,
19239                        type_id: TypeId::of::<T>(),
19240                    },
19241                );
19242            }
19243
19244            // If any of the following highlights intersect with this one, merge them.
19245            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19246                let highlight = &row_highlights[ix];
19247                if next_highlight
19248                    .range
19249                    .start
19250                    .cmp(&highlight.range.end, &snapshot)
19251                    .is_le()
19252                {
19253                    if next_highlight
19254                        .range
19255                        .end
19256                        .cmp(&highlight.range.end, &snapshot)
19257                        .is_gt()
19258                    {
19259                        row_highlights[ix].range.end = next_highlight.range.end;
19260                    }
19261                    row_highlights.remove(ix + 1);
19262                } else {
19263                    break;
19264                }
19265            }
19266        }
19267    }
19268
19269    /// Remove any highlighted row ranges of the given type that intersect the
19270    /// given ranges.
19271    pub fn remove_highlighted_rows<T: 'static>(
19272        &mut self,
19273        ranges_to_remove: Vec<Range<Anchor>>,
19274        cx: &mut Context<Self>,
19275    ) {
19276        let snapshot = self.buffer().read(cx).snapshot(cx);
19277        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19278        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19279        row_highlights.retain(|highlight| {
19280            while let Some(range_to_remove) = ranges_to_remove.peek() {
19281                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19282                    Ordering::Less | Ordering::Equal => {
19283                        ranges_to_remove.next();
19284                    }
19285                    Ordering::Greater => {
19286                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19287                            Ordering::Less | Ordering::Equal => {
19288                                return false;
19289                            }
19290                            Ordering::Greater => break,
19291                        }
19292                    }
19293                }
19294            }
19295
19296            true
19297        })
19298    }
19299
19300    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19301    pub fn clear_row_highlights<T: 'static>(&mut self) {
19302        self.highlighted_rows.remove(&TypeId::of::<T>());
19303    }
19304
19305    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19306    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19307        self.highlighted_rows
19308            .get(&TypeId::of::<T>())
19309            .map_or(&[] as &[_], |vec| vec.as_slice())
19310            .iter()
19311            .map(|highlight| (highlight.range.clone(), highlight.color))
19312    }
19313
19314    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19315    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19316    /// Allows to ignore certain kinds of highlights.
19317    pub fn highlighted_display_rows(
19318        &self,
19319        window: &mut Window,
19320        cx: &mut App,
19321    ) -> BTreeMap<DisplayRow, LineHighlight> {
19322        let snapshot = self.snapshot(window, cx);
19323        let mut used_highlight_orders = HashMap::default();
19324        self.highlighted_rows
19325            .iter()
19326            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19327            .fold(
19328                BTreeMap::<DisplayRow, LineHighlight>::new(),
19329                |mut unique_rows, highlight| {
19330                    let start = highlight.range.start.to_display_point(&snapshot);
19331                    let end = highlight.range.end.to_display_point(&snapshot);
19332                    let start_row = start.row().0;
19333                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19334                        && end.column() == 0
19335                    {
19336                        end.row().0.saturating_sub(1)
19337                    } else {
19338                        end.row().0
19339                    };
19340                    for row in start_row..=end_row {
19341                        let used_index =
19342                            used_highlight_orders.entry(row).or_insert(highlight.index);
19343                        if highlight.index >= *used_index {
19344                            *used_index = highlight.index;
19345                            unique_rows.insert(
19346                                DisplayRow(row),
19347                                LineHighlight {
19348                                    include_gutter: highlight.options.include_gutter,
19349                                    border: None,
19350                                    background: highlight.color.into(),
19351                                    type_id: Some(highlight.type_id),
19352                                },
19353                            );
19354                        }
19355                    }
19356                    unique_rows
19357                },
19358            )
19359    }
19360
19361    pub fn highlighted_display_row_for_autoscroll(
19362        &self,
19363        snapshot: &DisplaySnapshot,
19364    ) -> Option<DisplayRow> {
19365        self.highlighted_rows
19366            .values()
19367            .flat_map(|highlighted_rows| highlighted_rows.iter())
19368            .filter_map(|highlight| {
19369                if highlight.options.autoscroll {
19370                    Some(highlight.range.start.to_display_point(snapshot).row())
19371                } else {
19372                    None
19373                }
19374            })
19375            .min()
19376    }
19377
19378    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19379        self.highlight_background::<SearchWithinRange>(
19380            ranges,
19381            |colors| colors.colors().editor_document_highlight_read_background,
19382            cx,
19383        )
19384    }
19385
19386    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19387        self.breadcrumb_header = Some(new_header);
19388    }
19389
19390    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19391        self.clear_background_highlights::<SearchWithinRange>(cx);
19392    }
19393
19394    pub fn highlight_background<T: 'static>(
19395        &mut self,
19396        ranges: &[Range<Anchor>],
19397        color_fetcher: fn(&Theme) -> Hsla,
19398        cx: &mut Context<Self>,
19399    ) {
19400        self.background_highlights.insert(
19401            HighlightKey::Type(TypeId::of::<T>()),
19402            (color_fetcher, Arc::from(ranges)),
19403        );
19404        self.scrollbar_marker_state.dirty = true;
19405        cx.notify();
19406    }
19407
19408    pub fn highlight_background_key<T: 'static>(
19409        &mut self,
19410        key: usize,
19411        ranges: &[Range<Anchor>],
19412        color_fetcher: fn(&Theme) -> Hsla,
19413        cx: &mut Context<Self>,
19414    ) {
19415        self.background_highlights.insert(
19416            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19417            (color_fetcher, Arc::from(ranges)),
19418        );
19419        self.scrollbar_marker_state.dirty = true;
19420        cx.notify();
19421    }
19422
19423    pub fn clear_background_highlights<T: 'static>(
19424        &mut self,
19425        cx: &mut Context<Self>,
19426    ) -> Option<BackgroundHighlight> {
19427        let text_highlights = self
19428            .background_highlights
19429            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19430        if !text_highlights.1.is_empty() {
19431            self.scrollbar_marker_state.dirty = true;
19432            cx.notify();
19433        }
19434        Some(text_highlights)
19435    }
19436
19437    pub fn highlight_gutter<T: 'static>(
19438        &mut self,
19439        ranges: impl Into<Vec<Range<Anchor>>>,
19440        color_fetcher: fn(&App) -> Hsla,
19441        cx: &mut Context<Self>,
19442    ) {
19443        self.gutter_highlights
19444            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19445        cx.notify();
19446    }
19447
19448    pub fn clear_gutter_highlights<T: 'static>(
19449        &mut self,
19450        cx: &mut Context<Self>,
19451    ) -> Option<GutterHighlight> {
19452        cx.notify();
19453        self.gutter_highlights.remove(&TypeId::of::<T>())
19454    }
19455
19456    pub fn insert_gutter_highlight<T: 'static>(
19457        &mut self,
19458        range: Range<Anchor>,
19459        color_fetcher: fn(&App) -> Hsla,
19460        cx: &mut Context<Self>,
19461    ) {
19462        let snapshot = self.buffer().read(cx).snapshot(cx);
19463        let mut highlights = self
19464            .gutter_highlights
19465            .remove(&TypeId::of::<T>())
19466            .map(|(_, highlights)| highlights)
19467            .unwrap_or_default();
19468        let ix = highlights.binary_search_by(|highlight| {
19469            Ordering::Equal
19470                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19471                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19472        });
19473        if let Err(ix) = ix {
19474            highlights.insert(ix, range);
19475        }
19476        self.gutter_highlights
19477            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19478    }
19479
19480    pub fn remove_gutter_highlights<T: 'static>(
19481        &mut self,
19482        ranges_to_remove: Vec<Range<Anchor>>,
19483        cx: &mut Context<Self>,
19484    ) {
19485        let snapshot = self.buffer().read(cx).snapshot(cx);
19486        let Some((color_fetcher, mut gutter_highlights)) =
19487            self.gutter_highlights.remove(&TypeId::of::<T>())
19488        else {
19489            return;
19490        };
19491        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19492        gutter_highlights.retain(|highlight| {
19493            while let Some(range_to_remove) = ranges_to_remove.peek() {
19494                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19495                    Ordering::Less | Ordering::Equal => {
19496                        ranges_to_remove.next();
19497                    }
19498                    Ordering::Greater => {
19499                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19500                            Ordering::Less | Ordering::Equal => {
19501                                return false;
19502                            }
19503                            Ordering::Greater => break,
19504                        }
19505                    }
19506                }
19507            }
19508
19509            true
19510        });
19511        self.gutter_highlights
19512            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19513    }
19514
19515    #[cfg(feature = "test-support")]
19516    pub fn all_text_highlights(
19517        &self,
19518        window: &mut Window,
19519        cx: &mut Context<Self>,
19520    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19521        let snapshot = self.snapshot(window, cx);
19522        self.display_map.update(cx, |display_map, _| {
19523            display_map
19524                .all_text_highlights()
19525                .map(|highlight| {
19526                    let (style, ranges) = highlight.as_ref();
19527                    (
19528                        *style,
19529                        ranges
19530                            .iter()
19531                            .map(|range| range.clone().to_display_points(&snapshot))
19532                            .collect(),
19533                    )
19534                })
19535                .collect()
19536        })
19537    }
19538
19539    #[cfg(feature = "test-support")]
19540    pub fn all_text_background_highlights(
19541        &self,
19542        window: &mut Window,
19543        cx: &mut Context<Self>,
19544    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19545        let snapshot = self.snapshot(window, cx);
19546        let buffer = &snapshot.buffer_snapshot;
19547        let start = buffer.anchor_before(0);
19548        let end = buffer.anchor_after(buffer.len());
19549        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19550    }
19551
19552    #[cfg(feature = "test-support")]
19553    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19554        let snapshot = self.buffer().read(cx).snapshot(cx);
19555
19556        let highlights = self
19557            .background_highlights
19558            .get(&HighlightKey::Type(TypeId::of::<
19559                items::BufferSearchHighlights,
19560            >()));
19561
19562        if let Some((_color, ranges)) = highlights {
19563            ranges
19564                .iter()
19565                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19566                .collect_vec()
19567        } else {
19568            vec![]
19569        }
19570    }
19571
19572    fn document_highlights_for_position<'a>(
19573        &'a self,
19574        position: Anchor,
19575        buffer: &'a MultiBufferSnapshot,
19576    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19577        let read_highlights = self
19578            .background_highlights
19579            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19580            .map(|h| &h.1);
19581        let write_highlights = self
19582            .background_highlights
19583            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19584            .map(|h| &h.1);
19585        let left_position = position.bias_left(buffer);
19586        let right_position = position.bias_right(buffer);
19587        read_highlights
19588            .into_iter()
19589            .chain(write_highlights)
19590            .flat_map(move |ranges| {
19591                let start_ix = match ranges.binary_search_by(|probe| {
19592                    let cmp = probe.end.cmp(&left_position, buffer);
19593                    if cmp.is_ge() {
19594                        Ordering::Greater
19595                    } else {
19596                        Ordering::Less
19597                    }
19598                }) {
19599                    Ok(i) | Err(i) => i,
19600                };
19601
19602                ranges[start_ix..]
19603                    .iter()
19604                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19605            })
19606    }
19607
19608    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19609        self.background_highlights
19610            .get(&HighlightKey::Type(TypeId::of::<T>()))
19611            .is_some_and(|(_, highlights)| !highlights.is_empty())
19612    }
19613
19614    pub fn background_highlights_in_range(
19615        &self,
19616        search_range: Range<Anchor>,
19617        display_snapshot: &DisplaySnapshot,
19618        theme: &Theme,
19619    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19620        let mut results = Vec::new();
19621        for (color_fetcher, ranges) in self.background_highlights.values() {
19622            let color = color_fetcher(theme);
19623            let start_ix = match ranges.binary_search_by(|probe| {
19624                let cmp = probe
19625                    .end
19626                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19627                if cmp.is_gt() {
19628                    Ordering::Greater
19629                } else {
19630                    Ordering::Less
19631                }
19632            }) {
19633                Ok(i) | Err(i) => i,
19634            };
19635            for range in &ranges[start_ix..] {
19636                if range
19637                    .start
19638                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19639                    .is_ge()
19640                {
19641                    break;
19642                }
19643
19644                let start = range.start.to_display_point(display_snapshot);
19645                let end = range.end.to_display_point(display_snapshot);
19646                results.push((start..end, color))
19647            }
19648        }
19649        results
19650    }
19651
19652    pub fn background_highlight_row_ranges<T: 'static>(
19653        &self,
19654        search_range: Range<Anchor>,
19655        display_snapshot: &DisplaySnapshot,
19656        count: usize,
19657    ) -> Vec<RangeInclusive<DisplayPoint>> {
19658        let mut results = Vec::new();
19659        let Some((_, ranges)) = self
19660            .background_highlights
19661            .get(&HighlightKey::Type(TypeId::of::<T>()))
19662        else {
19663            return vec![];
19664        };
19665
19666        let start_ix = match ranges.binary_search_by(|probe| {
19667            let cmp = probe
19668                .end
19669                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19670            if cmp.is_gt() {
19671                Ordering::Greater
19672            } else {
19673                Ordering::Less
19674            }
19675        }) {
19676            Ok(i) | Err(i) => i,
19677        };
19678        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19679            if let (Some(start_display), Some(end_display)) = (start, end) {
19680                results.push(
19681                    start_display.to_display_point(display_snapshot)
19682                        ..=end_display.to_display_point(display_snapshot),
19683                );
19684            }
19685        };
19686        let mut start_row: Option<Point> = None;
19687        let mut end_row: Option<Point> = None;
19688        if ranges.len() > count {
19689            return Vec::new();
19690        }
19691        for range in &ranges[start_ix..] {
19692            if range
19693                .start
19694                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19695                .is_ge()
19696            {
19697                break;
19698            }
19699            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19700            if let Some(current_row) = &end_row
19701                && end.row == current_row.row
19702            {
19703                continue;
19704            }
19705            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19706            if start_row.is_none() {
19707                assert_eq!(end_row, None);
19708                start_row = Some(start);
19709                end_row = Some(end);
19710                continue;
19711            }
19712            if let Some(current_end) = end_row.as_mut() {
19713                if start.row > current_end.row + 1 {
19714                    push_region(start_row, end_row);
19715                    start_row = Some(start);
19716                    end_row = Some(end);
19717                } else {
19718                    // Merge two hunks.
19719                    *current_end = end;
19720                }
19721            } else {
19722                unreachable!();
19723            }
19724        }
19725        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19726        push_region(start_row, end_row);
19727        results
19728    }
19729
19730    pub fn gutter_highlights_in_range(
19731        &self,
19732        search_range: Range<Anchor>,
19733        display_snapshot: &DisplaySnapshot,
19734        cx: &App,
19735    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19736        let mut results = Vec::new();
19737        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19738            let color = color_fetcher(cx);
19739            let start_ix = match ranges.binary_search_by(|probe| {
19740                let cmp = probe
19741                    .end
19742                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19743                if cmp.is_gt() {
19744                    Ordering::Greater
19745                } else {
19746                    Ordering::Less
19747                }
19748            }) {
19749                Ok(i) | Err(i) => i,
19750            };
19751            for range in &ranges[start_ix..] {
19752                if range
19753                    .start
19754                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19755                    .is_ge()
19756                {
19757                    break;
19758                }
19759
19760                let start = range.start.to_display_point(display_snapshot);
19761                let end = range.end.to_display_point(display_snapshot);
19762                results.push((start..end, color))
19763            }
19764        }
19765        results
19766    }
19767
19768    /// Get the text ranges corresponding to the redaction query
19769    pub fn redacted_ranges(
19770        &self,
19771        search_range: Range<Anchor>,
19772        display_snapshot: &DisplaySnapshot,
19773        cx: &App,
19774    ) -> Vec<Range<DisplayPoint>> {
19775        display_snapshot
19776            .buffer_snapshot
19777            .redacted_ranges(search_range, |file| {
19778                if let Some(file) = file {
19779                    file.is_private()
19780                        && EditorSettings::get(
19781                            Some(SettingsLocation {
19782                                worktree_id: file.worktree_id(cx),
19783                                path: file.path().as_ref(),
19784                            }),
19785                            cx,
19786                        )
19787                        .redact_private_values
19788                } else {
19789                    false
19790                }
19791            })
19792            .map(|range| {
19793                range.start.to_display_point(display_snapshot)
19794                    ..range.end.to_display_point(display_snapshot)
19795            })
19796            .collect()
19797    }
19798
19799    pub fn highlight_text_key<T: 'static>(
19800        &mut self,
19801        key: usize,
19802        ranges: Vec<Range<Anchor>>,
19803        style: HighlightStyle,
19804        cx: &mut Context<Self>,
19805    ) {
19806        self.display_map.update(cx, |map, _| {
19807            map.highlight_text(
19808                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19809                ranges,
19810                style,
19811            );
19812        });
19813        cx.notify();
19814    }
19815
19816    pub fn highlight_text<T: 'static>(
19817        &mut self,
19818        ranges: Vec<Range<Anchor>>,
19819        style: HighlightStyle,
19820        cx: &mut Context<Self>,
19821    ) {
19822        self.display_map.update(cx, |map, _| {
19823            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19824        });
19825        cx.notify();
19826    }
19827
19828    pub(crate) fn highlight_inlays<T: 'static>(
19829        &mut self,
19830        highlights: Vec<InlayHighlight>,
19831        style: HighlightStyle,
19832        cx: &mut Context<Self>,
19833    ) {
19834        self.display_map.update(cx, |map, _| {
19835            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19836        });
19837        cx.notify();
19838    }
19839
19840    pub fn text_highlights<'a, T: 'static>(
19841        &'a self,
19842        cx: &'a App,
19843    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19844        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19845    }
19846
19847    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19848        let cleared = self
19849            .display_map
19850            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19851        if cleared {
19852            cx.notify();
19853        }
19854    }
19855
19856    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19857        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19858            && self.focus_handle.is_focused(window)
19859    }
19860
19861    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19862        self.show_cursor_when_unfocused = is_enabled;
19863        cx.notify();
19864    }
19865
19866    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19867        cx.notify();
19868    }
19869
19870    fn on_debug_session_event(
19871        &mut self,
19872        _session: Entity<Session>,
19873        event: &SessionEvent,
19874        cx: &mut Context<Self>,
19875    ) {
19876        if let SessionEvent::InvalidateInlineValue = event {
19877            self.refresh_inline_values(cx);
19878        }
19879    }
19880
19881    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19882        let Some(project) = self.project.clone() else {
19883            return;
19884        };
19885
19886        if !self.inline_value_cache.enabled {
19887            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19888            self.splice_inlays(&inlays, Vec::new(), cx);
19889            return;
19890        }
19891
19892        let current_execution_position = self
19893            .highlighted_rows
19894            .get(&TypeId::of::<ActiveDebugLine>())
19895            .and_then(|lines| lines.last().map(|line| line.range.end));
19896
19897        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19898            let inline_values = editor
19899                .update(cx, |editor, cx| {
19900                    let Some(current_execution_position) = current_execution_position else {
19901                        return Some(Task::ready(Ok(Vec::new())));
19902                    };
19903
19904                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19905                        let snapshot = buffer.snapshot(cx);
19906
19907                        let excerpt = snapshot.excerpt_containing(
19908                            current_execution_position..current_execution_position,
19909                        )?;
19910
19911                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19912                    })?;
19913
19914                    let range =
19915                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19916
19917                    project.inline_values(buffer, range, cx)
19918                })
19919                .ok()
19920                .flatten()?
19921                .await
19922                .context("refreshing debugger inlays")
19923                .log_err()?;
19924
19925            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19926
19927            for (buffer_id, inline_value) in inline_values
19928                .into_iter()
19929                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19930            {
19931                buffer_inline_values
19932                    .entry(buffer_id)
19933                    .or_default()
19934                    .push(inline_value);
19935            }
19936
19937            editor
19938                .update(cx, |editor, cx| {
19939                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19940                    let mut new_inlays = Vec::default();
19941
19942                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19943                        let buffer_id = buffer_snapshot.remote_id();
19944                        buffer_inline_values
19945                            .get(&buffer_id)
19946                            .into_iter()
19947                            .flatten()
19948                            .for_each(|hint| {
19949                                let inlay = Inlay::debugger(
19950                                    post_inc(&mut editor.next_inlay_id),
19951                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19952                                    hint.text(),
19953                                );
19954                                if !inlay.text.chars().contains(&'\n') {
19955                                    new_inlays.push(inlay);
19956                                }
19957                            });
19958                    }
19959
19960                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19961                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19962
19963                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19964                })
19965                .ok()?;
19966            Some(())
19967        });
19968    }
19969
19970    fn on_buffer_event(
19971        &mut self,
19972        multibuffer: &Entity<MultiBuffer>,
19973        event: &multi_buffer::Event,
19974        window: &mut Window,
19975        cx: &mut Context<Self>,
19976    ) {
19977        match event {
19978            multi_buffer::Event::Edited {
19979                singleton_buffer_edited,
19980                edited_buffer,
19981            } => {
19982                self.scrollbar_marker_state.dirty = true;
19983                self.active_indent_guides_state.dirty = true;
19984                self.refresh_active_diagnostics(cx);
19985                self.refresh_code_actions(window, cx);
19986                self.refresh_selected_text_highlights(true, window, cx);
19987                self.refresh_single_line_folds(window, cx);
19988                refresh_matching_bracket_highlights(self, window, cx);
19989                if self.has_active_edit_prediction() {
19990                    self.update_visible_edit_prediction(window, cx);
19991                }
19992                if let Some(project) = self.project.as_ref()
19993                    && let Some(edited_buffer) = edited_buffer
19994                {
19995                    project.update(cx, |project, cx| {
19996                        self.registered_buffers
19997                            .entry(edited_buffer.read(cx).remote_id())
19998                            .or_insert_with(|| {
19999                                project.register_buffer_with_language_servers(edited_buffer, cx)
20000                            });
20001                    });
20002                }
20003                cx.emit(EditorEvent::BufferEdited);
20004                cx.emit(SearchEvent::MatchesInvalidated);
20005
20006                if let Some(buffer) = edited_buffer {
20007                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20008                }
20009
20010                if *singleton_buffer_edited {
20011                    if let Some(buffer) = edited_buffer
20012                        && buffer.read(cx).file().is_none()
20013                    {
20014                        cx.emit(EditorEvent::TitleChanged);
20015                    }
20016                    if let Some(project) = &self.project {
20017                        #[allow(clippy::mutable_key_type)]
20018                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20019                            multibuffer
20020                                .all_buffers()
20021                                .into_iter()
20022                                .filter_map(|buffer| {
20023                                    buffer.update(cx, |buffer, cx| {
20024                                        let language = buffer.language()?;
20025                                        let should_discard = project.update(cx, |project, cx| {
20026                                            project.is_local()
20027                                                && !project.has_language_servers_for(buffer, cx)
20028                                        });
20029                                        should_discard.not().then_some(language.clone())
20030                                    })
20031                                })
20032                                .collect::<HashSet<_>>()
20033                        });
20034                        if !languages_affected.is_empty() {
20035                            self.refresh_inlay_hints(
20036                                InlayHintRefreshReason::BufferEdited(languages_affected),
20037                                cx,
20038                            );
20039                        }
20040                    }
20041                }
20042
20043                let Some(project) = &self.project else { return };
20044                let (telemetry, is_via_ssh) = {
20045                    let project = project.read(cx);
20046                    let telemetry = project.client().telemetry().clone();
20047                    let is_via_ssh = project.is_via_ssh();
20048                    (telemetry, is_via_ssh)
20049                };
20050                refresh_linked_ranges(self, window, cx);
20051                telemetry.log_edit_event("editor", is_via_ssh);
20052            }
20053            multi_buffer::Event::ExcerptsAdded {
20054                buffer,
20055                predecessor,
20056                excerpts,
20057            } => {
20058                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20059                let buffer_id = buffer.read(cx).remote_id();
20060                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20061                    && let Some(project) = &self.project
20062                {
20063                    update_uncommitted_diff_for_buffer(
20064                        cx.entity(),
20065                        project,
20066                        [buffer.clone()],
20067                        self.buffer.clone(),
20068                        cx,
20069                    )
20070                    .detach();
20071                }
20072                self.update_lsp_data(false, Some(buffer_id), window, cx);
20073                cx.emit(EditorEvent::ExcerptsAdded {
20074                    buffer: buffer.clone(),
20075                    predecessor: *predecessor,
20076                    excerpts: excerpts.clone(),
20077                });
20078                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20079            }
20080            multi_buffer::Event::ExcerptsRemoved {
20081                ids,
20082                removed_buffer_ids,
20083            } => {
20084                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20085                let buffer = self.buffer.read(cx);
20086                self.registered_buffers
20087                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20088                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20089                cx.emit(EditorEvent::ExcerptsRemoved {
20090                    ids: ids.clone(),
20091                    removed_buffer_ids: removed_buffer_ids.clone(),
20092                });
20093            }
20094            multi_buffer::Event::ExcerptsEdited {
20095                excerpt_ids,
20096                buffer_ids,
20097            } => {
20098                self.display_map.update(cx, |map, cx| {
20099                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20100                });
20101                cx.emit(EditorEvent::ExcerptsEdited {
20102                    ids: excerpt_ids.clone(),
20103                });
20104            }
20105            multi_buffer::Event::ExcerptsExpanded { ids } => {
20106                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20107                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20108            }
20109            multi_buffer::Event::Reparsed(buffer_id) => {
20110                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20111                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20112
20113                cx.emit(EditorEvent::Reparsed(*buffer_id));
20114            }
20115            multi_buffer::Event::DiffHunksToggled => {
20116                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20117            }
20118            multi_buffer::Event::LanguageChanged(buffer_id) => {
20119                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20120                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20121                cx.emit(EditorEvent::Reparsed(*buffer_id));
20122                cx.notify();
20123            }
20124            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20125            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20126            multi_buffer::Event::FileHandleChanged
20127            | multi_buffer::Event::Reloaded
20128            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20129            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20130            multi_buffer::Event::DiagnosticsUpdated => {
20131                self.update_diagnostics_state(window, cx);
20132            }
20133            _ => {}
20134        };
20135    }
20136
20137    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20138        if !self.diagnostics_enabled() {
20139            return;
20140        }
20141        self.refresh_active_diagnostics(cx);
20142        self.refresh_inline_diagnostics(true, window, cx);
20143        self.scrollbar_marker_state.dirty = true;
20144        cx.notify();
20145    }
20146
20147    pub fn start_temporary_diff_override(&mut self) {
20148        self.load_diff_task.take();
20149        self.temporary_diff_override = true;
20150    }
20151
20152    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20153        self.temporary_diff_override = false;
20154        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20155        self.buffer.update(cx, |buffer, cx| {
20156            buffer.set_all_diff_hunks_collapsed(cx);
20157        });
20158
20159        if let Some(project) = self.project.clone() {
20160            self.load_diff_task = Some(
20161                update_uncommitted_diff_for_buffer(
20162                    cx.entity(),
20163                    &project,
20164                    self.buffer.read(cx).all_buffers(),
20165                    self.buffer.clone(),
20166                    cx,
20167                )
20168                .shared(),
20169            );
20170        }
20171    }
20172
20173    fn on_display_map_changed(
20174        &mut self,
20175        _: Entity<DisplayMap>,
20176        _: &mut Window,
20177        cx: &mut Context<Self>,
20178    ) {
20179        cx.notify();
20180    }
20181
20182    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20183        if self.diagnostics_enabled() {
20184            let new_severity = EditorSettings::get_global(cx)
20185                .diagnostics_max_severity
20186                .unwrap_or(DiagnosticSeverity::Hint);
20187            self.set_max_diagnostics_severity(new_severity, cx);
20188        }
20189        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20190        self.update_edit_prediction_settings(cx);
20191        self.refresh_edit_prediction(true, false, window, cx);
20192        self.refresh_inline_values(cx);
20193        self.refresh_inlay_hints(
20194            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20195                self.selections.newest_anchor().head(),
20196                &self.buffer.read(cx).snapshot(cx),
20197                cx,
20198            )),
20199            cx,
20200        );
20201
20202        let old_cursor_shape = self.cursor_shape;
20203        let old_show_breadcrumbs = self.show_breadcrumbs;
20204
20205        {
20206            let editor_settings = EditorSettings::get_global(cx);
20207            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20208            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20209            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20210            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20211        }
20212
20213        if old_cursor_shape != self.cursor_shape {
20214            cx.emit(EditorEvent::CursorShapeChanged);
20215        }
20216
20217        if old_show_breadcrumbs != self.show_breadcrumbs {
20218            cx.emit(EditorEvent::BreadcrumbsChanged);
20219        }
20220
20221        let project_settings = ProjectSettings::get_global(cx);
20222        self.serialize_dirty_buffers =
20223            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20224
20225        if self.mode.is_full() {
20226            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20227            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20228            if self.show_inline_diagnostics != show_inline_diagnostics {
20229                self.show_inline_diagnostics = show_inline_diagnostics;
20230                self.refresh_inline_diagnostics(false, window, cx);
20231            }
20232
20233            if self.git_blame_inline_enabled != inline_blame_enabled {
20234                self.toggle_git_blame_inline_internal(false, window, cx);
20235            }
20236
20237            let minimap_settings = EditorSettings::get_global(cx).minimap;
20238            if self.minimap_visibility != MinimapVisibility::Disabled {
20239                if self.minimap_visibility.settings_visibility()
20240                    != minimap_settings.minimap_enabled()
20241                {
20242                    self.set_minimap_visibility(
20243                        MinimapVisibility::for_mode(self.mode(), cx),
20244                        window,
20245                        cx,
20246                    );
20247                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20248                    minimap_entity.update(cx, |minimap_editor, cx| {
20249                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20250                    })
20251                }
20252            }
20253        }
20254
20255        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20256            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20257        }) {
20258            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20259                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20260            }
20261            self.refresh_colors(false, None, window, cx);
20262        }
20263
20264        cx.notify();
20265    }
20266
20267    pub fn set_searchable(&mut self, searchable: bool) {
20268        self.searchable = searchable;
20269    }
20270
20271    pub fn searchable(&self) -> bool {
20272        self.searchable
20273    }
20274
20275    fn open_proposed_changes_editor(
20276        &mut self,
20277        _: &OpenProposedChangesEditor,
20278        window: &mut Window,
20279        cx: &mut Context<Self>,
20280    ) {
20281        let Some(workspace) = self.workspace() else {
20282            cx.propagate();
20283            return;
20284        };
20285
20286        let selections = self.selections.all::<usize>(cx);
20287        let multi_buffer = self.buffer.read(cx);
20288        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20289        let mut new_selections_by_buffer = HashMap::default();
20290        for selection in selections {
20291            for (buffer, range, _) in
20292                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20293            {
20294                let mut range = range.to_point(buffer);
20295                range.start.column = 0;
20296                range.end.column = buffer.line_len(range.end.row);
20297                new_selections_by_buffer
20298                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20299                    .or_insert(Vec::new())
20300                    .push(range)
20301            }
20302        }
20303
20304        let proposed_changes_buffers = new_selections_by_buffer
20305            .into_iter()
20306            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20307            .collect::<Vec<_>>();
20308        let proposed_changes_editor = cx.new(|cx| {
20309            ProposedChangesEditor::new(
20310                "Proposed changes",
20311                proposed_changes_buffers,
20312                self.project.clone(),
20313                window,
20314                cx,
20315            )
20316        });
20317
20318        window.defer(cx, move |window, cx| {
20319            workspace.update(cx, |workspace, cx| {
20320                workspace.active_pane().update(cx, |pane, cx| {
20321                    pane.add_item(
20322                        Box::new(proposed_changes_editor),
20323                        true,
20324                        true,
20325                        None,
20326                        window,
20327                        cx,
20328                    );
20329                });
20330            });
20331        });
20332    }
20333
20334    pub fn open_excerpts_in_split(
20335        &mut self,
20336        _: &OpenExcerptsSplit,
20337        window: &mut Window,
20338        cx: &mut Context<Self>,
20339    ) {
20340        self.open_excerpts_common(None, true, window, cx)
20341    }
20342
20343    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20344        self.open_excerpts_common(None, false, window, cx)
20345    }
20346
20347    fn open_excerpts_common(
20348        &mut self,
20349        jump_data: Option<JumpData>,
20350        split: bool,
20351        window: &mut Window,
20352        cx: &mut Context<Self>,
20353    ) {
20354        let Some(workspace) = self.workspace() else {
20355            cx.propagate();
20356            return;
20357        };
20358
20359        if self.buffer.read(cx).is_singleton() {
20360            cx.propagate();
20361            return;
20362        }
20363
20364        let mut new_selections_by_buffer = HashMap::default();
20365        match &jump_data {
20366            Some(JumpData::MultiBufferPoint {
20367                excerpt_id,
20368                position,
20369                anchor,
20370                line_offset_from_top,
20371            }) => {
20372                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20373                if let Some(buffer) = multi_buffer_snapshot
20374                    .buffer_id_for_excerpt(*excerpt_id)
20375                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20376                {
20377                    let buffer_snapshot = buffer.read(cx).snapshot();
20378                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20379                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20380                    } else {
20381                        buffer_snapshot.clip_point(*position, Bias::Left)
20382                    };
20383                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20384                    new_selections_by_buffer.insert(
20385                        buffer,
20386                        (
20387                            vec![jump_to_offset..jump_to_offset],
20388                            Some(*line_offset_from_top),
20389                        ),
20390                    );
20391                }
20392            }
20393            Some(JumpData::MultiBufferRow {
20394                row,
20395                line_offset_from_top,
20396            }) => {
20397                let point = MultiBufferPoint::new(row.0, 0);
20398                if let Some((buffer, buffer_point, _)) =
20399                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20400                {
20401                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20402                    new_selections_by_buffer
20403                        .entry(buffer)
20404                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20405                        .0
20406                        .push(buffer_offset..buffer_offset)
20407                }
20408            }
20409            None => {
20410                let selections = self.selections.all::<usize>(cx);
20411                let multi_buffer = self.buffer.read(cx);
20412                for selection in selections {
20413                    for (snapshot, range, _, anchor) in multi_buffer
20414                        .snapshot(cx)
20415                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20416                    {
20417                        if let Some(anchor) = anchor {
20418                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20419                            else {
20420                                continue;
20421                            };
20422                            let offset = text::ToOffset::to_offset(
20423                                &anchor.text_anchor,
20424                                &buffer_handle.read(cx).snapshot(),
20425                            );
20426                            let range = offset..offset;
20427                            new_selections_by_buffer
20428                                .entry(buffer_handle)
20429                                .or_insert((Vec::new(), None))
20430                                .0
20431                                .push(range)
20432                        } else {
20433                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20434                            else {
20435                                continue;
20436                            };
20437                            new_selections_by_buffer
20438                                .entry(buffer_handle)
20439                                .or_insert((Vec::new(), None))
20440                                .0
20441                                .push(range)
20442                        }
20443                    }
20444                }
20445            }
20446        }
20447
20448        new_selections_by_buffer
20449            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20450
20451        if new_selections_by_buffer.is_empty() {
20452            return;
20453        }
20454
20455        // We defer the pane interaction because we ourselves are a workspace item
20456        // and activating a new item causes the pane to call a method on us reentrantly,
20457        // which panics if we're on the stack.
20458        window.defer(cx, move |window, cx| {
20459            workspace.update(cx, |workspace, cx| {
20460                let pane = if split {
20461                    workspace.adjacent_pane(window, cx)
20462                } else {
20463                    workspace.active_pane().clone()
20464                };
20465
20466                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20467                    let editor = buffer
20468                        .read(cx)
20469                        .file()
20470                        .is_none()
20471                        .then(|| {
20472                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20473                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20474                            // Instead, we try to activate the existing editor in the pane first.
20475                            let (editor, pane_item_index) =
20476                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20477                                    let editor = item.downcast::<Editor>()?;
20478                                    let singleton_buffer =
20479                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20480                                    if singleton_buffer == buffer {
20481                                        Some((editor, i))
20482                                    } else {
20483                                        None
20484                                    }
20485                                })?;
20486                            pane.update(cx, |pane, cx| {
20487                                pane.activate_item(pane_item_index, true, true, window, cx)
20488                            });
20489                            Some(editor)
20490                        })
20491                        .flatten()
20492                        .unwrap_or_else(|| {
20493                            workspace.open_project_item::<Self>(
20494                                pane.clone(),
20495                                buffer,
20496                                true,
20497                                true,
20498                                window,
20499                                cx,
20500                            )
20501                        });
20502
20503                    editor.update(cx, |editor, cx| {
20504                        let autoscroll = match scroll_offset {
20505                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20506                            None => Autoscroll::newest(),
20507                        };
20508                        let nav_history = editor.nav_history.take();
20509                        editor.change_selections(
20510                            SelectionEffects::scroll(autoscroll),
20511                            window,
20512                            cx,
20513                            |s| {
20514                                s.select_ranges(ranges);
20515                            },
20516                        );
20517                        editor.nav_history = nav_history;
20518                    });
20519                }
20520            })
20521        });
20522    }
20523
20524    // For now, don't allow opening excerpts in buffers that aren't backed by
20525    // regular project files.
20526    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20527        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20528    }
20529
20530    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20531        let snapshot = self.buffer.read(cx).read(cx);
20532        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20533        Some(
20534            ranges
20535                .iter()
20536                .map(move |range| {
20537                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20538                })
20539                .collect(),
20540        )
20541    }
20542
20543    fn selection_replacement_ranges(
20544        &self,
20545        range: Range<OffsetUtf16>,
20546        cx: &mut App,
20547    ) -> Vec<Range<OffsetUtf16>> {
20548        let selections = self.selections.all::<OffsetUtf16>(cx);
20549        let newest_selection = selections
20550            .iter()
20551            .max_by_key(|selection| selection.id)
20552            .unwrap();
20553        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20554        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20555        let snapshot = self.buffer.read(cx).read(cx);
20556        selections
20557            .into_iter()
20558            .map(|mut selection| {
20559                selection.start.0 =
20560                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20561                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20562                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20563                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20564            })
20565            .collect()
20566    }
20567
20568    fn report_editor_event(
20569        &self,
20570        reported_event: ReportEditorEvent,
20571        file_extension: Option<String>,
20572        cx: &App,
20573    ) {
20574        if cfg!(any(test, feature = "test-support")) {
20575            return;
20576        }
20577
20578        let Some(project) = &self.project else { return };
20579
20580        // If None, we are in a file without an extension
20581        let file = self
20582            .buffer
20583            .read(cx)
20584            .as_singleton()
20585            .and_then(|b| b.read(cx).file());
20586        let file_extension = file_extension.or(file
20587            .as_ref()
20588            .and_then(|file| Path::new(file.file_name(cx)).extension())
20589            .and_then(|e| e.to_str())
20590            .map(|a| a.to_string()));
20591
20592        let vim_mode = vim_enabled(cx);
20593
20594        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20595        let copilot_enabled = edit_predictions_provider
20596            == language::language_settings::EditPredictionProvider::Copilot;
20597        let copilot_enabled_for_language = self
20598            .buffer
20599            .read(cx)
20600            .language_settings(cx)
20601            .show_edit_predictions;
20602
20603        let project = project.read(cx);
20604        let event_type = reported_event.event_type();
20605
20606        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20607            telemetry::event!(
20608                event_type,
20609                type = if auto_saved {"autosave"} else {"manual"},
20610                file_extension,
20611                vim_mode,
20612                copilot_enabled,
20613                copilot_enabled_for_language,
20614                edit_predictions_provider,
20615                is_via_ssh = project.is_via_ssh(),
20616            );
20617        } else {
20618            telemetry::event!(
20619                event_type,
20620                file_extension,
20621                vim_mode,
20622                copilot_enabled,
20623                copilot_enabled_for_language,
20624                edit_predictions_provider,
20625                is_via_ssh = project.is_via_ssh(),
20626            );
20627        };
20628    }
20629
20630    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20631    /// with each line being an array of {text, highlight} objects.
20632    fn copy_highlight_json(
20633        &mut self,
20634        _: &CopyHighlightJson,
20635        window: &mut Window,
20636        cx: &mut Context<Self>,
20637    ) {
20638        #[derive(Serialize)]
20639        struct Chunk<'a> {
20640            text: String,
20641            highlight: Option<&'a str>,
20642        }
20643
20644        let snapshot = self.buffer.read(cx).snapshot(cx);
20645        let range = self
20646            .selected_text_range(false, window, cx)
20647            .and_then(|selection| {
20648                if selection.range.is_empty() {
20649                    None
20650                } else {
20651                    Some(selection.range)
20652                }
20653            })
20654            .unwrap_or_else(|| 0..snapshot.len());
20655
20656        let chunks = snapshot.chunks(range, true);
20657        let mut lines = Vec::new();
20658        let mut line: VecDeque<Chunk> = VecDeque::new();
20659
20660        let Some(style) = self.style.as_ref() else {
20661            return;
20662        };
20663
20664        for chunk in chunks {
20665            let highlight = chunk
20666                .syntax_highlight_id
20667                .and_then(|id| id.name(&style.syntax));
20668            let mut chunk_lines = chunk.text.split('\n').peekable();
20669            while let Some(text) = chunk_lines.next() {
20670                let mut merged_with_last_token = false;
20671                if let Some(last_token) = line.back_mut()
20672                    && last_token.highlight == highlight
20673                {
20674                    last_token.text.push_str(text);
20675                    merged_with_last_token = true;
20676                }
20677
20678                if !merged_with_last_token {
20679                    line.push_back(Chunk {
20680                        text: text.into(),
20681                        highlight,
20682                    });
20683                }
20684
20685                if chunk_lines.peek().is_some() {
20686                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20687                        line.pop_front();
20688                    }
20689                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20690                        line.pop_back();
20691                    }
20692
20693                    lines.push(mem::take(&mut line));
20694                }
20695            }
20696        }
20697
20698        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20699            return;
20700        };
20701        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20702    }
20703
20704    pub fn open_context_menu(
20705        &mut self,
20706        _: &OpenContextMenu,
20707        window: &mut Window,
20708        cx: &mut Context<Self>,
20709    ) {
20710        self.request_autoscroll(Autoscroll::newest(), cx);
20711        let position = self.selections.newest_display(cx).start;
20712        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20713    }
20714
20715    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20716        &self.inlay_hint_cache
20717    }
20718
20719    pub fn replay_insert_event(
20720        &mut self,
20721        text: &str,
20722        relative_utf16_range: Option<Range<isize>>,
20723        window: &mut Window,
20724        cx: &mut Context<Self>,
20725    ) {
20726        if !self.input_enabled {
20727            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20728            return;
20729        }
20730        if let Some(relative_utf16_range) = relative_utf16_range {
20731            let selections = self.selections.all::<OffsetUtf16>(cx);
20732            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20733                let new_ranges = selections.into_iter().map(|range| {
20734                    let start = OffsetUtf16(
20735                        range
20736                            .head()
20737                            .0
20738                            .saturating_add_signed(relative_utf16_range.start),
20739                    );
20740                    let end = OffsetUtf16(
20741                        range
20742                            .head()
20743                            .0
20744                            .saturating_add_signed(relative_utf16_range.end),
20745                    );
20746                    start..end
20747                });
20748                s.select_ranges(new_ranges);
20749            });
20750        }
20751
20752        self.handle_input(text, window, cx);
20753    }
20754
20755    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20756        let Some(provider) = self.semantics_provider.as_ref() else {
20757            return false;
20758        };
20759
20760        let mut supports = false;
20761        self.buffer().update(cx, |this, cx| {
20762            this.for_each_buffer(|buffer| {
20763                supports |= provider.supports_inlay_hints(buffer, cx);
20764            });
20765        });
20766
20767        supports
20768    }
20769
20770    pub fn is_focused(&self, window: &Window) -> bool {
20771        self.focus_handle.is_focused(window)
20772    }
20773
20774    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20775        cx.emit(EditorEvent::Focused);
20776
20777        if let Some(descendant) = self
20778            .last_focused_descendant
20779            .take()
20780            .and_then(|descendant| descendant.upgrade())
20781        {
20782            window.focus(&descendant);
20783        } else {
20784            if let Some(blame) = self.blame.as_ref() {
20785                blame.update(cx, GitBlame::focus)
20786            }
20787
20788            self.blink_manager.update(cx, BlinkManager::enable);
20789            self.show_cursor_names(window, cx);
20790            self.buffer.update(cx, |buffer, cx| {
20791                buffer.finalize_last_transaction(cx);
20792                if self.leader_id.is_none() {
20793                    buffer.set_active_selections(
20794                        &self.selections.disjoint_anchors(),
20795                        self.selections.line_mode,
20796                        self.cursor_shape,
20797                        cx,
20798                    );
20799                }
20800            });
20801        }
20802    }
20803
20804    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20805        cx.emit(EditorEvent::FocusedIn)
20806    }
20807
20808    fn handle_focus_out(
20809        &mut self,
20810        event: FocusOutEvent,
20811        _window: &mut Window,
20812        cx: &mut Context<Self>,
20813    ) {
20814        if event.blurred != self.focus_handle {
20815            self.last_focused_descendant = Some(event.blurred);
20816        }
20817        self.selection_drag_state = SelectionDragState::None;
20818        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20819    }
20820
20821    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20822        self.blink_manager.update(cx, BlinkManager::disable);
20823        self.buffer
20824            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20825
20826        if let Some(blame) = self.blame.as_ref() {
20827            blame.update(cx, GitBlame::blur)
20828        }
20829        if !self.hover_state.focused(window, cx) {
20830            hide_hover(self, cx);
20831        }
20832        if !self
20833            .context_menu
20834            .borrow()
20835            .as_ref()
20836            .is_some_and(|context_menu| context_menu.focused(window, cx))
20837        {
20838            self.hide_context_menu(window, cx);
20839        }
20840        self.discard_edit_prediction(false, cx);
20841        cx.emit(EditorEvent::Blurred);
20842        cx.notify();
20843    }
20844
20845    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20846        let mut pending: String = window
20847            .pending_input_keystrokes()
20848            .into_iter()
20849            .flatten()
20850            .filter_map(|keystroke| {
20851                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20852                    keystroke.key_char.clone()
20853                } else {
20854                    None
20855                }
20856            })
20857            .collect();
20858
20859        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20860            pending = "".to_string();
20861        }
20862
20863        let existing_pending = self
20864            .text_highlights::<PendingInput>(cx)
20865            .map(|(_, ranges)| ranges.to_vec());
20866        if existing_pending.is_none() && pending.is_empty() {
20867            return;
20868        }
20869        let transaction =
20870            self.transact(window, cx, |this, window, cx| {
20871                let selections = this.selections.all::<usize>(cx);
20872                let edits = selections
20873                    .iter()
20874                    .map(|selection| (selection.end..selection.end, pending.clone()));
20875                this.edit(edits, cx);
20876                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20877                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20878                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20879                    }));
20880                });
20881                if let Some(existing_ranges) = existing_pending {
20882                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20883                    this.edit(edits, cx);
20884                }
20885            });
20886
20887        let snapshot = self.snapshot(window, cx);
20888        let ranges = self
20889            .selections
20890            .all::<usize>(cx)
20891            .into_iter()
20892            .map(|selection| {
20893                snapshot.buffer_snapshot.anchor_after(selection.end)
20894                    ..snapshot
20895                        .buffer_snapshot
20896                        .anchor_before(selection.end + pending.len())
20897            })
20898            .collect();
20899
20900        if pending.is_empty() {
20901            self.clear_highlights::<PendingInput>(cx);
20902        } else {
20903            self.highlight_text::<PendingInput>(
20904                ranges,
20905                HighlightStyle {
20906                    underline: Some(UnderlineStyle {
20907                        thickness: px(1.),
20908                        color: None,
20909                        wavy: false,
20910                    }),
20911                    ..Default::default()
20912                },
20913                cx,
20914            );
20915        }
20916
20917        self.ime_transaction = self.ime_transaction.or(transaction);
20918        if let Some(transaction) = self.ime_transaction {
20919            self.buffer.update(cx, |buffer, cx| {
20920                buffer.group_until_transaction(transaction, cx);
20921            });
20922        }
20923
20924        if self.text_highlights::<PendingInput>(cx).is_none() {
20925            self.ime_transaction.take();
20926        }
20927    }
20928
20929    pub fn register_action_renderer(
20930        &mut self,
20931        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20932    ) -> Subscription {
20933        let id = self.next_editor_action_id.post_inc();
20934        self.editor_actions
20935            .borrow_mut()
20936            .insert(id, Box::new(listener));
20937
20938        let editor_actions = self.editor_actions.clone();
20939        Subscription::new(move || {
20940            editor_actions.borrow_mut().remove(&id);
20941        })
20942    }
20943
20944    pub fn register_action<A: Action>(
20945        &mut self,
20946        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20947    ) -> Subscription {
20948        let id = self.next_editor_action_id.post_inc();
20949        let listener = Arc::new(listener);
20950        self.editor_actions.borrow_mut().insert(
20951            id,
20952            Box::new(move |_, window, _| {
20953                let listener = listener.clone();
20954                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20955                    let action = action.downcast_ref().unwrap();
20956                    if phase == DispatchPhase::Bubble {
20957                        listener(action, window, cx)
20958                    }
20959                })
20960            }),
20961        );
20962
20963        let editor_actions = self.editor_actions.clone();
20964        Subscription::new(move || {
20965            editor_actions.borrow_mut().remove(&id);
20966        })
20967    }
20968
20969    pub fn file_header_size(&self) -> u32 {
20970        FILE_HEADER_HEIGHT
20971    }
20972
20973    pub fn restore(
20974        &mut self,
20975        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20976        window: &mut Window,
20977        cx: &mut Context<Self>,
20978    ) {
20979        let workspace = self.workspace();
20980        let project = self.project();
20981        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20982            let mut tasks = Vec::new();
20983            for (buffer_id, changes) in revert_changes {
20984                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20985                    buffer.update(cx, |buffer, cx| {
20986                        buffer.edit(
20987                            changes
20988                                .into_iter()
20989                                .map(|(range, text)| (range, text.to_string())),
20990                            None,
20991                            cx,
20992                        );
20993                    });
20994
20995                    if let Some(project) =
20996                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20997                    {
20998                        project.update(cx, |project, cx| {
20999                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21000                        })
21001                    }
21002                }
21003            }
21004            tasks
21005        });
21006        cx.spawn_in(window, async move |_, cx| {
21007            for (buffer, task) in save_tasks {
21008                let result = task.await;
21009                if result.is_err() {
21010                    let Some(path) = buffer
21011                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21012                        .ok()
21013                    else {
21014                        continue;
21015                    };
21016                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21017                        let Some(task) = cx
21018                            .update_window_entity(workspace, |workspace, window, cx| {
21019                                workspace
21020                                    .open_path_preview(path, None, false, false, false, window, cx)
21021                            })
21022                            .ok()
21023                        else {
21024                            continue;
21025                        };
21026                        task.await.log_err();
21027                    }
21028                }
21029            }
21030        })
21031        .detach();
21032        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21033            selections.refresh()
21034        });
21035    }
21036
21037    pub fn to_pixel_point(
21038        &self,
21039        source: multi_buffer::Anchor,
21040        editor_snapshot: &EditorSnapshot,
21041        window: &mut Window,
21042    ) -> Option<gpui::Point<Pixels>> {
21043        let source_point = source.to_display_point(editor_snapshot);
21044        self.display_to_pixel_point(source_point, editor_snapshot, window)
21045    }
21046
21047    pub fn display_to_pixel_point(
21048        &self,
21049        source: DisplayPoint,
21050        editor_snapshot: &EditorSnapshot,
21051        window: &mut Window,
21052    ) -> Option<gpui::Point<Pixels>> {
21053        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21054        let text_layout_details = self.text_layout_details(window);
21055        let scroll_top = text_layout_details
21056            .scroll_anchor
21057            .scroll_position(editor_snapshot)
21058            .y;
21059
21060        if source.row().as_f32() < scroll_top.floor() {
21061            return None;
21062        }
21063        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21064        let source_y = line_height * (source.row().as_f32() - scroll_top);
21065        Some(gpui::Point::new(source_x, source_y))
21066    }
21067
21068    pub fn has_visible_completions_menu(&self) -> bool {
21069        !self.edit_prediction_preview_is_active()
21070            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21071                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21072            })
21073    }
21074
21075    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21076        if self.mode.is_minimap() {
21077            return;
21078        }
21079        self.addons
21080            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21081    }
21082
21083    pub fn unregister_addon<T: Addon>(&mut self) {
21084        self.addons.remove(&std::any::TypeId::of::<T>());
21085    }
21086
21087    pub fn addon<T: Addon>(&self) -> Option<&T> {
21088        let type_id = std::any::TypeId::of::<T>();
21089        self.addons
21090            .get(&type_id)
21091            .and_then(|item| item.to_any().downcast_ref::<T>())
21092    }
21093
21094    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21095        let type_id = std::any::TypeId::of::<T>();
21096        self.addons
21097            .get_mut(&type_id)
21098            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21099    }
21100
21101    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21102        let text_layout_details = self.text_layout_details(window);
21103        let style = &text_layout_details.editor_style;
21104        let font_id = window.text_system().resolve_font(&style.text.font());
21105        let font_size = style.text.font_size.to_pixels(window.rem_size());
21106        let line_height = style.text.line_height_in_pixels(window.rem_size());
21107        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21108        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21109
21110        CharacterDimensions {
21111            em_width,
21112            em_advance,
21113            line_height,
21114        }
21115    }
21116
21117    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21118        self.load_diff_task.clone()
21119    }
21120
21121    fn read_metadata_from_db(
21122        &mut self,
21123        item_id: u64,
21124        workspace_id: WorkspaceId,
21125        window: &mut Window,
21126        cx: &mut Context<Editor>,
21127    ) {
21128        if self.is_singleton(cx)
21129            && !self.mode.is_minimap()
21130            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21131        {
21132            let buffer_snapshot = OnceCell::new();
21133
21134            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21135                && !folds.is_empty()
21136            {
21137                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21138                self.fold_ranges(
21139                    folds
21140                        .into_iter()
21141                        .map(|(start, end)| {
21142                            snapshot.clip_offset(start, Bias::Left)
21143                                ..snapshot.clip_offset(end, Bias::Right)
21144                        })
21145                        .collect(),
21146                    false,
21147                    window,
21148                    cx,
21149                );
21150            }
21151
21152            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21153                && !selections.is_empty()
21154            {
21155                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21156                // skip adding the initial selection to selection history
21157                self.selection_history.mode = SelectionHistoryMode::Skipping;
21158                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21159                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21160                        snapshot.clip_offset(start, Bias::Left)
21161                            ..snapshot.clip_offset(end, Bias::Right)
21162                    }));
21163                });
21164                self.selection_history.mode = SelectionHistoryMode::Normal;
21165            };
21166        }
21167
21168        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21169    }
21170
21171    fn update_lsp_data(
21172        &mut self,
21173        ignore_cache: bool,
21174        for_buffer: Option<BufferId>,
21175        window: &mut Window,
21176        cx: &mut Context<'_, Self>,
21177    ) {
21178        self.pull_diagnostics(for_buffer, window, cx);
21179        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21180    }
21181}
21182
21183fn vim_enabled(cx: &App) -> bool {
21184    cx.global::<SettingsStore>()
21185        .raw_user_settings()
21186        .get("vim_mode")
21187        == Some(&serde_json::Value::Bool(true))
21188}
21189
21190fn process_completion_for_edit(
21191    completion: &Completion,
21192    intent: CompletionIntent,
21193    buffer: &Entity<Buffer>,
21194    cursor_position: &text::Anchor,
21195    cx: &mut Context<Editor>,
21196) -> CompletionEdit {
21197    let buffer = buffer.read(cx);
21198    let buffer_snapshot = buffer.snapshot();
21199    let (snippet, new_text) = if completion.is_snippet() {
21200        // Workaround for typescript language server issues so that methods don't expand within
21201        // strings and functions with type expressions. The previous point is used because the query
21202        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21203        let mut snippet_source = completion.new_text.clone();
21204        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21205        previous_point.column = previous_point.column.saturating_sub(1);
21206        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21207            && scope.prefers_label_for_snippet_in_completion()
21208            && let Some(label) = completion.label()
21209            && matches!(
21210                completion.kind(),
21211                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21212            )
21213        {
21214            snippet_source = label;
21215        }
21216        match Snippet::parse(&snippet_source).log_err() {
21217            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21218            None => (None, completion.new_text.clone()),
21219        }
21220    } else {
21221        (None, completion.new_text.clone())
21222    };
21223
21224    let mut range_to_replace = {
21225        let replace_range = &completion.replace_range;
21226        if let CompletionSource::Lsp {
21227            insert_range: Some(insert_range),
21228            ..
21229        } = &completion.source
21230        {
21231            debug_assert_eq!(
21232                insert_range.start, replace_range.start,
21233                "insert_range and replace_range should start at the same position"
21234            );
21235            debug_assert!(
21236                insert_range
21237                    .start
21238                    .cmp(cursor_position, &buffer_snapshot)
21239                    .is_le(),
21240                "insert_range should start before or at cursor position"
21241            );
21242            debug_assert!(
21243                replace_range
21244                    .start
21245                    .cmp(cursor_position, &buffer_snapshot)
21246                    .is_le(),
21247                "replace_range should start before or at cursor position"
21248            );
21249
21250            let should_replace = match intent {
21251                CompletionIntent::CompleteWithInsert => false,
21252                CompletionIntent::CompleteWithReplace => true,
21253                CompletionIntent::Complete | CompletionIntent::Compose => {
21254                    let insert_mode =
21255                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21256                            .completions
21257                            .lsp_insert_mode;
21258                    match insert_mode {
21259                        LspInsertMode::Insert => false,
21260                        LspInsertMode::Replace => true,
21261                        LspInsertMode::ReplaceSubsequence => {
21262                            let mut text_to_replace = buffer.chars_for_range(
21263                                buffer.anchor_before(replace_range.start)
21264                                    ..buffer.anchor_after(replace_range.end),
21265                            );
21266                            let mut current_needle = text_to_replace.next();
21267                            for haystack_ch in completion.label.text.chars() {
21268                                if let Some(needle_ch) = current_needle
21269                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21270                                {
21271                                    current_needle = text_to_replace.next();
21272                                }
21273                            }
21274                            current_needle.is_none()
21275                        }
21276                        LspInsertMode::ReplaceSuffix => {
21277                            if replace_range
21278                                .end
21279                                .cmp(cursor_position, &buffer_snapshot)
21280                                .is_gt()
21281                            {
21282                                let range_after_cursor = *cursor_position..replace_range.end;
21283                                let text_after_cursor = buffer
21284                                    .text_for_range(
21285                                        buffer.anchor_before(range_after_cursor.start)
21286                                            ..buffer.anchor_after(range_after_cursor.end),
21287                                    )
21288                                    .collect::<String>()
21289                                    .to_ascii_lowercase();
21290                                completion
21291                                    .label
21292                                    .text
21293                                    .to_ascii_lowercase()
21294                                    .ends_with(&text_after_cursor)
21295                            } else {
21296                                true
21297                            }
21298                        }
21299                    }
21300                }
21301            };
21302
21303            if should_replace {
21304                replace_range.clone()
21305            } else {
21306                insert_range.clone()
21307            }
21308        } else {
21309            replace_range.clone()
21310        }
21311    };
21312
21313    if range_to_replace
21314        .end
21315        .cmp(cursor_position, &buffer_snapshot)
21316        .is_lt()
21317    {
21318        range_to_replace.end = *cursor_position;
21319    }
21320
21321    CompletionEdit {
21322        new_text,
21323        replace_range: range_to_replace.to_offset(buffer),
21324        snippet,
21325    }
21326}
21327
21328struct CompletionEdit {
21329    new_text: String,
21330    replace_range: Range<usize>,
21331    snippet: Option<Snippet>,
21332}
21333
21334fn insert_extra_newline_brackets(
21335    buffer: &MultiBufferSnapshot,
21336    range: Range<usize>,
21337    language: &language::LanguageScope,
21338) -> bool {
21339    let leading_whitespace_len = buffer
21340        .reversed_chars_at(range.start)
21341        .take_while(|c| c.is_whitespace() && *c != '\n')
21342        .map(|c| c.len_utf8())
21343        .sum::<usize>();
21344    let trailing_whitespace_len = buffer
21345        .chars_at(range.end)
21346        .take_while(|c| c.is_whitespace() && *c != '\n')
21347        .map(|c| c.len_utf8())
21348        .sum::<usize>();
21349    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21350
21351    language.brackets().any(|(pair, enabled)| {
21352        let pair_start = pair.start.trim_end();
21353        let pair_end = pair.end.trim_start();
21354
21355        enabled
21356            && pair.newline
21357            && buffer.contains_str_at(range.end, pair_end)
21358            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21359    })
21360}
21361
21362fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21363    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21364        [(buffer, range, _)] => (*buffer, range.clone()),
21365        _ => return false,
21366    };
21367    let pair = {
21368        let mut result: Option<BracketMatch> = None;
21369
21370        for pair in buffer
21371            .all_bracket_ranges(range.clone())
21372            .filter(move |pair| {
21373                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21374            })
21375        {
21376            let len = pair.close_range.end - pair.open_range.start;
21377
21378            if let Some(existing) = &result {
21379                let existing_len = existing.close_range.end - existing.open_range.start;
21380                if len > existing_len {
21381                    continue;
21382                }
21383            }
21384
21385            result = Some(pair);
21386        }
21387
21388        result
21389    };
21390    let Some(pair) = pair else {
21391        return false;
21392    };
21393    pair.newline_only
21394        && buffer
21395            .chars_for_range(pair.open_range.end..range.start)
21396            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21397            .all(|c| c.is_whitespace() && c != '\n')
21398}
21399
21400fn update_uncommitted_diff_for_buffer(
21401    editor: Entity<Editor>,
21402    project: &Entity<Project>,
21403    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21404    buffer: Entity<MultiBuffer>,
21405    cx: &mut App,
21406) -> Task<()> {
21407    let mut tasks = Vec::new();
21408    project.update(cx, |project, cx| {
21409        for buffer in buffers {
21410            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21411                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21412            }
21413        }
21414    });
21415    cx.spawn(async move |cx| {
21416        let diffs = future::join_all(tasks).await;
21417        if editor
21418            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21419            .unwrap_or(false)
21420        {
21421            return;
21422        }
21423
21424        buffer
21425            .update(cx, |buffer, cx| {
21426                for diff in diffs.into_iter().flatten() {
21427                    buffer.add_diff(diff, cx);
21428                }
21429            })
21430            .ok();
21431    })
21432}
21433
21434fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21435    let tab_size = tab_size.get() as usize;
21436    let mut width = offset;
21437
21438    for ch in text.chars() {
21439        width += if ch == '\t' {
21440            tab_size - (width % tab_size)
21441        } else {
21442            1
21443        };
21444    }
21445
21446    width - offset
21447}
21448
21449#[cfg(test)]
21450mod tests {
21451    use super::*;
21452
21453    #[test]
21454    fn test_string_size_with_expanded_tabs() {
21455        let nz = |val| NonZeroU32::new(val).unwrap();
21456        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21457        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21458        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21459        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21460        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21461        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21462        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21463        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21464    }
21465}
21466
21467/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21468struct WordBreakingTokenizer<'a> {
21469    input: &'a str,
21470}
21471
21472impl<'a> WordBreakingTokenizer<'a> {
21473    fn new(input: &'a str) -> Self {
21474        Self { input }
21475    }
21476}
21477
21478fn is_char_ideographic(ch: char) -> bool {
21479    use unicode_script::Script::*;
21480    use unicode_script::UnicodeScript;
21481    matches!(ch.script(), Han | Tangut | Yi)
21482}
21483
21484fn is_grapheme_ideographic(text: &str) -> bool {
21485    text.chars().any(is_char_ideographic)
21486}
21487
21488fn is_grapheme_whitespace(text: &str) -> bool {
21489    text.chars().any(|x| x.is_whitespace())
21490}
21491
21492fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21493    text.chars()
21494        .next()
21495        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21496}
21497
21498#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21499enum WordBreakToken<'a> {
21500    Word { token: &'a str, grapheme_len: usize },
21501    InlineWhitespace { token: &'a str, grapheme_len: usize },
21502    Newline,
21503}
21504
21505impl<'a> Iterator for WordBreakingTokenizer<'a> {
21506    /// Yields a span, the count of graphemes in the token, and whether it was
21507    /// whitespace. Note that it also breaks at word boundaries.
21508    type Item = WordBreakToken<'a>;
21509
21510    fn next(&mut self) -> Option<Self::Item> {
21511        use unicode_segmentation::UnicodeSegmentation;
21512        if self.input.is_empty() {
21513            return None;
21514        }
21515
21516        let mut iter = self.input.graphemes(true).peekable();
21517        let mut offset = 0;
21518        let mut grapheme_len = 0;
21519        if let Some(first_grapheme) = iter.next() {
21520            let is_newline = first_grapheme == "\n";
21521            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21522            offset += first_grapheme.len();
21523            grapheme_len += 1;
21524            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21525                if let Some(grapheme) = iter.peek().copied()
21526                    && should_stay_with_preceding_ideograph(grapheme)
21527                {
21528                    offset += grapheme.len();
21529                    grapheme_len += 1;
21530                }
21531            } else {
21532                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21533                let mut next_word_bound = words.peek().copied();
21534                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21535                    next_word_bound = words.next();
21536                }
21537                while let Some(grapheme) = iter.peek().copied() {
21538                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21539                        break;
21540                    };
21541                    if is_grapheme_whitespace(grapheme) != is_whitespace
21542                        || (grapheme == "\n") != is_newline
21543                    {
21544                        break;
21545                    };
21546                    offset += grapheme.len();
21547                    grapheme_len += 1;
21548                    iter.next();
21549                }
21550            }
21551            let token = &self.input[..offset];
21552            self.input = &self.input[offset..];
21553            if token == "\n" {
21554                Some(WordBreakToken::Newline)
21555            } else if is_whitespace {
21556                Some(WordBreakToken::InlineWhitespace {
21557                    token,
21558                    grapheme_len,
21559                })
21560            } else {
21561                Some(WordBreakToken::Word {
21562                    token,
21563                    grapheme_len,
21564                })
21565            }
21566        } else {
21567            None
21568        }
21569    }
21570}
21571
21572#[test]
21573fn test_word_breaking_tokenizer() {
21574    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21575        ("", &[]),
21576        ("  ", &[whitespace("  ", 2)]),
21577        ("Ʒ", &[word("Ʒ", 1)]),
21578        ("Ǽ", &[word("Ǽ", 1)]),
21579        ("", &[word("", 1)]),
21580        ("⋑⋑", &[word("⋑⋑", 2)]),
21581        (
21582            "原理,进而",
21583            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21584        ),
21585        (
21586            "hello world",
21587            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21588        ),
21589        (
21590            "hello, world",
21591            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21592        ),
21593        (
21594            "  hello world",
21595            &[
21596                whitespace("  ", 2),
21597                word("hello", 5),
21598                whitespace(" ", 1),
21599                word("world", 5),
21600            ],
21601        ),
21602        (
21603            "这是什么 \n 钢笔",
21604            &[
21605                word("", 1),
21606                word("", 1),
21607                word("", 1),
21608                word("", 1),
21609                whitespace(" ", 1),
21610                newline(),
21611                whitespace(" ", 1),
21612                word("", 1),
21613                word("", 1),
21614            ],
21615        ),
21616        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21617    ];
21618
21619    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21620        WordBreakToken::Word {
21621            token,
21622            grapheme_len,
21623        }
21624    }
21625
21626    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21627        WordBreakToken::InlineWhitespace {
21628            token,
21629            grapheme_len,
21630        }
21631    }
21632
21633    fn newline() -> WordBreakToken<'static> {
21634        WordBreakToken::Newline
21635    }
21636
21637    for (input, result) in tests {
21638        assert_eq!(
21639            WordBreakingTokenizer::new(input)
21640                .collect::<Vec<_>>()
21641                .as_slice(),
21642            *result,
21643        );
21644    }
21645}
21646
21647fn wrap_with_prefix(
21648    first_line_prefix: String,
21649    subsequent_lines_prefix: String,
21650    unwrapped_text: String,
21651    wrap_column: usize,
21652    tab_size: NonZeroU32,
21653    preserve_existing_whitespace: bool,
21654) -> String {
21655    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21656    let subsequent_lines_prefix_len =
21657        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21658    let mut wrapped_text = String::new();
21659    let mut current_line = first_line_prefix;
21660    let mut is_first_line = true;
21661
21662    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21663    let mut current_line_len = first_line_prefix_len;
21664    let mut in_whitespace = false;
21665    for token in tokenizer {
21666        let have_preceding_whitespace = in_whitespace;
21667        match token {
21668            WordBreakToken::Word {
21669                token,
21670                grapheme_len,
21671            } => {
21672                in_whitespace = false;
21673                let current_prefix_len = if is_first_line {
21674                    first_line_prefix_len
21675                } else {
21676                    subsequent_lines_prefix_len
21677                };
21678                if current_line_len + grapheme_len > wrap_column
21679                    && current_line_len != current_prefix_len
21680                {
21681                    wrapped_text.push_str(current_line.trim_end());
21682                    wrapped_text.push('\n');
21683                    is_first_line = false;
21684                    current_line = subsequent_lines_prefix.clone();
21685                    current_line_len = subsequent_lines_prefix_len;
21686                }
21687                current_line.push_str(token);
21688                current_line_len += grapheme_len;
21689            }
21690            WordBreakToken::InlineWhitespace {
21691                mut token,
21692                mut grapheme_len,
21693            } => {
21694                in_whitespace = true;
21695                if have_preceding_whitespace && !preserve_existing_whitespace {
21696                    continue;
21697                }
21698                if !preserve_existing_whitespace {
21699                    token = " ";
21700                    grapheme_len = 1;
21701                }
21702                let current_prefix_len = if is_first_line {
21703                    first_line_prefix_len
21704                } else {
21705                    subsequent_lines_prefix_len
21706                };
21707                if current_line_len + grapheme_len > wrap_column {
21708                    wrapped_text.push_str(current_line.trim_end());
21709                    wrapped_text.push('\n');
21710                    is_first_line = false;
21711                    current_line = subsequent_lines_prefix.clone();
21712                    current_line_len = subsequent_lines_prefix_len;
21713                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21714                    current_line.push_str(token);
21715                    current_line_len += grapheme_len;
21716                }
21717            }
21718            WordBreakToken::Newline => {
21719                in_whitespace = true;
21720                let current_prefix_len = if is_first_line {
21721                    first_line_prefix_len
21722                } else {
21723                    subsequent_lines_prefix_len
21724                };
21725                if preserve_existing_whitespace {
21726                    wrapped_text.push_str(current_line.trim_end());
21727                    wrapped_text.push('\n');
21728                    is_first_line = false;
21729                    current_line = subsequent_lines_prefix.clone();
21730                    current_line_len = subsequent_lines_prefix_len;
21731                } else if have_preceding_whitespace {
21732                    continue;
21733                } else if current_line_len + 1 > wrap_column
21734                    && current_line_len != current_prefix_len
21735                {
21736                    wrapped_text.push_str(current_line.trim_end());
21737                    wrapped_text.push('\n');
21738                    is_first_line = false;
21739                    current_line = subsequent_lines_prefix.clone();
21740                    current_line_len = subsequent_lines_prefix_len;
21741                } else if current_line_len != current_prefix_len {
21742                    current_line.push(' ');
21743                    current_line_len += 1;
21744                }
21745            }
21746        }
21747    }
21748
21749    if !current_line.is_empty() {
21750        wrapped_text.push_str(&current_line);
21751    }
21752    wrapped_text
21753}
21754
21755#[test]
21756fn test_wrap_with_prefix() {
21757    assert_eq!(
21758        wrap_with_prefix(
21759            "# ".to_string(),
21760            "# ".to_string(),
21761            "abcdefg".to_string(),
21762            4,
21763            NonZeroU32::new(4).unwrap(),
21764            false,
21765        ),
21766        "# abcdefg"
21767    );
21768    assert_eq!(
21769        wrap_with_prefix(
21770            "".to_string(),
21771            "".to_string(),
21772            "\thello world".to_string(),
21773            8,
21774            NonZeroU32::new(4).unwrap(),
21775            false,
21776        ),
21777        "hello\nworld"
21778    );
21779    assert_eq!(
21780        wrap_with_prefix(
21781            "// ".to_string(),
21782            "// ".to_string(),
21783            "xx \nyy zz aa bb cc".to_string(),
21784            12,
21785            NonZeroU32::new(4).unwrap(),
21786            false,
21787        ),
21788        "// xx yy zz\n// aa bb cc"
21789    );
21790    assert_eq!(
21791        wrap_with_prefix(
21792            String::new(),
21793            String::new(),
21794            "这是什么 \n 钢笔".to_string(),
21795            3,
21796            NonZeroU32::new(4).unwrap(),
21797            false,
21798        ),
21799        "这是什\n么 钢\n"
21800    );
21801}
21802
21803pub trait CollaborationHub {
21804    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21805    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21806    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21807}
21808
21809impl CollaborationHub for Entity<Project> {
21810    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21811        self.read(cx).collaborators()
21812    }
21813
21814    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21815        self.read(cx).user_store().read(cx).participant_indices()
21816    }
21817
21818    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21819        let this = self.read(cx);
21820        let user_ids = this.collaborators().values().map(|c| c.user_id);
21821        this.user_store().read(cx).participant_names(user_ids, cx)
21822    }
21823}
21824
21825pub trait SemanticsProvider {
21826    fn hover(
21827        &self,
21828        buffer: &Entity<Buffer>,
21829        position: text::Anchor,
21830        cx: &mut App,
21831    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21832
21833    fn inline_values(
21834        &self,
21835        buffer_handle: Entity<Buffer>,
21836        range: Range<text::Anchor>,
21837        cx: &mut App,
21838    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21839
21840    fn inlay_hints(
21841        &self,
21842        buffer_handle: Entity<Buffer>,
21843        range: Range<text::Anchor>,
21844        cx: &mut App,
21845    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21846
21847    fn resolve_inlay_hint(
21848        &self,
21849        hint: InlayHint,
21850        buffer_handle: Entity<Buffer>,
21851        server_id: LanguageServerId,
21852        cx: &mut App,
21853    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21854
21855    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21856
21857    fn document_highlights(
21858        &self,
21859        buffer: &Entity<Buffer>,
21860        position: text::Anchor,
21861        cx: &mut App,
21862    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21863
21864    fn definitions(
21865        &self,
21866        buffer: &Entity<Buffer>,
21867        position: text::Anchor,
21868        kind: GotoDefinitionKind,
21869        cx: &mut App,
21870    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21871
21872    fn range_for_rename(
21873        &self,
21874        buffer: &Entity<Buffer>,
21875        position: text::Anchor,
21876        cx: &mut App,
21877    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21878
21879    fn perform_rename(
21880        &self,
21881        buffer: &Entity<Buffer>,
21882        position: text::Anchor,
21883        new_name: String,
21884        cx: &mut App,
21885    ) -> Option<Task<Result<ProjectTransaction>>>;
21886}
21887
21888pub trait CompletionProvider {
21889    fn completions(
21890        &self,
21891        excerpt_id: ExcerptId,
21892        buffer: &Entity<Buffer>,
21893        buffer_position: text::Anchor,
21894        trigger: CompletionContext,
21895        window: &mut Window,
21896        cx: &mut Context<Editor>,
21897    ) -> Task<Result<Vec<CompletionResponse>>>;
21898
21899    fn resolve_completions(
21900        &self,
21901        _buffer: Entity<Buffer>,
21902        _completion_indices: Vec<usize>,
21903        _completions: Rc<RefCell<Box<[Completion]>>>,
21904        _cx: &mut Context<Editor>,
21905    ) -> Task<Result<bool>> {
21906        Task::ready(Ok(false))
21907    }
21908
21909    fn apply_additional_edits_for_completion(
21910        &self,
21911        _buffer: Entity<Buffer>,
21912        _completions: Rc<RefCell<Box<[Completion]>>>,
21913        _completion_index: usize,
21914        _push_to_history: bool,
21915        _cx: &mut Context<Editor>,
21916    ) -> Task<Result<Option<language::Transaction>>> {
21917        Task::ready(Ok(None))
21918    }
21919
21920    fn is_completion_trigger(
21921        &self,
21922        buffer: &Entity<Buffer>,
21923        position: language::Anchor,
21924        text: &str,
21925        trigger_in_words: bool,
21926        menu_is_open: bool,
21927        cx: &mut Context<Editor>,
21928    ) -> bool;
21929
21930    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21931
21932    fn sort_completions(&self) -> bool {
21933        true
21934    }
21935
21936    fn filter_completions(&self) -> bool {
21937        true
21938    }
21939}
21940
21941pub trait CodeActionProvider {
21942    fn id(&self) -> Arc<str>;
21943
21944    fn code_actions(
21945        &self,
21946        buffer: &Entity<Buffer>,
21947        range: Range<text::Anchor>,
21948        window: &mut Window,
21949        cx: &mut App,
21950    ) -> Task<Result<Vec<CodeAction>>>;
21951
21952    fn apply_code_action(
21953        &self,
21954        buffer_handle: Entity<Buffer>,
21955        action: CodeAction,
21956        excerpt_id: ExcerptId,
21957        push_to_history: bool,
21958        window: &mut Window,
21959        cx: &mut App,
21960    ) -> Task<Result<ProjectTransaction>>;
21961}
21962
21963impl CodeActionProvider for Entity<Project> {
21964    fn id(&self) -> Arc<str> {
21965        "project".into()
21966    }
21967
21968    fn code_actions(
21969        &self,
21970        buffer: &Entity<Buffer>,
21971        range: Range<text::Anchor>,
21972        _window: &mut Window,
21973        cx: &mut App,
21974    ) -> Task<Result<Vec<CodeAction>>> {
21975        self.update(cx, |project, cx| {
21976            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21977            let code_actions = project.code_actions(buffer, range, None, cx);
21978            cx.background_spawn(async move {
21979                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21980                Ok(code_lens_actions
21981                    .context("code lens fetch")?
21982                    .into_iter()
21983                    .flatten()
21984                    .chain(
21985                        code_actions
21986                            .context("code action fetch")?
21987                            .into_iter()
21988                            .flatten(),
21989                    )
21990                    .collect())
21991            })
21992        })
21993    }
21994
21995    fn apply_code_action(
21996        &self,
21997        buffer_handle: Entity<Buffer>,
21998        action: CodeAction,
21999        _excerpt_id: ExcerptId,
22000        push_to_history: bool,
22001        _window: &mut Window,
22002        cx: &mut App,
22003    ) -> Task<Result<ProjectTransaction>> {
22004        self.update(cx, |project, cx| {
22005            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22006        })
22007    }
22008}
22009
22010fn snippet_completions(
22011    project: &Project,
22012    buffer: &Entity<Buffer>,
22013    buffer_position: text::Anchor,
22014    cx: &mut App,
22015) -> Task<Result<CompletionResponse>> {
22016    let languages = buffer.read(cx).languages_at(buffer_position);
22017    let snippet_store = project.snippets().read(cx);
22018
22019    let scopes: Vec<_> = languages
22020        .iter()
22021        .filter_map(|language| {
22022            let language_name = language.lsp_id();
22023            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22024
22025            if snippets.is_empty() {
22026                None
22027            } else {
22028                Some((language.default_scope(), snippets))
22029            }
22030        })
22031        .collect();
22032
22033    if scopes.is_empty() {
22034        return Task::ready(Ok(CompletionResponse {
22035            completions: vec![],
22036            is_incomplete: false,
22037        }));
22038    }
22039
22040    let snapshot = buffer.read(cx).text_snapshot();
22041    let chars: String = snapshot
22042        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22043        .collect();
22044    let executor = cx.background_executor().clone();
22045
22046    cx.background_spawn(async move {
22047        let mut is_incomplete = false;
22048        let mut completions: Vec<Completion> = Vec::new();
22049        for (scope, snippets) in scopes.into_iter() {
22050            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22051            let mut last_word = chars
22052                .chars()
22053                .take_while(|c| classifier.is_word(*c))
22054                .collect::<String>();
22055            last_word = last_word.chars().rev().collect();
22056
22057            if last_word.is_empty() {
22058                return Ok(CompletionResponse {
22059                    completions: vec![],
22060                    is_incomplete: true,
22061                });
22062            }
22063
22064            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22065            let to_lsp = |point: &text::Anchor| {
22066                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22067                point_to_lsp(end)
22068            };
22069            let lsp_end = to_lsp(&buffer_position);
22070
22071            let candidates = snippets
22072                .iter()
22073                .enumerate()
22074                .flat_map(|(ix, snippet)| {
22075                    snippet
22076                        .prefix
22077                        .iter()
22078                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22079                })
22080                .collect::<Vec<StringMatchCandidate>>();
22081
22082            const MAX_RESULTS: usize = 100;
22083            let mut matches = fuzzy::match_strings(
22084                &candidates,
22085                &last_word,
22086                last_word.chars().any(|c| c.is_uppercase()),
22087                true,
22088                MAX_RESULTS,
22089                &Default::default(),
22090                executor.clone(),
22091            )
22092            .await;
22093
22094            if matches.len() >= MAX_RESULTS {
22095                is_incomplete = true;
22096            }
22097
22098            // Remove all candidates where the query's start does not match the start of any word in the candidate
22099            if let Some(query_start) = last_word.chars().next() {
22100                matches.retain(|string_match| {
22101                    split_words(&string_match.string).any(|word| {
22102                        // Check that the first codepoint of the word as lowercase matches the first
22103                        // codepoint of the query as lowercase
22104                        word.chars()
22105                            .flat_map(|codepoint| codepoint.to_lowercase())
22106                            .zip(query_start.to_lowercase())
22107                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22108                    })
22109                });
22110            }
22111
22112            let matched_strings = matches
22113                .into_iter()
22114                .map(|m| m.string)
22115                .collect::<HashSet<_>>();
22116
22117            completions.extend(snippets.iter().filter_map(|snippet| {
22118                let matching_prefix = snippet
22119                    .prefix
22120                    .iter()
22121                    .find(|prefix| matched_strings.contains(*prefix))?;
22122                let start = as_offset - last_word.len();
22123                let start = snapshot.anchor_before(start);
22124                let range = start..buffer_position;
22125                let lsp_start = to_lsp(&start);
22126                let lsp_range = lsp::Range {
22127                    start: lsp_start,
22128                    end: lsp_end,
22129                };
22130                Some(Completion {
22131                    replace_range: range,
22132                    new_text: snippet.body.clone(),
22133                    source: CompletionSource::Lsp {
22134                        insert_range: None,
22135                        server_id: LanguageServerId(usize::MAX),
22136                        resolved: true,
22137                        lsp_completion: Box::new(lsp::CompletionItem {
22138                            label: snippet.prefix.first().unwrap().clone(),
22139                            kind: Some(CompletionItemKind::SNIPPET),
22140                            label_details: snippet.description.as_ref().map(|description| {
22141                                lsp::CompletionItemLabelDetails {
22142                                    detail: Some(description.clone()),
22143                                    description: None,
22144                                }
22145                            }),
22146                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22147                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22148                                lsp::InsertReplaceEdit {
22149                                    new_text: snippet.body.clone(),
22150                                    insert: lsp_range,
22151                                    replace: lsp_range,
22152                                },
22153                            )),
22154                            filter_text: Some(snippet.body.clone()),
22155                            sort_text: Some(char::MAX.to_string()),
22156                            ..lsp::CompletionItem::default()
22157                        }),
22158                        lsp_defaults: None,
22159                    },
22160                    label: CodeLabel {
22161                        text: matching_prefix.clone(),
22162                        runs: Vec::new(),
22163                        filter_range: 0..matching_prefix.len(),
22164                    },
22165                    icon_path: None,
22166                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22167                        single_line: snippet.name.clone().into(),
22168                        plain_text: snippet
22169                            .description
22170                            .clone()
22171                            .map(|description| description.into()),
22172                    }),
22173                    insert_text_mode: None,
22174                    confirm: None,
22175                })
22176            }))
22177        }
22178
22179        Ok(CompletionResponse {
22180            completions,
22181            is_incomplete,
22182        })
22183    })
22184}
22185
22186impl CompletionProvider for Entity<Project> {
22187    fn completions(
22188        &self,
22189        _excerpt_id: ExcerptId,
22190        buffer: &Entity<Buffer>,
22191        buffer_position: text::Anchor,
22192        options: CompletionContext,
22193        _window: &mut Window,
22194        cx: &mut Context<Editor>,
22195    ) -> Task<Result<Vec<CompletionResponse>>> {
22196        self.update(cx, |project, cx| {
22197            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22198            let project_completions = project.completions(buffer, buffer_position, options, cx);
22199            cx.background_spawn(async move {
22200                let mut responses = project_completions.await?;
22201                let snippets = snippets.await?;
22202                if !snippets.completions.is_empty() {
22203                    responses.push(snippets);
22204                }
22205                Ok(responses)
22206            })
22207        })
22208    }
22209
22210    fn resolve_completions(
22211        &self,
22212        buffer: Entity<Buffer>,
22213        completion_indices: Vec<usize>,
22214        completions: Rc<RefCell<Box<[Completion]>>>,
22215        cx: &mut Context<Editor>,
22216    ) -> Task<Result<bool>> {
22217        self.update(cx, |project, cx| {
22218            project.lsp_store().update(cx, |lsp_store, cx| {
22219                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22220            })
22221        })
22222    }
22223
22224    fn apply_additional_edits_for_completion(
22225        &self,
22226        buffer: Entity<Buffer>,
22227        completions: Rc<RefCell<Box<[Completion]>>>,
22228        completion_index: usize,
22229        push_to_history: bool,
22230        cx: &mut Context<Editor>,
22231    ) -> Task<Result<Option<language::Transaction>>> {
22232        self.update(cx, |project, cx| {
22233            project.lsp_store().update(cx, |lsp_store, cx| {
22234                lsp_store.apply_additional_edits_for_completion(
22235                    buffer,
22236                    completions,
22237                    completion_index,
22238                    push_to_history,
22239                    cx,
22240                )
22241            })
22242        })
22243    }
22244
22245    fn is_completion_trigger(
22246        &self,
22247        buffer: &Entity<Buffer>,
22248        position: language::Anchor,
22249        text: &str,
22250        trigger_in_words: bool,
22251        menu_is_open: bool,
22252        cx: &mut Context<Editor>,
22253    ) -> bool {
22254        let mut chars = text.chars();
22255        let char = if let Some(char) = chars.next() {
22256            char
22257        } else {
22258            return false;
22259        };
22260        if chars.next().is_some() {
22261            return false;
22262        }
22263
22264        let buffer = buffer.read(cx);
22265        let snapshot = buffer.snapshot();
22266        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22267            return false;
22268        }
22269        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22270        if trigger_in_words && classifier.is_word(char) {
22271            return true;
22272        }
22273
22274        buffer.completion_triggers().contains(text)
22275    }
22276}
22277
22278impl SemanticsProvider for Entity<Project> {
22279    fn hover(
22280        &self,
22281        buffer: &Entity<Buffer>,
22282        position: text::Anchor,
22283        cx: &mut App,
22284    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22285        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22286    }
22287
22288    fn document_highlights(
22289        &self,
22290        buffer: &Entity<Buffer>,
22291        position: text::Anchor,
22292        cx: &mut App,
22293    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22294        Some(self.update(cx, |project, cx| {
22295            project.document_highlights(buffer, position, cx)
22296        }))
22297    }
22298
22299    fn definitions(
22300        &self,
22301        buffer: &Entity<Buffer>,
22302        position: text::Anchor,
22303        kind: GotoDefinitionKind,
22304        cx: &mut App,
22305    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22306        Some(self.update(cx, |project, cx| match kind {
22307            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22308            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22309            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22310            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22311        }))
22312    }
22313
22314    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22315        self.update(cx, |project, cx| {
22316            if project
22317                .active_debug_session(cx)
22318                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22319            {
22320                return true;
22321            }
22322
22323            buffer.update(cx, |buffer, cx| {
22324                project.any_language_server_supports_inlay_hints(buffer, cx)
22325            })
22326        })
22327    }
22328
22329    fn inline_values(
22330        &self,
22331        buffer_handle: Entity<Buffer>,
22332        range: Range<text::Anchor>,
22333        cx: &mut App,
22334    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22335        self.update(cx, |project, cx| {
22336            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22337
22338            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22339        })
22340    }
22341
22342    fn inlay_hints(
22343        &self,
22344        buffer_handle: Entity<Buffer>,
22345        range: Range<text::Anchor>,
22346        cx: &mut App,
22347    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22348        Some(self.update(cx, |project, cx| {
22349            project.inlay_hints(buffer_handle, range, cx)
22350        }))
22351    }
22352
22353    fn resolve_inlay_hint(
22354        &self,
22355        hint: InlayHint,
22356        buffer_handle: Entity<Buffer>,
22357        server_id: LanguageServerId,
22358        cx: &mut App,
22359    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22360        Some(self.update(cx, |project, cx| {
22361            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22362        }))
22363    }
22364
22365    fn range_for_rename(
22366        &self,
22367        buffer: &Entity<Buffer>,
22368        position: text::Anchor,
22369        cx: &mut App,
22370    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22371        Some(self.update(cx, |project, cx| {
22372            let buffer = buffer.clone();
22373            let task = project.prepare_rename(buffer.clone(), position, cx);
22374            cx.spawn(async move |_, cx| {
22375                Ok(match task.await? {
22376                    PrepareRenameResponse::Success(range) => Some(range),
22377                    PrepareRenameResponse::InvalidPosition => None,
22378                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22379                        // Fallback on using TreeSitter info to determine identifier range
22380                        buffer.read_with(cx, |buffer, _| {
22381                            let snapshot = buffer.snapshot();
22382                            let (range, kind) = snapshot.surrounding_word(position, false);
22383                            if kind != Some(CharKind::Word) {
22384                                return None;
22385                            }
22386                            Some(
22387                                snapshot.anchor_before(range.start)
22388                                    ..snapshot.anchor_after(range.end),
22389                            )
22390                        })?
22391                    }
22392                })
22393            })
22394        }))
22395    }
22396
22397    fn perform_rename(
22398        &self,
22399        buffer: &Entity<Buffer>,
22400        position: text::Anchor,
22401        new_name: String,
22402        cx: &mut App,
22403    ) -> Option<Task<Result<ProjectTransaction>>> {
22404        Some(self.update(cx, |project, cx| {
22405            project.perform_rename(buffer.clone(), position, new_name, cx)
22406        }))
22407    }
22408}
22409
22410fn inlay_hint_settings(
22411    location: Anchor,
22412    snapshot: &MultiBufferSnapshot,
22413    cx: &mut Context<Editor>,
22414) -> InlayHintSettings {
22415    let file = snapshot.file_at(location);
22416    let language = snapshot.language_at(location).map(|l| l.name());
22417    language_settings(language, file, cx).inlay_hints
22418}
22419
22420fn consume_contiguous_rows(
22421    contiguous_row_selections: &mut Vec<Selection<Point>>,
22422    selection: &Selection<Point>,
22423    display_map: &DisplaySnapshot,
22424    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22425) -> (MultiBufferRow, MultiBufferRow) {
22426    contiguous_row_selections.push(selection.clone());
22427    let start_row = starting_row(selection, display_map);
22428    let mut end_row = ending_row(selection, display_map);
22429
22430    while let Some(next_selection) = selections.peek() {
22431        if next_selection.start.row <= end_row.0 {
22432            end_row = ending_row(next_selection, display_map);
22433            contiguous_row_selections.push(selections.next().unwrap().clone());
22434        } else {
22435            break;
22436        }
22437    }
22438    (start_row, end_row)
22439}
22440
22441fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22442    if selection.start.column > 0 {
22443        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22444    } else {
22445        MultiBufferRow(selection.start.row)
22446    }
22447}
22448
22449fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22450    if next_selection.end.column > 0 || next_selection.is_empty() {
22451        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22452    } else {
22453        MultiBufferRow(next_selection.end.row)
22454    }
22455}
22456
22457impl EditorSnapshot {
22458    pub fn remote_selections_in_range<'a>(
22459        &'a self,
22460        range: &'a Range<Anchor>,
22461        collaboration_hub: &dyn CollaborationHub,
22462        cx: &'a App,
22463    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22464        let participant_names = collaboration_hub.user_names(cx);
22465        let participant_indices = collaboration_hub.user_participant_indices(cx);
22466        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22467        let collaborators_by_replica_id = collaborators_by_peer_id
22468            .values()
22469            .map(|collaborator| (collaborator.replica_id, collaborator))
22470            .collect::<HashMap<_, _>>();
22471        self.buffer_snapshot
22472            .selections_in_range(range, false)
22473            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22474                if replica_id == AGENT_REPLICA_ID {
22475                    Some(RemoteSelection {
22476                        replica_id,
22477                        selection,
22478                        cursor_shape,
22479                        line_mode,
22480                        collaborator_id: CollaboratorId::Agent,
22481                        user_name: Some("Agent".into()),
22482                        color: cx.theme().players().agent(),
22483                    })
22484                } else {
22485                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22486                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22487                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22488                    Some(RemoteSelection {
22489                        replica_id,
22490                        selection,
22491                        cursor_shape,
22492                        line_mode,
22493                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22494                        user_name,
22495                        color: if let Some(index) = participant_index {
22496                            cx.theme().players().color_for_participant(index.0)
22497                        } else {
22498                            cx.theme().players().absent()
22499                        },
22500                    })
22501                }
22502            })
22503    }
22504
22505    pub fn hunks_for_ranges(
22506        &self,
22507        ranges: impl IntoIterator<Item = Range<Point>>,
22508    ) -> Vec<MultiBufferDiffHunk> {
22509        let mut hunks = Vec::new();
22510        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22511            HashMap::default();
22512        for query_range in ranges {
22513            let query_rows =
22514                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22515            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22516                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22517            ) {
22518                // Include deleted hunks that are adjacent to the query range, because
22519                // otherwise they would be missed.
22520                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22521                if hunk.status().is_deleted() {
22522                    intersects_range |= hunk.row_range.start == query_rows.end;
22523                    intersects_range |= hunk.row_range.end == query_rows.start;
22524                }
22525                if intersects_range {
22526                    if !processed_buffer_rows
22527                        .entry(hunk.buffer_id)
22528                        .or_default()
22529                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22530                    {
22531                        continue;
22532                    }
22533                    hunks.push(hunk);
22534                }
22535            }
22536        }
22537
22538        hunks
22539    }
22540
22541    fn display_diff_hunks_for_rows<'a>(
22542        &'a self,
22543        display_rows: Range<DisplayRow>,
22544        folded_buffers: &'a HashSet<BufferId>,
22545    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22546        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22547        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22548
22549        self.buffer_snapshot
22550            .diff_hunks_in_range(buffer_start..buffer_end)
22551            .filter_map(|hunk| {
22552                if folded_buffers.contains(&hunk.buffer_id) {
22553                    return None;
22554                }
22555
22556                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22557                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22558
22559                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22560                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22561
22562                let display_hunk = if hunk_display_start.column() != 0 {
22563                    DisplayDiffHunk::Folded {
22564                        display_row: hunk_display_start.row(),
22565                    }
22566                } else {
22567                    let mut end_row = hunk_display_end.row();
22568                    if hunk_display_end.column() > 0 {
22569                        end_row.0 += 1;
22570                    }
22571                    let is_created_file = hunk.is_created_file();
22572                    DisplayDiffHunk::Unfolded {
22573                        status: hunk.status(),
22574                        diff_base_byte_range: hunk.diff_base_byte_range,
22575                        display_row_range: hunk_display_start.row()..end_row,
22576                        multi_buffer_range: Anchor::range_in_buffer(
22577                            hunk.excerpt_id,
22578                            hunk.buffer_id,
22579                            hunk.buffer_range,
22580                        ),
22581                        is_created_file,
22582                    }
22583                };
22584
22585                Some(display_hunk)
22586            })
22587    }
22588
22589    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22590        self.display_snapshot.buffer_snapshot.language_at(position)
22591    }
22592
22593    pub fn is_focused(&self) -> bool {
22594        self.is_focused
22595    }
22596
22597    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22598        self.placeholder_text.as_ref()
22599    }
22600
22601    pub fn scroll_position(&self) -> gpui::Point<f32> {
22602        self.scroll_anchor.scroll_position(&self.display_snapshot)
22603    }
22604
22605    fn gutter_dimensions(
22606        &self,
22607        font_id: FontId,
22608        font_size: Pixels,
22609        max_line_number_width: Pixels,
22610        cx: &App,
22611    ) -> Option<GutterDimensions> {
22612        if !self.show_gutter {
22613            return None;
22614        }
22615
22616        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22617        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22618
22619        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22620            matches!(
22621                ProjectSettings::get_global(cx).git.git_gutter,
22622                Some(GitGutterSetting::TrackedFiles)
22623            )
22624        });
22625        let gutter_settings = EditorSettings::get_global(cx).gutter;
22626        let show_line_numbers = self
22627            .show_line_numbers
22628            .unwrap_or(gutter_settings.line_numbers);
22629        let line_gutter_width = if show_line_numbers {
22630            // Avoid flicker-like gutter resizes when the line number gains another digit by
22631            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22632            let min_width_for_number_on_gutter =
22633                ch_advance * gutter_settings.min_line_number_digits as f32;
22634            max_line_number_width.max(min_width_for_number_on_gutter)
22635        } else {
22636            0.0.into()
22637        };
22638
22639        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22640        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22641
22642        let git_blame_entries_width =
22643            self.git_blame_gutter_max_author_length
22644                .map(|max_author_length| {
22645                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22646                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22647
22648                    /// The number of characters to dedicate to gaps and margins.
22649                    const SPACING_WIDTH: usize = 4;
22650
22651                    let max_char_count = max_author_length.min(renderer.max_author_length())
22652                        + ::git::SHORT_SHA_LENGTH
22653                        + MAX_RELATIVE_TIMESTAMP.len()
22654                        + SPACING_WIDTH;
22655
22656                    ch_advance * max_char_count
22657                });
22658
22659        let is_singleton = self.buffer_snapshot.is_singleton();
22660
22661        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22662        left_padding += if !is_singleton {
22663            ch_width * 4.0
22664        } else if show_runnables || show_breakpoints {
22665            ch_width * 3.0
22666        } else if show_git_gutter && show_line_numbers {
22667            ch_width * 2.0
22668        } else if show_git_gutter || show_line_numbers {
22669            ch_width
22670        } else {
22671            px(0.)
22672        };
22673
22674        let shows_folds = is_singleton && gutter_settings.folds;
22675
22676        let right_padding = if shows_folds && show_line_numbers {
22677            ch_width * 4.0
22678        } else if shows_folds || (!is_singleton && show_line_numbers) {
22679            ch_width * 3.0
22680        } else if show_line_numbers {
22681            ch_width
22682        } else {
22683            px(0.)
22684        };
22685
22686        Some(GutterDimensions {
22687            left_padding,
22688            right_padding,
22689            width: line_gutter_width + left_padding + right_padding,
22690            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22691            git_blame_entries_width,
22692        })
22693    }
22694
22695    pub fn render_crease_toggle(
22696        &self,
22697        buffer_row: MultiBufferRow,
22698        row_contains_cursor: bool,
22699        editor: Entity<Editor>,
22700        window: &mut Window,
22701        cx: &mut App,
22702    ) -> Option<AnyElement> {
22703        let folded = self.is_line_folded(buffer_row);
22704        let mut is_foldable = false;
22705
22706        if let Some(crease) = self
22707            .crease_snapshot
22708            .query_row(buffer_row, &self.buffer_snapshot)
22709        {
22710            is_foldable = true;
22711            match crease {
22712                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22713                    if let Some(render_toggle) = render_toggle {
22714                        let toggle_callback =
22715                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22716                                if folded {
22717                                    editor.update(cx, |editor, cx| {
22718                                        editor.fold_at(buffer_row, window, cx)
22719                                    });
22720                                } else {
22721                                    editor.update(cx, |editor, cx| {
22722                                        editor.unfold_at(buffer_row, window, cx)
22723                                    });
22724                                }
22725                            });
22726                        return Some((render_toggle)(
22727                            buffer_row,
22728                            folded,
22729                            toggle_callback,
22730                            window,
22731                            cx,
22732                        ));
22733                    }
22734                }
22735            }
22736        }
22737
22738        is_foldable |= self.starts_indent(buffer_row);
22739
22740        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22741            Some(
22742                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22743                    .toggle_state(folded)
22744                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22745                        if folded {
22746                            this.unfold_at(buffer_row, window, cx);
22747                        } else {
22748                            this.fold_at(buffer_row, window, cx);
22749                        }
22750                    }))
22751                    .into_any_element(),
22752            )
22753        } else {
22754            None
22755        }
22756    }
22757
22758    pub fn render_crease_trailer(
22759        &self,
22760        buffer_row: MultiBufferRow,
22761        window: &mut Window,
22762        cx: &mut App,
22763    ) -> Option<AnyElement> {
22764        let folded = self.is_line_folded(buffer_row);
22765        if let Crease::Inline { render_trailer, .. } = self
22766            .crease_snapshot
22767            .query_row(buffer_row, &self.buffer_snapshot)?
22768        {
22769            let render_trailer = render_trailer.as_ref()?;
22770            Some(render_trailer(buffer_row, folded, window, cx))
22771        } else {
22772            None
22773        }
22774    }
22775}
22776
22777impl Deref for EditorSnapshot {
22778    type Target = DisplaySnapshot;
22779
22780    fn deref(&self) -> &Self::Target {
22781        &self.display_snapshot
22782    }
22783}
22784
22785#[derive(Clone, Debug, PartialEq, Eq)]
22786pub enum EditorEvent {
22787    InputIgnored {
22788        text: Arc<str>,
22789    },
22790    InputHandled {
22791        utf16_range_to_replace: Option<Range<isize>>,
22792        text: Arc<str>,
22793    },
22794    ExcerptsAdded {
22795        buffer: Entity<Buffer>,
22796        predecessor: ExcerptId,
22797        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22798    },
22799    ExcerptsRemoved {
22800        ids: Vec<ExcerptId>,
22801        removed_buffer_ids: Vec<BufferId>,
22802    },
22803    BufferFoldToggled {
22804        ids: Vec<ExcerptId>,
22805        folded: bool,
22806    },
22807    ExcerptsEdited {
22808        ids: Vec<ExcerptId>,
22809    },
22810    ExcerptsExpanded {
22811        ids: Vec<ExcerptId>,
22812    },
22813    BufferEdited,
22814    Edited {
22815        transaction_id: clock::Lamport,
22816    },
22817    Reparsed(BufferId),
22818    Focused,
22819    FocusedIn,
22820    Blurred,
22821    DirtyChanged,
22822    Saved,
22823    TitleChanged,
22824    DiffBaseChanged,
22825    SelectionsChanged {
22826        local: bool,
22827    },
22828    ScrollPositionChanged {
22829        local: bool,
22830        autoscroll: bool,
22831    },
22832    Closed,
22833    TransactionUndone {
22834        transaction_id: clock::Lamport,
22835    },
22836    TransactionBegun {
22837        transaction_id: clock::Lamport,
22838    },
22839    Reloaded,
22840    CursorShapeChanged,
22841    BreadcrumbsChanged,
22842    PushedToNavHistory {
22843        anchor: Anchor,
22844        is_deactivate: bool,
22845    },
22846}
22847
22848impl EventEmitter<EditorEvent> for Editor {}
22849
22850impl Focusable for Editor {
22851    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22852        self.focus_handle.clone()
22853    }
22854}
22855
22856impl Render for Editor {
22857    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22858        let settings = ThemeSettings::get_global(cx);
22859
22860        let mut text_style = match self.mode {
22861            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22862                color: cx.theme().colors().editor_foreground,
22863                font_family: settings.ui_font.family.clone(),
22864                font_features: settings.ui_font.features.clone(),
22865                font_fallbacks: settings.ui_font.fallbacks.clone(),
22866                font_size: rems(0.875).into(),
22867                font_weight: settings.ui_font.weight,
22868                line_height: relative(settings.buffer_line_height.value()),
22869                ..Default::default()
22870            },
22871            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22872                color: cx.theme().colors().editor_foreground,
22873                font_family: settings.buffer_font.family.clone(),
22874                font_features: settings.buffer_font.features.clone(),
22875                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22876                font_size: settings.buffer_font_size(cx).into(),
22877                font_weight: settings.buffer_font.weight,
22878                line_height: relative(settings.buffer_line_height.value()),
22879                ..Default::default()
22880            },
22881        };
22882        if let Some(text_style_refinement) = &self.text_style_refinement {
22883            text_style.refine(text_style_refinement)
22884        }
22885
22886        let background = match self.mode {
22887            EditorMode::SingleLine => cx.theme().system().transparent,
22888            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22889            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22890            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22891        };
22892
22893        EditorElement::new(
22894            &cx.entity(),
22895            EditorStyle {
22896                background,
22897                border: cx.theme().colors().border,
22898                local_player: cx.theme().players().local(),
22899                text: text_style,
22900                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22901                syntax: cx.theme().syntax().clone(),
22902                status: cx.theme().status().clone(),
22903                inlay_hints_style: make_inlay_hints_style(cx),
22904                edit_prediction_styles: make_suggestion_styles(cx),
22905                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22906                show_underlines: self.diagnostics_enabled(),
22907            },
22908        )
22909    }
22910}
22911
22912impl EntityInputHandler for Editor {
22913    fn text_for_range(
22914        &mut self,
22915        range_utf16: Range<usize>,
22916        adjusted_range: &mut Option<Range<usize>>,
22917        _: &mut Window,
22918        cx: &mut Context<Self>,
22919    ) -> Option<String> {
22920        let snapshot = self.buffer.read(cx).read(cx);
22921        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22922        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22923        if (start.0..end.0) != range_utf16 {
22924            adjusted_range.replace(start.0..end.0);
22925        }
22926        Some(snapshot.text_for_range(start..end).collect())
22927    }
22928
22929    fn selected_text_range(
22930        &mut self,
22931        ignore_disabled_input: bool,
22932        _: &mut Window,
22933        cx: &mut Context<Self>,
22934    ) -> Option<UTF16Selection> {
22935        // Prevent the IME menu from appearing when holding down an alphabetic key
22936        // while input is disabled.
22937        if !ignore_disabled_input && !self.input_enabled {
22938            return None;
22939        }
22940
22941        let selection = self.selections.newest::<OffsetUtf16>(cx);
22942        let range = selection.range();
22943
22944        Some(UTF16Selection {
22945            range: range.start.0..range.end.0,
22946            reversed: selection.reversed,
22947        })
22948    }
22949
22950    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22951        let snapshot = self.buffer.read(cx).read(cx);
22952        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22953        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22954    }
22955
22956    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22957        self.clear_highlights::<InputComposition>(cx);
22958        self.ime_transaction.take();
22959    }
22960
22961    fn replace_text_in_range(
22962        &mut self,
22963        range_utf16: Option<Range<usize>>,
22964        text: &str,
22965        window: &mut Window,
22966        cx: &mut Context<Self>,
22967    ) {
22968        if !self.input_enabled {
22969            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22970            return;
22971        }
22972
22973        self.transact(window, cx, |this, window, cx| {
22974            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22975                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22976                Some(this.selection_replacement_ranges(range_utf16, cx))
22977            } else {
22978                this.marked_text_ranges(cx)
22979            };
22980
22981            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22982                let newest_selection_id = this.selections.newest_anchor().id;
22983                this.selections
22984                    .all::<OffsetUtf16>(cx)
22985                    .iter()
22986                    .zip(ranges_to_replace.iter())
22987                    .find_map(|(selection, range)| {
22988                        if selection.id == newest_selection_id {
22989                            Some(
22990                                (range.start.0 as isize - selection.head().0 as isize)
22991                                    ..(range.end.0 as isize - selection.head().0 as isize),
22992                            )
22993                        } else {
22994                            None
22995                        }
22996                    })
22997            });
22998
22999            cx.emit(EditorEvent::InputHandled {
23000                utf16_range_to_replace: range_to_replace,
23001                text: text.into(),
23002            });
23003
23004            if let Some(new_selected_ranges) = new_selected_ranges {
23005                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23006                    selections.select_ranges(new_selected_ranges)
23007                });
23008                this.backspace(&Default::default(), window, cx);
23009            }
23010
23011            this.handle_input(text, window, cx);
23012        });
23013
23014        if let Some(transaction) = self.ime_transaction {
23015            self.buffer.update(cx, |buffer, cx| {
23016                buffer.group_until_transaction(transaction, cx);
23017            });
23018        }
23019
23020        self.unmark_text(window, cx);
23021    }
23022
23023    fn replace_and_mark_text_in_range(
23024        &mut self,
23025        range_utf16: Option<Range<usize>>,
23026        text: &str,
23027        new_selected_range_utf16: Option<Range<usize>>,
23028        window: &mut Window,
23029        cx: &mut Context<Self>,
23030    ) {
23031        if !self.input_enabled {
23032            return;
23033        }
23034
23035        let transaction = self.transact(window, cx, |this, window, cx| {
23036            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23037                let snapshot = this.buffer.read(cx).read(cx);
23038                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23039                    for marked_range in &mut marked_ranges {
23040                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23041                        marked_range.start.0 += relative_range_utf16.start;
23042                        marked_range.start =
23043                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23044                        marked_range.end =
23045                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23046                    }
23047                }
23048                Some(marked_ranges)
23049            } else if let Some(range_utf16) = range_utf16 {
23050                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23051                Some(this.selection_replacement_ranges(range_utf16, cx))
23052            } else {
23053                None
23054            };
23055
23056            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23057                let newest_selection_id = this.selections.newest_anchor().id;
23058                this.selections
23059                    .all::<OffsetUtf16>(cx)
23060                    .iter()
23061                    .zip(ranges_to_replace.iter())
23062                    .find_map(|(selection, range)| {
23063                        if selection.id == newest_selection_id {
23064                            Some(
23065                                (range.start.0 as isize - selection.head().0 as isize)
23066                                    ..(range.end.0 as isize - selection.head().0 as isize),
23067                            )
23068                        } else {
23069                            None
23070                        }
23071                    })
23072            });
23073
23074            cx.emit(EditorEvent::InputHandled {
23075                utf16_range_to_replace: range_to_replace,
23076                text: text.into(),
23077            });
23078
23079            if let Some(ranges) = ranges_to_replace {
23080                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23081                    s.select_ranges(ranges)
23082                });
23083            }
23084
23085            let marked_ranges = {
23086                let snapshot = this.buffer.read(cx).read(cx);
23087                this.selections
23088                    .disjoint_anchors()
23089                    .iter()
23090                    .map(|selection| {
23091                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23092                    })
23093                    .collect::<Vec<_>>()
23094            };
23095
23096            if text.is_empty() {
23097                this.unmark_text(window, cx);
23098            } else {
23099                this.highlight_text::<InputComposition>(
23100                    marked_ranges.clone(),
23101                    HighlightStyle {
23102                        underline: Some(UnderlineStyle {
23103                            thickness: px(1.),
23104                            color: None,
23105                            wavy: false,
23106                        }),
23107                        ..Default::default()
23108                    },
23109                    cx,
23110                );
23111            }
23112
23113            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23114            let use_autoclose = this.use_autoclose;
23115            let use_auto_surround = this.use_auto_surround;
23116            this.set_use_autoclose(false);
23117            this.set_use_auto_surround(false);
23118            this.handle_input(text, window, cx);
23119            this.set_use_autoclose(use_autoclose);
23120            this.set_use_auto_surround(use_auto_surround);
23121
23122            if let Some(new_selected_range) = new_selected_range_utf16 {
23123                let snapshot = this.buffer.read(cx).read(cx);
23124                let new_selected_ranges = marked_ranges
23125                    .into_iter()
23126                    .map(|marked_range| {
23127                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23128                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23129                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23130                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23131                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23132                    })
23133                    .collect::<Vec<_>>();
23134
23135                drop(snapshot);
23136                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23137                    selections.select_ranges(new_selected_ranges)
23138                });
23139            }
23140        });
23141
23142        self.ime_transaction = self.ime_transaction.or(transaction);
23143        if let Some(transaction) = self.ime_transaction {
23144            self.buffer.update(cx, |buffer, cx| {
23145                buffer.group_until_transaction(transaction, cx);
23146            });
23147        }
23148
23149        if self.text_highlights::<InputComposition>(cx).is_none() {
23150            self.ime_transaction.take();
23151        }
23152    }
23153
23154    fn bounds_for_range(
23155        &mut self,
23156        range_utf16: Range<usize>,
23157        element_bounds: gpui::Bounds<Pixels>,
23158        window: &mut Window,
23159        cx: &mut Context<Self>,
23160    ) -> Option<gpui::Bounds<Pixels>> {
23161        let text_layout_details = self.text_layout_details(window);
23162        let CharacterDimensions {
23163            em_width,
23164            em_advance,
23165            line_height,
23166        } = self.character_dimensions(window);
23167
23168        let snapshot = self.snapshot(window, cx);
23169        let scroll_position = snapshot.scroll_position();
23170        let scroll_left = scroll_position.x * em_advance;
23171
23172        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23173        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23174            + self.gutter_dimensions.full_width();
23175        let y = line_height * (start.row().as_f32() - scroll_position.y);
23176
23177        Some(Bounds {
23178            origin: element_bounds.origin + point(x, y),
23179            size: size(em_width, line_height),
23180        })
23181    }
23182
23183    fn character_index_for_point(
23184        &mut self,
23185        point: gpui::Point<Pixels>,
23186        _window: &mut Window,
23187        _cx: &mut Context<Self>,
23188    ) -> Option<usize> {
23189        let position_map = self.last_position_map.as_ref()?;
23190        if !position_map.text_hitbox.contains(&point) {
23191            return None;
23192        }
23193        let display_point = position_map.point_for_position(point).previous_valid;
23194        let anchor = position_map
23195            .snapshot
23196            .display_point_to_anchor(display_point, Bias::Left);
23197        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23198        Some(utf16_offset.0)
23199    }
23200}
23201
23202trait SelectionExt {
23203    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23204    fn spanned_rows(
23205        &self,
23206        include_end_if_at_line_start: bool,
23207        map: &DisplaySnapshot,
23208    ) -> Range<MultiBufferRow>;
23209}
23210
23211impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23212    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23213        let start = self
23214            .start
23215            .to_point(&map.buffer_snapshot)
23216            .to_display_point(map);
23217        let end = self
23218            .end
23219            .to_point(&map.buffer_snapshot)
23220            .to_display_point(map);
23221        if self.reversed {
23222            end..start
23223        } else {
23224            start..end
23225        }
23226    }
23227
23228    fn spanned_rows(
23229        &self,
23230        include_end_if_at_line_start: bool,
23231        map: &DisplaySnapshot,
23232    ) -> Range<MultiBufferRow> {
23233        let start = self.start.to_point(&map.buffer_snapshot);
23234        let mut end = self.end.to_point(&map.buffer_snapshot);
23235        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23236            end.row -= 1;
23237        }
23238
23239        let buffer_start = map.prev_line_boundary(start).0;
23240        let buffer_end = map.next_line_boundary(end).0;
23241        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23242    }
23243}
23244
23245impl<T: InvalidationRegion> InvalidationStack<T> {
23246    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23247    where
23248        S: Clone + ToOffset,
23249    {
23250        while let Some(region) = self.last() {
23251            let all_selections_inside_invalidation_ranges =
23252                if selections.len() == region.ranges().len() {
23253                    selections
23254                        .iter()
23255                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23256                        .all(|(selection, invalidation_range)| {
23257                            let head = selection.head().to_offset(buffer);
23258                            invalidation_range.start <= head && invalidation_range.end >= head
23259                        })
23260                } else {
23261                    false
23262                };
23263
23264            if all_selections_inside_invalidation_ranges {
23265                break;
23266            } else {
23267                self.pop();
23268            }
23269        }
23270    }
23271}
23272
23273impl<T> Default for InvalidationStack<T> {
23274    fn default() -> Self {
23275        Self(Default::default())
23276    }
23277}
23278
23279impl<T> Deref for InvalidationStack<T> {
23280    type Target = Vec<T>;
23281
23282    fn deref(&self) -> &Self::Target {
23283        &self.0
23284    }
23285}
23286
23287impl<T> DerefMut for InvalidationStack<T> {
23288    fn deref_mut(&mut self) -> &mut Self::Target {
23289        &mut self.0
23290    }
23291}
23292
23293impl InvalidationRegion for SnippetState {
23294    fn ranges(&self) -> &[Range<Anchor>] {
23295        &self.ranges[self.active_index]
23296    }
23297}
23298
23299fn edit_prediction_edit_text(
23300    current_snapshot: &BufferSnapshot,
23301    edits: &[(Range<Anchor>, String)],
23302    edit_preview: &EditPreview,
23303    include_deletions: bool,
23304    cx: &App,
23305) -> HighlightedText {
23306    let edits = edits
23307        .iter()
23308        .map(|(anchor, text)| {
23309            (
23310                anchor.start.text_anchor..anchor.end.text_anchor,
23311                text.clone(),
23312            )
23313        })
23314        .collect::<Vec<_>>();
23315
23316    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23317}
23318
23319fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23320    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23321    // Just show the raw edit text with basic styling
23322    let mut text = String::new();
23323    let mut highlights = Vec::new();
23324
23325    let insertion_highlight_style = HighlightStyle {
23326        color: Some(cx.theme().colors().text),
23327        ..Default::default()
23328    };
23329
23330    for (_, edit_text) in edits {
23331        let start_offset = text.len();
23332        text.push_str(edit_text);
23333        let end_offset = text.len();
23334
23335        if start_offset < end_offset {
23336            highlights.push((start_offset..end_offset, insertion_highlight_style));
23337        }
23338    }
23339
23340    HighlightedText {
23341        text: text.into(),
23342        highlights,
23343    }
23344}
23345
23346pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23347    match severity {
23348        lsp::DiagnosticSeverity::ERROR => colors.error,
23349        lsp::DiagnosticSeverity::WARNING => colors.warning,
23350        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23351        lsp::DiagnosticSeverity::HINT => colors.info,
23352        _ => colors.ignored,
23353    }
23354}
23355
23356pub fn styled_runs_for_code_label<'a>(
23357    label: &'a CodeLabel,
23358    syntax_theme: &'a theme::SyntaxTheme,
23359) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23360    let fade_out = HighlightStyle {
23361        fade_out: Some(0.35),
23362        ..Default::default()
23363    };
23364
23365    let mut prev_end = label.filter_range.end;
23366    label
23367        .runs
23368        .iter()
23369        .enumerate()
23370        .flat_map(move |(ix, (range, highlight_id))| {
23371            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23372                style
23373            } else {
23374                return Default::default();
23375            };
23376            let mut muted_style = style;
23377            muted_style.highlight(fade_out);
23378
23379            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23380            if range.start >= label.filter_range.end {
23381                if range.start > prev_end {
23382                    runs.push((prev_end..range.start, fade_out));
23383                }
23384                runs.push((range.clone(), muted_style));
23385            } else if range.end <= label.filter_range.end {
23386                runs.push((range.clone(), style));
23387            } else {
23388                runs.push((range.start..label.filter_range.end, style));
23389                runs.push((label.filter_range.end..range.end, muted_style));
23390            }
23391            prev_end = cmp::max(prev_end, range.end);
23392
23393            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23394                runs.push((prev_end..label.text.len(), fade_out));
23395            }
23396
23397            runs
23398        })
23399}
23400
23401pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23402    let mut prev_index = 0;
23403    let mut prev_codepoint: Option<char> = None;
23404    text.char_indices()
23405        .chain([(text.len(), '\0')])
23406        .filter_map(move |(index, codepoint)| {
23407            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23408            let is_boundary = index == text.len()
23409                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23410                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23411            if is_boundary {
23412                let chunk = &text[prev_index..index];
23413                prev_index = index;
23414                Some(chunk)
23415            } else {
23416                None
23417            }
23418        })
23419}
23420
23421pub trait RangeToAnchorExt: Sized {
23422    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23423
23424    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23425        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23426        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23427    }
23428}
23429
23430impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23431    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23432        let start_offset = self.start.to_offset(snapshot);
23433        let end_offset = self.end.to_offset(snapshot);
23434        if start_offset == end_offset {
23435            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23436        } else {
23437            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23438        }
23439    }
23440}
23441
23442pub trait RowExt {
23443    fn as_f32(&self) -> f32;
23444
23445    fn next_row(&self) -> Self;
23446
23447    fn previous_row(&self) -> Self;
23448
23449    fn minus(&self, other: Self) -> u32;
23450}
23451
23452impl RowExt for DisplayRow {
23453    fn as_f32(&self) -> f32 {
23454        self.0 as f32
23455    }
23456
23457    fn next_row(&self) -> Self {
23458        Self(self.0 + 1)
23459    }
23460
23461    fn previous_row(&self) -> Self {
23462        Self(self.0.saturating_sub(1))
23463    }
23464
23465    fn minus(&self, other: Self) -> u32 {
23466        self.0 - other.0
23467    }
23468}
23469
23470impl RowExt for MultiBufferRow {
23471    fn as_f32(&self) -> f32 {
23472        self.0 as f32
23473    }
23474
23475    fn next_row(&self) -> Self {
23476        Self(self.0 + 1)
23477    }
23478
23479    fn previous_row(&self) -> Self {
23480        Self(self.0.saturating_sub(1))
23481    }
23482
23483    fn minus(&self, other: Self) -> u32 {
23484        self.0 - other.0
23485    }
23486}
23487
23488trait RowRangeExt {
23489    type Row;
23490
23491    fn len(&self) -> usize;
23492
23493    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23494}
23495
23496impl RowRangeExt for Range<MultiBufferRow> {
23497    type Row = MultiBufferRow;
23498
23499    fn len(&self) -> usize {
23500        (self.end.0 - self.start.0) as usize
23501    }
23502
23503    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23504        (self.start.0..self.end.0).map(MultiBufferRow)
23505    }
23506}
23507
23508impl RowRangeExt for Range<DisplayRow> {
23509    type Row = DisplayRow;
23510
23511    fn len(&self) -> usize {
23512        (self.end.0 - self.start.0) as usize
23513    }
23514
23515    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23516        (self.start.0..self.end.0).map(DisplayRow)
23517    }
23518}
23519
23520/// If select range has more than one line, we
23521/// just point the cursor to range.start.
23522fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23523    if range.start.row == range.end.row {
23524        range
23525    } else {
23526        range.start..range.start
23527    }
23528}
23529pub struct KillRing(ClipboardItem);
23530impl Global for KillRing {}
23531
23532const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23533
23534enum BreakpointPromptEditAction {
23535    Log,
23536    Condition,
23537    HitCondition,
23538}
23539
23540struct BreakpointPromptEditor {
23541    pub(crate) prompt: Entity<Editor>,
23542    editor: WeakEntity<Editor>,
23543    breakpoint_anchor: Anchor,
23544    breakpoint: Breakpoint,
23545    edit_action: BreakpointPromptEditAction,
23546    block_ids: HashSet<CustomBlockId>,
23547    editor_margins: Arc<Mutex<EditorMargins>>,
23548    _subscriptions: Vec<Subscription>,
23549}
23550
23551impl BreakpointPromptEditor {
23552    const MAX_LINES: u8 = 4;
23553
23554    fn new(
23555        editor: WeakEntity<Editor>,
23556        breakpoint_anchor: Anchor,
23557        breakpoint: Breakpoint,
23558        edit_action: BreakpointPromptEditAction,
23559        window: &mut Window,
23560        cx: &mut Context<Self>,
23561    ) -> Self {
23562        let base_text = match edit_action {
23563            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23564            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23565            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23566        }
23567        .map(|msg| msg.to_string())
23568        .unwrap_or_default();
23569
23570        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23571        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23572
23573        let prompt = cx.new(|cx| {
23574            let mut prompt = Editor::new(
23575                EditorMode::AutoHeight {
23576                    min_lines: 1,
23577                    max_lines: Some(Self::MAX_LINES as usize),
23578                },
23579                buffer,
23580                None,
23581                window,
23582                cx,
23583            );
23584            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23585            prompt.set_show_cursor_when_unfocused(false, cx);
23586            prompt.set_placeholder_text(
23587                match edit_action {
23588                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23589                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23590                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23591                },
23592                cx,
23593            );
23594
23595            prompt
23596        });
23597
23598        Self {
23599            prompt,
23600            editor,
23601            breakpoint_anchor,
23602            breakpoint,
23603            edit_action,
23604            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23605            block_ids: Default::default(),
23606            _subscriptions: vec![],
23607        }
23608    }
23609
23610    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23611        self.block_ids.extend(block_ids)
23612    }
23613
23614    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23615        if let Some(editor) = self.editor.upgrade() {
23616            let message = self
23617                .prompt
23618                .read(cx)
23619                .buffer
23620                .read(cx)
23621                .as_singleton()
23622                .expect("A multi buffer in breakpoint prompt isn't possible")
23623                .read(cx)
23624                .as_rope()
23625                .to_string();
23626
23627            editor.update(cx, |editor, cx| {
23628                editor.edit_breakpoint_at_anchor(
23629                    self.breakpoint_anchor,
23630                    self.breakpoint.clone(),
23631                    match self.edit_action {
23632                        BreakpointPromptEditAction::Log => {
23633                            BreakpointEditAction::EditLogMessage(message.into())
23634                        }
23635                        BreakpointPromptEditAction::Condition => {
23636                            BreakpointEditAction::EditCondition(message.into())
23637                        }
23638                        BreakpointPromptEditAction::HitCondition => {
23639                            BreakpointEditAction::EditHitCondition(message.into())
23640                        }
23641                    },
23642                    cx,
23643                );
23644
23645                editor.remove_blocks(self.block_ids.clone(), None, cx);
23646                cx.focus_self(window);
23647            });
23648        }
23649    }
23650
23651    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23652        self.editor
23653            .update(cx, |editor, cx| {
23654                editor.remove_blocks(self.block_ids.clone(), None, cx);
23655                window.focus(&editor.focus_handle);
23656            })
23657            .log_err();
23658    }
23659
23660    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23661        let settings = ThemeSettings::get_global(cx);
23662        let text_style = TextStyle {
23663            color: if self.prompt.read(cx).read_only(cx) {
23664                cx.theme().colors().text_disabled
23665            } else {
23666                cx.theme().colors().text
23667            },
23668            font_family: settings.buffer_font.family.clone(),
23669            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23670            font_size: settings.buffer_font_size(cx).into(),
23671            font_weight: settings.buffer_font.weight,
23672            line_height: relative(settings.buffer_line_height.value()),
23673            ..Default::default()
23674        };
23675        EditorElement::new(
23676            &self.prompt,
23677            EditorStyle {
23678                background: cx.theme().colors().editor_background,
23679                local_player: cx.theme().players().local(),
23680                text: text_style,
23681                ..Default::default()
23682            },
23683        )
23684    }
23685}
23686
23687impl Render for BreakpointPromptEditor {
23688    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23689        let editor_margins = *self.editor_margins.lock();
23690        let gutter_dimensions = editor_margins.gutter;
23691        h_flex()
23692            .key_context("Editor")
23693            .bg(cx.theme().colors().editor_background)
23694            .border_y_1()
23695            .border_color(cx.theme().status().info_border)
23696            .size_full()
23697            .py(window.line_height() / 2.5)
23698            .on_action(cx.listener(Self::confirm))
23699            .on_action(cx.listener(Self::cancel))
23700            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23701            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23702    }
23703}
23704
23705impl Focusable for BreakpointPromptEditor {
23706    fn focus_handle(&self, cx: &App) -> FocusHandle {
23707        self.prompt.focus_handle(cx)
23708    }
23709}
23710
23711fn all_edits_insertions_or_deletions(
23712    edits: &Vec<(Range<Anchor>, String)>,
23713    snapshot: &MultiBufferSnapshot,
23714) -> bool {
23715    let mut all_insertions = true;
23716    let mut all_deletions = true;
23717
23718    for (range, new_text) in edits.iter() {
23719        let range_is_empty = range.to_offset(snapshot).is_empty();
23720        let text_is_empty = new_text.is_empty();
23721
23722        if range_is_empty != text_is_empty {
23723            if range_is_empty {
23724                all_deletions = false;
23725            } else {
23726                all_insertions = false;
23727            }
23728        } else {
23729            return false;
23730        }
23731
23732        if !all_insertions && !all_deletions {
23733            return false;
23734        }
23735    }
23736    all_insertions || all_deletions
23737}
23738
23739struct MissingEditPredictionKeybindingTooltip;
23740
23741impl Render for MissingEditPredictionKeybindingTooltip {
23742    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23743        ui::tooltip_container(window, cx, |container, _, cx| {
23744            container
23745                .flex_shrink_0()
23746                .max_w_80()
23747                .min_h(rems_from_px(124.))
23748                .justify_between()
23749                .child(
23750                    v_flex()
23751                        .flex_1()
23752                        .text_ui_sm(cx)
23753                        .child(Label::new("Conflict with Accept Keybinding"))
23754                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23755                )
23756                .child(
23757                    h_flex()
23758                        .pb_1()
23759                        .gap_1()
23760                        .items_end()
23761                        .w_full()
23762                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23763                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23764                        }))
23765                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23766                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23767                        })),
23768                )
23769        })
23770    }
23771}
23772
23773#[derive(Debug, Clone, Copy, PartialEq)]
23774pub struct LineHighlight {
23775    pub background: Background,
23776    pub border: Option<gpui::Hsla>,
23777    pub include_gutter: bool,
23778    pub type_id: Option<TypeId>,
23779}
23780
23781struct LineManipulationResult {
23782    pub new_text: String,
23783    pub line_count_before: usize,
23784    pub line_count_after: usize,
23785}
23786
23787fn render_diff_hunk_controls(
23788    row: u32,
23789    status: &DiffHunkStatus,
23790    hunk_range: Range<Anchor>,
23791    is_created_file: bool,
23792    line_height: Pixels,
23793    editor: &Entity<Editor>,
23794    _window: &mut Window,
23795    cx: &mut App,
23796) -> AnyElement {
23797    h_flex()
23798        .h(line_height)
23799        .mr_1()
23800        .gap_1()
23801        .px_0p5()
23802        .pb_1()
23803        .border_x_1()
23804        .border_b_1()
23805        .border_color(cx.theme().colors().border_variant)
23806        .rounded_b_lg()
23807        .bg(cx.theme().colors().editor_background)
23808        .gap_1()
23809        .block_mouse_except_scroll()
23810        .shadow_md()
23811        .child(if status.has_secondary_hunk() {
23812            Button::new(("stage", row as u64), "Stage")
23813                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23814                .tooltip({
23815                    let focus_handle = editor.focus_handle(cx);
23816                    move |window, cx| {
23817                        Tooltip::for_action_in(
23818                            "Stage Hunk",
23819                            &::git::ToggleStaged,
23820                            &focus_handle,
23821                            window,
23822                            cx,
23823                        )
23824                    }
23825                })
23826                .on_click({
23827                    let editor = editor.clone();
23828                    move |_event, _window, cx| {
23829                        editor.update(cx, |editor, cx| {
23830                            editor.stage_or_unstage_diff_hunks(
23831                                true,
23832                                vec![hunk_range.start..hunk_range.start],
23833                                cx,
23834                            );
23835                        });
23836                    }
23837                })
23838        } else {
23839            Button::new(("unstage", row as u64), "Unstage")
23840                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23841                .tooltip({
23842                    let focus_handle = editor.focus_handle(cx);
23843                    move |window, cx| {
23844                        Tooltip::for_action_in(
23845                            "Unstage Hunk",
23846                            &::git::ToggleStaged,
23847                            &focus_handle,
23848                            window,
23849                            cx,
23850                        )
23851                    }
23852                })
23853                .on_click({
23854                    let editor = editor.clone();
23855                    move |_event, _window, cx| {
23856                        editor.update(cx, |editor, cx| {
23857                            editor.stage_or_unstage_diff_hunks(
23858                                false,
23859                                vec![hunk_range.start..hunk_range.start],
23860                                cx,
23861                            );
23862                        });
23863                    }
23864                })
23865        })
23866        .child(
23867            Button::new(("restore", row as u64), "Restore")
23868                .tooltip({
23869                    let focus_handle = editor.focus_handle(cx);
23870                    move |window, cx| {
23871                        Tooltip::for_action_in(
23872                            "Restore Hunk",
23873                            &::git::Restore,
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                            let snapshot = editor.snapshot(window, cx);
23885                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23886                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23887                        });
23888                    }
23889                })
23890                .disabled(is_created_file),
23891        )
23892        .when(
23893            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23894            |el| {
23895                el.child(
23896                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23897                        .shape(IconButtonShape::Square)
23898                        .icon_size(IconSize::Small)
23899                        // .disabled(!has_multiple_hunks)
23900                        .tooltip({
23901                            let focus_handle = editor.focus_handle(cx);
23902                            move |window, cx| {
23903                                Tooltip::for_action_in(
23904                                    "Next Hunk",
23905                                    &GoToHunk,
23906                                    &focus_handle,
23907                                    window,
23908                                    cx,
23909                                )
23910                            }
23911                        })
23912                        .on_click({
23913                            let editor = editor.clone();
23914                            move |_event, window, cx| {
23915                                editor.update(cx, |editor, cx| {
23916                                    let snapshot = editor.snapshot(window, cx);
23917                                    let position =
23918                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23919                                    editor.go_to_hunk_before_or_after_position(
23920                                        &snapshot,
23921                                        position,
23922                                        Direction::Next,
23923                                        window,
23924                                        cx,
23925                                    );
23926                                    editor.expand_selected_diff_hunks(cx);
23927                                });
23928                            }
23929                        }),
23930                )
23931                .child(
23932                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23933                        .shape(IconButtonShape::Square)
23934                        .icon_size(IconSize::Small)
23935                        // .disabled(!has_multiple_hunks)
23936                        .tooltip({
23937                            let focus_handle = editor.focus_handle(cx);
23938                            move |window, cx| {
23939                                Tooltip::for_action_in(
23940                                    "Previous Hunk",
23941                                    &GoToPreviousHunk,
23942                                    &focus_handle,
23943                                    window,
23944                                    cx,
23945                                )
23946                            }
23947                        })
23948                        .on_click({
23949                            let editor = editor.clone();
23950                            move |_event, window, cx| {
23951                                editor.update(cx, |editor, cx| {
23952                                    let snapshot = editor.snapshot(window, cx);
23953                                    let point =
23954                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23955                                    editor.go_to_hunk_before_or_after_position(
23956                                        &snapshot,
23957                                        point,
23958                                        Direction::Prev,
23959                                        window,
23960                                        cx,
23961                                    );
23962                                    editor.expand_selected_diff_hunks(cx);
23963                                });
23964                            }
23965                        }),
23966                )
23967            },
23968        )
23969        .into_any_element()
23970}