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_id = cursor_position.buffer_id;
 6701                    let buffer = this.buffer.read(cx);
 6702                    if buffer
 6703                        .text_anchor_for_position(cursor_position, cx)
 6704                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6705                    {
 6706                        return;
 6707                    }
 6708
 6709                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6710                    let mut write_ranges = Vec::new();
 6711                    let mut read_ranges = Vec::new();
 6712                    for highlight in highlights {
 6713                        for (excerpt_id, excerpt_range) in
 6714                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6715                        {
 6716                            let start = highlight
 6717                                .range
 6718                                .start
 6719                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6720                            let end = highlight
 6721                                .range
 6722                                .end
 6723                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6724                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6725                                continue;
 6726                            }
 6727
 6728                            let range = Anchor {
 6729                                buffer_id,
 6730                                excerpt_id,
 6731                                text_anchor: start,
 6732                                diff_base_anchor: None,
 6733                            }..Anchor {
 6734                                buffer_id,
 6735                                excerpt_id,
 6736                                text_anchor: end,
 6737                                diff_base_anchor: None,
 6738                            };
 6739                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6740                                write_ranges.push(range);
 6741                            } else {
 6742                                read_ranges.push(range);
 6743                            }
 6744                        }
 6745                    }
 6746
 6747                    this.highlight_background::<DocumentHighlightRead>(
 6748                        &read_ranges,
 6749                        |theme| theme.colors().editor_document_highlight_read_background,
 6750                        cx,
 6751                    );
 6752                    this.highlight_background::<DocumentHighlightWrite>(
 6753                        &write_ranges,
 6754                        |theme| theme.colors().editor_document_highlight_write_background,
 6755                        cx,
 6756                    );
 6757                    cx.notify();
 6758                })
 6759                .log_err();
 6760            }
 6761        }));
 6762        None
 6763    }
 6764
 6765    fn prepare_highlight_query_from_selection(
 6766        &mut self,
 6767        cx: &mut Context<Editor>,
 6768    ) -> Option<(String, Range<Anchor>)> {
 6769        if matches!(self.mode, EditorMode::SingleLine) {
 6770            return None;
 6771        }
 6772        if !EditorSettings::get_global(cx).selection_highlight {
 6773            return None;
 6774        }
 6775        if self.selections.count() != 1 || self.selections.line_mode {
 6776            return None;
 6777        }
 6778        let selection = self.selections.newest::<Point>(cx);
 6779        if selection.is_empty() || selection.start.row != selection.end.row {
 6780            return None;
 6781        }
 6782        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6783        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6784        let query = multi_buffer_snapshot
 6785            .text_for_range(selection_anchor_range.clone())
 6786            .collect::<String>();
 6787        if query.trim().is_empty() {
 6788            return None;
 6789        }
 6790        Some((query, selection_anchor_range))
 6791    }
 6792
 6793    fn update_selection_occurrence_highlights(
 6794        &mut self,
 6795        query_text: String,
 6796        query_range: Range<Anchor>,
 6797        multi_buffer_range_to_query: Range<Point>,
 6798        use_debounce: bool,
 6799        window: &mut Window,
 6800        cx: &mut Context<Editor>,
 6801    ) -> Task<()> {
 6802        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6803        cx.spawn_in(window, async move |editor, cx| {
 6804            if use_debounce {
 6805                cx.background_executor()
 6806                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6807                    .await;
 6808            }
 6809            let match_task = cx.background_spawn(async move {
 6810                let buffer_ranges = multi_buffer_snapshot
 6811                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6812                    .into_iter()
 6813                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6814                let mut match_ranges = Vec::new();
 6815                let Ok(regex) = project::search::SearchQuery::text(
 6816                    query_text.clone(),
 6817                    false,
 6818                    false,
 6819                    false,
 6820                    Default::default(),
 6821                    Default::default(),
 6822                    false,
 6823                    None,
 6824                ) else {
 6825                    return Vec::default();
 6826                };
 6827                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6828                    match_ranges.extend(
 6829                        regex
 6830                            .search(buffer_snapshot, Some(search_range.clone()))
 6831                            .await
 6832                            .into_iter()
 6833                            .filter_map(|match_range| {
 6834                                let match_start = buffer_snapshot
 6835                                    .anchor_after(search_range.start + match_range.start);
 6836                                let match_end = buffer_snapshot
 6837                                    .anchor_before(search_range.start + match_range.end);
 6838                                let match_anchor_range = Anchor::range_in_buffer(
 6839                                    excerpt_id,
 6840                                    buffer_snapshot.remote_id(),
 6841                                    match_start..match_end,
 6842                                );
 6843                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6844                            }),
 6845                    );
 6846                }
 6847                match_ranges
 6848            });
 6849            let match_ranges = match_task.await;
 6850            editor
 6851                .update_in(cx, |editor, _, cx| {
 6852                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6853                    if !match_ranges.is_empty() {
 6854                        editor.highlight_background::<SelectedTextHighlight>(
 6855                            &match_ranges,
 6856                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6857                            cx,
 6858                        )
 6859                    }
 6860                })
 6861                .log_err();
 6862        })
 6863    }
 6864
 6865    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6866        struct NewlineFold;
 6867        let type_id = std::any::TypeId::of::<NewlineFold>();
 6868        if !self.mode.is_single_line() {
 6869            return;
 6870        }
 6871        let snapshot = self.snapshot(window, cx);
 6872        if snapshot.buffer_snapshot.max_point().row == 0 {
 6873            return;
 6874        }
 6875        let task = cx.background_spawn(async move {
 6876            let new_newlines = snapshot
 6877                .buffer_chars_at(0)
 6878                .filter_map(|(c, i)| {
 6879                    if c == '\n' {
 6880                        Some(
 6881                            snapshot.buffer_snapshot.anchor_after(i)
 6882                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6883                        )
 6884                    } else {
 6885                        None
 6886                    }
 6887                })
 6888                .collect::<Vec<_>>();
 6889            let existing_newlines = snapshot
 6890                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6891                .filter_map(|fold| {
 6892                    if fold.placeholder.type_tag == Some(type_id) {
 6893                        Some(fold.range.start..fold.range.end)
 6894                    } else {
 6895                        None
 6896                    }
 6897                })
 6898                .collect::<Vec<_>>();
 6899
 6900            (new_newlines, existing_newlines)
 6901        });
 6902        self.folding_newlines = cx.spawn(async move |this, cx| {
 6903            let (new_newlines, existing_newlines) = task.await;
 6904            if new_newlines == existing_newlines {
 6905                return;
 6906            }
 6907            let placeholder = FoldPlaceholder {
 6908                render: Arc::new(move |_, _, cx| {
 6909                    div()
 6910                        .bg(cx.theme().status().hint_background)
 6911                        .border_b_1()
 6912                        .size_full()
 6913                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6914                        .border_color(cx.theme().status().hint)
 6915                        .child("\\n")
 6916                        .into_any()
 6917                }),
 6918                constrain_width: false,
 6919                merge_adjacent: false,
 6920                type_tag: Some(type_id),
 6921            };
 6922            let creases = new_newlines
 6923                .into_iter()
 6924                .map(|range| Crease::simple(range, placeholder.clone()))
 6925                .collect();
 6926            this.update(cx, |this, cx| {
 6927                this.display_map.update(cx, |display_map, cx| {
 6928                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6929                    display_map.fold(creases, cx);
 6930                });
 6931            })
 6932            .ok();
 6933        });
 6934    }
 6935
 6936    fn refresh_selected_text_highlights(
 6937        &mut self,
 6938        on_buffer_edit: bool,
 6939        window: &mut Window,
 6940        cx: &mut Context<Editor>,
 6941    ) {
 6942        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6943        else {
 6944            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6945            self.quick_selection_highlight_task.take();
 6946            self.debounced_selection_highlight_task.take();
 6947            return;
 6948        };
 6949        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6950        if on_buffer_edit
 6951            || self
 6952                .quick_selection_highlight_task
 6953                .as_ref()
 6954                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6955        {
 6956            let multi_buffer_visible_start = self
 6957                .scroll_manager
 6958                .anchor()
 6959                .anchor
 6960                .to_point(&multi_buffer_snapshot);
 6961            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6962                multi_buffer_visible_start
 6963                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6964                Bias::Left,
 6965            );
 6966            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6967            self.quick_selection_highlight_task = Some((
 6968                query_range.clone(),
 6969                self.update_selection_occurrence_highlights(
 6970                    query_text.clone(),
 6971                    query_range.clone(),
 6972                    multi_buffer_visible_range,
 6973                    false,
 6974                    window,
 6975                    cx,
 6976                ),
 6977            ));
 6978        }
 6979        if on_buffer_edit
 6980            || self
 6981                .debounced_selection_highlight_task
 6982                .as_ref()
 6983                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6984        {
 6985            let multi_buffer_start = multi_buffer_snapshot
 6986                .anchor_before(0)
 6987                .to_point(&multi_buffer_snapshot);
 6988            let multi_buffer_end = multi_buffer_snapshot
 6989                .anchor_after(multi_buffer_snapshot.len())
 6990                .to_point(&multi_buffer_snapshot);
 6991            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6992            self.debounced_selection_highlight_task = Some((
 6993                query_range.clone(),
 6994                self.update_selection_occurrence_highlights(
 6995                    query_text,
 6996                    query_range,
 6997                    multi_buffer_full_range,
 6998                    true,
 6999                    window,
 7000                    cx,
 7001                ),
 7002            ));
 7003        }
 7004    }
 7005
 7006    pub fn refresh_edit_prediction(
 7007        &mut self,
 7008        debounce: bool,
 7009        user_requested: bool,
 7010        window: &mut Window,
 7011        cx: &mut Context<Self>,
 7012    ) -> Option<()> {
 7013        if DisableAiSettings::get_global(cx).disable_ai {
 7014            return None;
 7015        }
 7016
 7017        let provider = self.edit_prediction_provider()?;
 7018        let cursor = self.selections.newest_anchor().head();
 7019        let (buffer, cursor_buffer_position) =
 7020            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7021
 7022        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7023            self.discard_edit_prediction(false, cx);
 7024            return None;
 7025        }
 7026
 7027        if !user_requested
 7028            && (!self.should_show_edit_predictions()
 7029                || !self.is_focused(window)
 7030                || buffer.read(cx).is_empty())
 7031        {
 7032            self.discard_edit_prediction(false, cx);
 7033            return None;
 7034        }
 7035
 7036        self.update_visible_edit_prediction(window, cx);
 7037        provider.refresh(
 7038            self.project.clone(),
 7039            buffer,
 7040            cursor_buffer_position,
 7041            debounce,
 7042            cx,
 7043        );
 7044        Some(())
 7045    }
 7046
 7047    fn show_edit_predictions_in_menu(&self) -> bool {
 7048        match self.edit_prediction_settings {
 7049            EditPredictionSettings::Disabled => false,
 7050            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7051        }
 7052    }
 7053
 7054    pub fn edit_predictions_enabled(&self) -> bool {
 7055        match self.edit_prediction_settings {
 7056            EditPredictionSettings::Disabled => false,
 7057            EditPredictionSettings::Enabled { .. } => true,
 7058        }
 7059    }
 7060
 7061    fn edit_prediction_requires_modifier(&self) -> bool {
 7062        match self.edit_prediction_settings {
 7063            EditPredictionSettings::Disabled => false,
 7064            EditPredictionSettings::Enabled {
 7065                preview_requires_modifier,
 7066                ..
 7067            } => preview_requires_modifier,
 7068        }
 7069    }
 7070
 7071    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7072        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7073            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7074            self.discard_edit_prediction(false, cx);
 7075        } else {
 7076            let selection = self.selections.newest_anchor();
 7077            let cursor = selection.head();
 7078
 7079            if let Some((buffer, cursor_buffer_position)) =
 7080                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7081            {
 7082                self.edit_prediction_settings =
 7083                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7084            }
 7085        }
 7086    }
 7087
 7088    fn edit_prediction_settings_at_position(
 7089        &self,
 7090        buffer: &Entity<Buffer>,
 7091        buffer_position: language::Anchor,
 7092        cx: &App,
 7093    ) -> EditPredictionSettings {
 7094        if !self.mode.is_full()
 7095            || !self.show_edit_predictions_override.unwrap_or(true)
 7096            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7097        {
 7098            return EditPredictionSettings::Disabled;
 7099        }
 7100
 7101        let buffer = buffer.read(cx);
 7102
 7103        let file = buffer.file();
 7104
 7105        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7106            return EditPredictionSettings::Disabled;
 7107        };
 7108
 7109        let by_provider = matches!(
 7110            self.menu_edit_predictions_policy,
 7111            MenuEditPredictionsPolicy::ByProvider
 7112        );
 7113
 7114        let show_in_menu = by_provider
 7115            && self
 7116                .edit_prediction_provider
 7117                .as_ref()
 7118                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7119
 7120        let preview_requires_modifier =
 7121            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7122
 7123        EditPredictionSettings::Enabled {
 7124            show_in_menu,
 7125            preview_requires_modifier,
 7126        }
 7127    }
 7128
 7129    fn should_show_edit_predictions(&self) -> bool {
 7130        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7131    }
 7132
 7133    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7134        matches!(
 7135            self.edit_prediction_preview,
 7136            EditPredictionPreview::Active { .. }
 7137        )
 7138    }
 7139
 7140    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7141        let cursor = self.selections.newest_anchor().head();
 7142        if let Some((buffer, cursor_position)) =
 7143            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7144        {
 7145            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7146        } else {
 7147            false
 7148        }
 7149    }
 7150
 7151    pub fn supports_minimap(&self, cx: &App) -> bool {
 7152        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7153    }
 7154
 7155    fn edit_predictions_enabled_in_buffer(
 7156        &self,
 7157        buffer: &Entity<Buffer>,
 7158        buffer_position: language::Anchor,
 7159        cx: &App,
 7160    ) -> bool {
 7161        maybe!({
 7162            if self.read_only(cx) {
 7163                return Some(false);
 7164            }
 7165            let provider = self.edit_prediction_provider()?;
 7166            if !provider.is_enabled(buffer, buffer_position, cx) {
 7167                return Some(false);
 7168            }
 7169            let buffer = buffer.read(cx);
 7170            let Some(file) = buffer.file() else {
 7171                return Some(true);
 7172            };
 7173            let settings = all_language_settings(Some(file), cx);
 7174            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7175        })
 7176        .unwrap_or(false)
 7177    }
 7178
 7179    fn cycle_edit_prediction(
 7180        &mut self,
 7181        direction: Direction,
 7182        window: &mut Window,
 7183        cx: &mut Context<Self>,
 7184    ) -> Option<()> {
 7185        let provider = self.edit_prediction_provider()?;
 7186        let cursor = self.selections.newest_anchor().head();
 7187        let (buffer, cursor_buffer_position) =
 7188            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7189        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7190            return None;
 7191        }
 7192
 7193        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7194        self.update_visible_edit_prediction(window, cx);
 7195
 7196        Some(())
 7197    }
 7198
 7199    pub fn show_edit_prediction(
 7200        &mut self,
 7201        _: &ShowEditPrediction,
 7202        window: &mut Window,
 7203        cx: &mut Context<Self>,
 7204    ) {
 7205        if !self.has_active_edit_prediction() {
 7206            self.refresh_edit_prediction(false, true, window, cx);
 7207            return;
 7208        }
 7209
 7210        self.update_visible_edit_prediction(window, cx);
 7211    }
 7212
 7213    pub fn display_cursor_names(
 7214        &mut self,
 7215        _: &DisplayCursorNames,
 7216        window: &mut Window,
 7217        cx: &mut Context<Self>,
 7218    ) {
 7219        self.show_cursor_names(window, cx);
 7220    }
 7221
 7222    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7223        self.show_cursor_names = true;
 7224        cx.notify();
 7225        cx.spawn_in(window, async move |this, cx| {
 7226            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7227            this.update(cx, |this, cx| {
 7228                this.show_cursor_names = false;
 7229                cx.notify()
 7230            })
 7231            .ok()
 7232        })
 7233        .detach();
 7234    }
 7235
 7236    pub fn next_edit_prediction(
 7237        &mut self,
 7238        _: &NextEditPrediction,
 7239        window: &mut Window,
 7240        cx: &mut Context<Self>,
 7241    ) {
 7242        if self.has_active_edit_prediction() {
 7243            self.cycle_edit_prediction(Direction::Next, window, cx);
 7244        } else {
 7245            let is_copilot_disabled = self
 7246                .refresh_edit_prediction(false, true, window, cx)
 7247                .is_none();
 7248            if is_copilot_disabled {
 7249                cx.propagate();
 7250            }
 7251        }
 7252    }
 7253
 7254    pub fn previous_edit_prediction(
 7255        &mut self,
 7256        _: &PreviousEditPrediction,
 7257        window: &mut Window,
 7258        cx: &mut Context<Self>,
 7259    ) {
 7260        if self.has_active_edit_prediction() {
 7261            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7262        } else {
 7263            let is_copilot_disabled = self
 7264                .refresh_edit_prediction(false, true, window, cx)
 7265                .is_none();
 7266            if is_copilot_disabled {
 7267                cx.propagate();
 7268            }
 7269        }
 7270    }
 7271
 7272    pub fn accept_edit_prediction(
 7273        &mut self,
 7274        _: &AcceptEditPrediction,
 7275        window: &mut Window,
 7276        cx: &mut Context<Self>,
 7277    ) {
 7278        if self.show_edit_predictions_in_menu() {
 7279            self.hide_context_menu(window, cx);
 7280        }
 7281
 7282        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7283            return;
 7284        };
 7285
 7286        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7287
 7288        match &active_edit_prediction.completion {
 7289            EditPrediction::Move { target, .. } => {
 7290                let target = *target;
 7291
 7292                if let Some(position_map) = &self.last_position_map {
 7293                    if position_map
 7294                        .visible_row_range
 7295                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7296                        || !self.edit_prediction_requires_modifier()
 7297                    {
 7298                        self.unfold_ranges(&[target..target], true, false, cx);
 7299                        // Note that this is also done in vim's handler of the Tab action.
 7300                        self.change_selections(
 7301                            SelectionEffects::scroll(Autoscroll::newest()),
 7302                            window,
 7303                            cx,
 7304                            |selections| {
 7305                                selections.select_anchor_ranges([target..target]);
 7306                            },
 7307                        );
 7308                        self.clear_row_highlights::<EditPredictionPreview>();
 7309
 7310                        self.edit_prediction_preview
 7311                            .set_previous_scroll_position(None);
 7312                    } else {
 7313                        self.edit_prediction_preview
 7314                            .set_previous_scroll_position(Some(
 7315                                position_map.snapshot.scroll_anchor,
 7316                            ));
 7317
 7318                        self.highlight_rows::<EditPredictionPreview>(
 7319                            target..target,
 7320                            cx.theme().colors().editor_highlighted_line_background,
 7321                            RowHighlightOptions {
 7322                                autoscroll: true,
 7323                                ..Default::default()
 7324                            },
 7325                            cx,
 7326                        );
 7327                        self.request_autoscroll(Autoscroll::fit(), cx);
 7328                    }
 7329                }
 7330            }
 7331            EditPrediction::Edit { edits, .. } => {
 7332                if let Some(provider) = self.edit_prediction_provider() {
 7333                    provider.accept(cx);
 7334                }
 7335
 7336                // Store the transaction ID and selections before applying the edit
 7337                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7338
 7339                let snapshot = self.buffer.read(cx).snapshot(cx);
 7340                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7341
 7342                self.buffer.update(cx, |buffer, cx| {
 7343                    buffer.edit(edits.iter().cloned(), None, cx)
 7344                });
 7345
 7346                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7347                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7348                });
 7349
 7350                let selections = self.selections.disjoint_anchors();
 7351                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7352                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7353                    if has_new_transaction {
 7354                        self.selection_history
 7355                            .insert_transaction(transaction_id_now, selections);
 7356                    }
 7357                }
 7358
 7359                self.update_visible_edit_prediction(window, cx);
 7360                if self.active_edit_prediction.is_none() {
 7361                    self.refresh_edit_prediction(true, true, window, cx);
 7362                }
 7363
 7364                cx.notify();
 7365            }
 7366        }
 7367
 7368        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7369    }
 7370
 7371    pub fn accept_partial_edit_prediction(
 7372        &mut self,
 7373        _: &AcceptPartialEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7378            return;
 7379        };
 7380        if self.selections.count() != 1 {
 7381            return;
 7382        }
 7383
 7384        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7385
 7386        match &active_edit_prediction.completion {
 7387            EditPrediction::Move { target, .. } => {
 7388                let target = *target;
 7389                self.change_selections(
 7390                    SelectionEffects::scroll(Autoscroll::newest()),
 7391                    window,
 7392                    cx,
 7393                    |selections| {
 7394                        selections.select_anchor_ranges([target..target]);
 7395                    },
 7396                );
 7397            }
 7398            EditPrediction::Edit { edits, .. } => {
 7399                // Find an insertion that starts at the cursor position.
 7400                let snapshot = self.buffer.read(cx).snapshot(cx);
 7401                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7402                let insertion = edits.iter().find_map(|(range, text)| {
 7403                    let range = range.to_offset(&snapshot);
 7404                    if range.is_empty() && range.start == cursor_offset {
 7405                        Some(text)
 7406                    } else {
 7407                        None
 7408                    }
 7409                });
 7410
 7411                if let Some(text) = insertion {
 7412                    let mut partial_completion = text
 7413                        .chars()
 7414                        .by_ref()
 7415                        .take_while(|c| c.is_alphabetic())
 7416                        .collect::<String>();
 7417                    if partial_completion.is_empty() {
 7418                        partial_completion = text
 7419                            .chars()
 7420                            .by_ref()
 7421                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7422                            .collect::<String>();
 7423                    }
 7424
 7425                    cx.emit(EditorEvent::InputHandled {
 7426                        utf16_range_to_replace: None,
 7427                        text: partial_completion.clone().into(),
 7428                    });
 7429
 7430                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7431
 7432                    self.refresh_edit_prediction(true, true, window, cx);
 7433                    cx.notify();
 7434                } else {
 7435                    self.accept_edit_prediction(&Default::default(), window, cx);
 7436                }
 7437            }
 7438        }
 7439    }
 7440
 7441    fn discard_edit_prediction(
 7442        &mut self,
 7443        should_report_edit_prediction_event: bool,
 7444        cx: &mut Context<Self>,
 7445    ) -> bool {
 7446        if should_report_edit_prediction_event {
 7447            let completion_id = self
 7448                .active_edit_prediction
 7449                .as_ref()
 7450                .and_then(|active_completion| active_completion.completion_id.clone());
 7451
 7452            self.report_edit_prediction_event(completion_id, false, cx);
 7453        }
 7454
 7455        if let Some(provider) = self.edit_prediction_provider() {
 7456            provider.discard(cx);
 7457        }
 7458
 7459        self.take_active_edit_prediction(cx)
 7460    }
 7461
 7462    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7463        let Some(provider) = self.edit_prediction_provider() else {
 7464            return;
 7465        };
 7466
 7467        let Some((_, buffer, _)) = self
 7468            .buffer
 7469            .read(cx)
 7470            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7471        else {
 7472            return;
 7473        };
 7474
 7475        let extension = buffer
 7476            .read(cx)
 7477            .file()
 7478            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7479
 7480        let event_type = match accepted {
 7481            true => "Edit Prediction Accepted",
 7482            false => "Edit Prediction Discarded",
 7483        };
 7484        telemetry::event!(
 7485            event_type,
 7486            provider = provider.name(),
 7487            prediction_id = id,
 7488            suggestion_accepted = accepted,
 7489            file_extension = extension,
 7490        );
 7491    }
 7492
 7493    pub fn has_active_edit_prediction(&self) -> bool {
 7494        self.active_edit_prediction.is_some()
 7495    }
 7496
 7497    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7498        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7499            return false;
 7500        };
 7501
 7502        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7503        self.clear_highlights::<EditPredictionHighlight>(cx);
 7504        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7505        true
 7506    }
 7507
 7508    /// Returns true when we're displaying the edit prediction popover below the cursor
 7509    /// like we are not previewing and the LSP autocomplete menu is visible
 7510    /// or we are in `when_holding_modifier` mode.
 7511    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7512        if self.edit_prediction_preview_is_active()
 7513            || !self.show_edit_predictions_in_menu()
 7514            || !self.edit_predictions_enabled()
 7515        {
 7516            return false;
 7517        }
 7518
 7519        if self.has_visible_completions_menu() {
 7520            return true;
 7521        }
 7522
 7523        has_completion && self.edit_prediction_requires_modifier()
 7524    }
 7525
 7526    fn handle_modifiers_changed(
 7527        &mut self,
 7528        modifiers: Modifiers,
 7529        position_map: &PositionMap,
 7530        window: &mut Window,
 7531        cx: &mut Context<Self>,
 7532    ) {
 7533        if self.show_edit_predictions_in_menu() {
 7534            self.update_edit_prediction_preview(&modifiers, window, cx);
 7535        }
 7536
 7537        self.update_selection_mode(&modifiers, position_map, window, cx);
 7538
 7539        let mouse_position = window.mouse_position();
 7540        if !position_map.text_hitbox.is_hovered(window) {
 7541            return;
 7542        }
 7543
 7544        self.update_hovered_link(
 7545            position_map.point_for_position(mouse_position),
 7546            &position_map.snapshot,
 7547            modifiers,
 7548            window,
 7549            cx,
 7550        )
 7551    }
 7552
 7553    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7554        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7555        if invert {
 7556            match multi_cursor_setting {
 7557                MultiCursorModifier::Alt => modifiers.alt,
 7558                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7559            }
 7560        } else {
 7561            match multi_cursor_setting {
 7562                MultiCursorModifier::Alt => modifiers.secondary(),
 7563                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7564            }
 7565        }
 7566    }
 7567
 7568    fn columnar_selection_mode(
 7569        modifiers: &Modifiers,
 7570        cx: &mut Context<Self>,
 7571    ) -> Option<ColumnarMode> {
 7572        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7573            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7574                Some(ColumnarMode::FromMouse)
 7575            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7576                Some(ColumnarMode::FromSelection)
 7577            } else {
 7578                None
 7579            }
 7580        } else {
 7581            None
 7582        }
 7583    }
 7584
 7585    fn update_selection_mode(
 7586        &mut self,
 7587        modifiers: &Modifiers,
 7588        position_map: &PositionMap,
 7589        window: &mut Window,
 7590        cx: &mut Context<Self>,
 7591    ) {
 7592        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7593            return;
 7594        };
 7595        if self.selections.pending.is_none() {
 7596            return;
 7597        }
 7598
 7599        let mouse_position = window.mouse_position();
 7600        let point_for_position = position_map.point_for_position(mouse_position);
 7601        let position = point_for_position.previous_valid;
 7602
 7603        self.select(
 7604            SelectPhase::BeginColumnar {
 7605                position,
 7606                reset: false,
 7607                mode,
 7608                goal_column: point_for_position.exact_unclipped.column(),
 7609            },
 7610            window,
 7611            cx,
 7612        );
 7613    }
 7614
 7615    fn update_edit_prediction_preview(
 7616        &mut self,
 7617        modifiers: &Modifiers,
 7618        window: &mut Window,
 7619        cx: &mut Context<Self>,
 7620    ) {
 7621        let mut modifiers_held = false;
 7622        if let Some(accept_keystroke) = self
 7623            .accept_edit_prediction_keybind(false, window, cx)
 7624            .keystroke()
 7625        {
 7626            modifiers_held = modifiers_held
 7627                || (&accept_keystroke.modifiers == modifiers
 7628                    && accept_keystroke.modifiers.modified());
 7629        };
 7630        if let Some(accept_partial_keystroke) = self
 7631            .accept_edit_prediction_keybind(true, window, cx)
 7632            .keystroke()
 7633        {
 7634            modifiers_held = modifiers_held
 7635                || (&accept_partial_keystroke.modifiers == modifiers
 7636                    && accept_partial_keystroke.modifiers.modified());
 7637        }
 7638
 7639        if modifiers_held {
 7640            if matches!(
 7641                self.edit_prediction_preview,
 7642                EditPredictionPreview::Inactive { .. }
 7643            ) {
 7644                self.edit_prediction_preview = EditPredictionPreview::Active {
 7645                    previous_scroll_position: None,
 7646                    since: Instant::now(),
 7647                };
 7648
 7649                self.update_visible_edit_prediction(window, cx);
 7650                cx.notify();
 7651            }
 7652        } else if let EditPredictionPreview::Active {
 7653            previous_scroll_position,
 7654            since,
 7655        } = self.edit_prediction_preview
 7656        {
 7657            if let (Some(previous_scroll_position), Some(position_map)) =
 7658                (previous_scroll_position, self.last_position_map.as_ref())
 7659            {
 7660                self.set_scroll_position(
 7661                    previous_scroll_position
 7662                        .scroll_position(&position_map.snapshot.display_snapshot),
 7663                    window,
 7664                    cx,
 7665                );
 7666            }
 7667
 7668            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7669                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7670            };
 7671            self.clear_row_highlights::<EditPredictionPreview>();
 7672            self.update_visible_edit_prediction(window, cx);
 7673            cx.notify();
 7674        }
 7675    }
 7676
 7677    fn update_visible_edit_prediction(
 7678        &mut self,
 7679        _window: &mut Window,
 7680        cx: &mut Context<Self>,
 7681    ) -> Option<()> {
 7682        if DisableAiSettings::get_global(cx).disable_ai {
 7683            return None;
 7684        }
 7685
 7686        let selection = self.selections.newest_anchor();
 7687        let cursor = selection.head();
 7688        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7689        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7690        let excerpt_id = cursor.excerpt_id;
 7691
 7692        let show_in_menu = self.show_edit_predictions_in_menu();
 7693        let completions_menu_has_precedence = !show_in_menu
 7694            && (self.context_menu.borrow().is_some()
 7695                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7696
 7697        if completions_menu_has_precedence
 7698            || !offset_selection.is_empty()
 7699            || self
 7700                .active_edit_prediction
 7701                .as_ref()
 7702                .is_some_and(|completion| {
 7703                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7704                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7705                    !invalidation_range.contains(&offset_selection.head())
 7706                })
 7707        {
 7708            self.discard_edit_prediction(false, cx);
 7709            return None;
 7710        }
 7711
 7712        self.take_active_edit_prediction(cx);
 7713        let Some(provider) = self.edit_prediction_provider() else {
 7714            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7715            return None;
 7716        };
 7717
 7718        let (buffer, cursor_buffer_position) =
 7719            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7720
 7721        self.edit_prediction_settings =
 7722            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7723
 7724        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7725            self.discard_edit_prediction(false, cx);
 7726            return None;
 7727        };
 7728
 7729        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7730
 7731        if self.edit_prediction_indent_conflict {
 7732            let cursor_point = cursor.to_point(&multibuffer);
 7733
 7734            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7735
 7736            if let Some((_, indent)) = indents.iter().next()
 7737                && indent.len == cursor_point.column
 7738            {
 7739                self.edit_prediction_indent_conflict = false;
 7740            }
 7741        }
 7742
 7743        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7744        let edits = edit_prediction
 7745            .edits
 7746            .into_iter()
 7747            .flat_map(|(range, new_text)| {
 7748                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7749                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7750                Some((start..end, new_text))
 7751            })
 7752            .collect::<Vec<_>>();
 7753        if edits.is_empty() {
 7754            return None;
 7755        }
 7756
 7757        let first_edit_start = edits.first().unwrap().0.start;
 7758        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7759        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7760
 7761        let last_edit_end = edits.last().unwrap().0.end;
 7762        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7763        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7764
 7765        let cursor_row = cursor.to_point(&multibuffer).row;
 7766
 7767        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7768
 7769        let mut inlay_ids = Vec::new();
 7770        let invalidation_row_range;
 7771        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7772            Some(cursor_row..edit_end_row)
 7773        } else if cursor_row > edit_end_row {
 7774            Some(edit_start_row..cursor_row)
 7775        } else {
 7776            None
 7777        };
 7778        let supports_jump = self
 7779            .edit_prediction_provider
 7780            .as_ref()
 7781            .map(|provider| provider.provider.supports_jump_to_edit())
 7782            .unwrap_or(true);
 7783
 7784        let is_move = supports_jump
 7785            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7786        let completion = if is_move {
 7787            invalidation_row_range =
 7788                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7789            let target = first_edit_start;
 7790            EditPrediction::Move { target, snapshot }
 7791        } else {
 7792            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7793                && !self.edit_predictions_hidden_for_vim_mode;
 7794
 7795            if show_completions_in_buffer {
 7796                if edits
 7797                    .iter()
 7798                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7799                {
 7800                    let mut inlays = Vec::new();
 7801                    for (range, new_text) in &edits {
 7802                        let inlay = Inlay::edit_prediction(
 7803                            post_inc(&mut self.next_inlay_id),
 7804                            range.start,
 7805                            new_text.as_str(),
 7806                        );
 7807                        inlay_ids.push(inlay.id);
 7808                        inlays.push(inlay);
 7809                    }
 7810
 7811                    self.splice_inlays(&[], inlays, cx);
 7812                } else {
 7813                    let background_color = cx.theme().status().deleted_background;
 7814                    self.highlight_text::<EditPredictionHighlight>(
 7815                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7816                        HighlightStyle {
 7817                            background_color: Some(background_color),
 7818                            ..Default::default()
 7819                        },
 7820                        cx,
 7821                    );
 7822                }
 7823            }
 7824
 7825            invalidation_row_range = edit_start_row..edit_end_row;
 7826
 7827            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7828                if provider.show_tab_accept_marker() {
 7829                    EditDisplayMode::TabAccept
 7830                } else {
 7831                    EditDisplayMode::Inline
 7832                }
 7833            } else {
 7834                EditDisplayMode::DiffPopover
 7835            };
 7836
 7837            EditPrediction::Edit {
 7838                edits,
 7839                edit_preview: edit_prediction.edit_preview,
 7840                display_mode,
 7841                snapshot,
 7842            }
 7843        };
 7844
 7845        let invalidation_range = multibuffer
 7846            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7847            ..multibuffer.anchor_after(Point::new(
 7848                invalidation_row_range.end,
 7849                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7850            ));
 7851
 7852        self.stale_edit_prediction_in_menu = None;
 7853        self.active_edit_prediction = Some(EditPredictionState {
 7854            inlay_ids,
 7855            completion,
 7856            completion_id: edit_prediction.id,
 7857            invalidation_range,
 7858        });
 7859
 7860        cx.notify();
 7861
 7862        Some(())
 7863    }
 7864
 7865    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7866        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7867    }
 7868
 7869    fn clear_tasks(&mut self) {
 7870        self.tasks.clear()
 7871    }
 7872
 7873    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7874        if self.tasks.insert(key, value).is_some() {
 7875            // This case should hopefully be rare, but just in case...
 7876            log::error!(
 7877                "multiple different run targets found on a single line, only the last target will be rendered"
 7878            )
 7879        }
 7880    }
 7881
 7882    /// Get all display points of breakpoints that will be rendered within editor
 7883    ///
 7884    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7885    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7886    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7887    fn active_breakpoints(
 7888        &self,
 7889        range: Range<DisplayRow>,
 7890        window: &mut Window,
 7891        cx: &mut Context<Self>,
 7892    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7893        let mut breakpoint_display_points = HashMap::default();
 7894
 7895        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7896            return breakpoint_display_points;
 7897        };
 7898
 7899        let snapshot = self.snapshot(window, cx);
 7900
 7901        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7902        let Some(project) = self.project() else {
 7903            return breakpoint_display_points;
 7904        };
 7905
 7906        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7907            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7908
 7909        for (buffer_snapshot, range, excerpt_id) in
 7910            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7911        {
 7912            let Some(buffer) = project
 7913                .read(cx)
 7914                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7915            else {
 7916                continue;
 7917            };
 7918            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7919                &buffer,
 7920                Some(
 7921                    buffer_snapshot.anchor_before(range.start)
 7922                        ..buffer_snapshot.anchor_after(range.end),
 7923                ),
 7924                buffer_snapshot,
 7925                cx,
 7926            );
 7927            for (breakpoint, state) in breakpoints {
 7928                let multi_buffer_anchor =
 7929                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7930                let position = multi_buffer_anchor
 7931                    .to_point(multi_buffer_snapshot)
 7932                    .to_display_point(&snapshot);
 7933
 7934                breakpoint_display_points.insert(
 7935                    position.row(),
 7936                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7937                );
 7938            }
 7939        }
 7940
 7941        breakpoint_display_points
 7942    }
 7943
 7944    fn breakpoint_context_menu(
 7945        &self,
 7946        anchor: Anchor,
 7947        window: &mut Window,
 7948        cx: &mut Context<Self>,
 7949    ) -> Entity<ui::ContextMenu> {
 7950        let weak_editor = cx.weak_entity();
 7951        let focus_handle = self.focus_handle(cx);
 7952
 7953        let row = self
 7954            .buffer
 7955            .read(cx)
 7956            .snapshot(cx)
 7957            .summary_for_anchor::<Point>(&anchor)
 7958            .row;
 7959
 7960        let breakpoint = self
 7961            .breakpoint_at_row(row, window, cx)
 7962            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7963
 7964        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7965            "Edit Log Breakpoint"
 7966        } else {
 7967            "Set Log Breakpoint"
 7968        };
 7969
 7970        let condition_breakpoint_msg = if breakpoint
 7971            .as_ref()
 7972            .is_some_and(|bp| bp.1.condition.is_some())
 7973        {
 7974            "Edit Condition Breakpoint"
 7975        } else {
 7976            "Set Condition Breakpoint"
 7977        };
 7978
 7979        let hit_condition_breakpoint_msg = if breakpoint
 7980            .as_ref()
 7981            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7982        {
 7983            "Edit Hit Condition Breakpoint"
 7984        } else {
 7985            "Set Hit Condition Breakpoint"
 7986        };
 7987
 7988        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7989            "Unset Breakpoint"
 7990        } else {
 7991            "Set Breakpoint"
 7992        };
 7993
 7994        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7995
 7996        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7997            BreakpointState::Enabled => Some("Disable"),
 7998            BreakpointState::Disabled => Some("Enable"),
 7999        });
 8000
 8001        let (anchor, breakpoint) =
 8002            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8003
 8004        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8005            menu.on_blur_subscription(Subscription::new(|| {}))
 8006                .context(focus_handle)
 8007                .when(run_to_cursor, |this| {
 8008                    let weak_editor = weak_editor.clone();
 8009                    this.entry("Run to cursor", None, move |window, cx| {
 8010                        weak_editor
 8011                            .update(cx, |editor, cx| {
 8012                                editor.change_selections(
 8013                                    SelectionEffects::no_scroll(),
 8014                                    window,
 8015                                    cx,
 8016                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8017                                );
 8018                            })
 8019                            .ok();
 8020
 8021                        window.dispatch_action(Box::new(RunToCursor), cx);
 8022                    })
 8023                    .separator()
 8024                })
 8025                .when_some(toggle_state_msg, |this, msg| {
 8026                    this.entry(msg, None, {
 8027                        let weak_editor = weak_editor.clone();
 8028                        let breakpoint = breakpoint.clone();
 8029                        move |_window, cx| {
 8030                            weak_editor
 8031                                .update(cx, |this, cx| {
 8032                                    this.edit_breakpoint_at_anchor(
 8033                                        anchor,
 8034                                        breakpoint.as_ref().clone(),
 8035                                        BreakpointEditAction::InvertState,
 8036                                        cx,
 8037                                    );
 8038                                })
 8039                                .log_err();
 8040                        }
 8041                    })
 8042                })
 8043                .entry(set_breakpoint_msg, None, {
 8044                    let weak_editor = weak_editor.clone();
 8045                    let breakpoint = breakpoint.clone();
 8046                    move |_window, cx| {
 8047                        weak_editor
 8048                            .update(cx, |this, cx| {
 8049                                this.edit_breakpoint_at_anchor(
 8050                                    anchor,
 8051                                    breakpoint.as_ref().clone(),
 8052                                    BreakpointEditAction::Toggle,
 8053                                    cx,
 8054                                );
 8055                            })
 8056                            .log_err();
 8057                    }
 8058                })
 8059                .entry(log_breakpoint_msg, None, {
 8060                    let breakpoint = breakpoint.clone();
 8061                    let weak_editor = weak_editor.clone();
 8062                    move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |this, cx| {
 8065                                this.add_edit_breakpoint_block(
 8066                                    anchor,
 8067                                    breakpoint.as_ref(),
 8068                                    BreakpointPromptEditAction::Log,
 8069                                    window,
 8070                                    cx,
 8071                                );
 8072                            })
 8073                            .log_err();
 8074                    }
 8075                })
 8076                .entry(condition_breakpoint_msg, None, {
 8077                    let breakpoint = breakpoint.clone();
 8078                    let weak_editor = weak_editor.clone();
 8079                    move |window, cx| {
 8080                        weak_editor
 8081                            .update(cx, |this, cx| {
 8082                                this.add_edit_breakpoint_block(
 8083                                    anchor,
 8084                                    breakpoint.as_ref(),
 8085                                    BreakpointPromptEditAction::Condition,
 8086                                    window,
 8087                                    cx,
 8088                                );
 8089                            })
 8090                            .log_err();
 8091                    }
 8092                })
 8093                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8094                    weak_editor
 8095                        .update(cx, |this, cx| {
 8096                            this.add_edit_breakpoint_block(
 8097                                anchor,
 8098                                breakpoint.as_ref(),
 8099                                BreakpointPromptEditAction::HitCondition,
 8100                                window,
 8101                                cx,
 8102                            );
 8103                        })
 8104                        .log_err();
 8105                })
 8106        })
 8107    }
 8108
 8109    fn render_breakpoint(
 8110        &self,
 8111        position: Anchor,
 8112        row: DisplayRow,
 8113        breakpoint: &Breakpoint,
 8114        state: Option<BreakpointSessionState>,
 8115        cx: &mut Context<Self>,
 8116    ) -> IconButton {
 8117        let is_rejected = state.is_some_and(|s| !s.verified);
 8118        // Is it a breakpoint that shows up when hovering over gutter?
 8119        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8120            (false, false),
 8121            |PhantomBreakpointIndicator {
 8122                 is_active,
 8123                 display_row,
 8124                 collides_with_existing_breakpoint,
 8125             }| {
 8126                (
 8127                    is_active && display_row == row,
 8128                    collides_with_existing_breakpoint,
 8129                )
 8130            },
 8131        );
 8132
 8133        let (color, icon) = {
 8134            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8135                (false, false) => ui::IconName::DebugBreakpoint,
 8136                (true, false) => ui::IconName::DebugLogBreakpoint,
 8137                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8138                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8139            };
 8140
 8141            let color = if is_phantom {
 8142                Color::Hint
 8143            } else if is_rejected {
 8144                Color::Disabled
 8145            } else {
 8146                Color::Debugger
 8147            };
 8148
 8149            (color, icon)
 8150        };
 8151
 8152        let breakpoint = Arc::from(breakpoint.clone());
 8153
 8154        let alt_as_text = gpui::Keystroke {
 8155            modifiers: Modifiers::secondary_key(),
 8156            ..Default::default()
 8157        };
 8158        let primary_action_text = if breakpoint.is_disabled() {
 8159            "Enable breakpoint"
 8160        } else if is_phantom && !collides_with_existing {
 8161            "Set breakpoint"
 8162        } else {
 8163            "Unset breakpoint"
 8164        };
 8165        let focus_handle = self.focus_handle.clone();
 8166
 8167        let meta = if is_rejected {
 8168            SharedString::from("No executable code is associated with this line.")
 8169        } else if collides_with_existing && !breakpoint.is_disabled() {
 8170            SharedString::from(format!(
 8171                "{alt_as_text}-click to disable,\nright-click for more options."
 8172            ))
 8173        } else {
 8174            SharedString::from("Right-click for more options.")
 8175        };
 8176        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8177            .icon_size(IconSize::XSmall)
 8178            .size(ui::ButtonSize::None)
 8179            .when(is_rejected, |this| {
 8180                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8181            })
 8182            .icon_color(color)
 8183            .style(ButtonStyle::Transparent)
 8184            .on_click(cx.listener({
 8185                move |editor, event: &ClickEvent, window, cx| {
 8186                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8187                        BreakpointEditAction::InvertState
 8188                    } else {
 8189                        BreakpointEditAction::Toggle
 8190                    };
 8191
 8192                    window.focus(&editor.focus_handle(cx));
 8193                    editor.edit_breakpoint_at_anchor(
 8194                        position,
 8195                        breakpoint.as_ref().clone(),
 8196                        edit_action,
 8197                        cx,
 8198                    );
 8199                }
 8200            }))
 8201            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8202                editor.set_breakpoint_context_menu(
 8203                    row,
 8204                    Some(position),
 8205                    event.position(),
 8206                    window,
 8207                    cx,
 8208                );
 8209            }))
 8210            .tooltip(move |window, cx| {
 8211                Tooltip::with_meta_in(
 8212                    primary_action_text,
 8213                    Some(&ToggleBreakpoint),
 8214                    meta.clone(),
 8215                    &focus_handle,
 8216                    window,
 8217                    cx,
 8218                )
 8219            })
 8220    }
 8221
 8222    fn build_tasks_context(
 8223        project: &Entity<Project>,
 8224        buffer: &Entity<Buffer>,
 8225        buffer_row: u32,
 8226        tasks: &Arc<RunnableTasks>,
 8227        cx: &mut Context<Self>,
 8228    ) -> Task<Option<task::TaskContext>> {
 8229        let position = Point::new(buffer_row, tasks.column);
 8230        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8231        let location = Location {
 8232            buffer: buffer.clone(),
 8233            range: range_start..range_start,
 8234        };
 8235        // Fill in the environmental variables from the tree-sitter captures
 8236        let mut captured_task_variables = TaskVariables::default();
 8237        for (capture_name, value) in tasks.extra_variables.clone() {
 8238            captured_task_variables.insert(
 8239                task::VariableName::Custom(capture_name.into()),
 8240                value.clone(),
 8241            );
 8242        }
 8243        project.update(cx, |project, cx| {
 8244            project.task_store().update(cx, |task_store, cx| {
 8245                task_store.task_context_for_location(captured_task_variables, location, cx)
 8246            })
 8247        })
 8248    }
 8249
 8250    pub fn spawn_nearest_task(
 8251        &mut self,
 8252        action: &SpawnNearestTask,
 8253        window: &mut Window,
 8254        cx: &mut Context<Self>,
 8255    ) {
 8256        let Some((workspace, _)) = self.workspace.clone() else {
 8257            return;
 8258        };
 8259        let Some(project) = self.project.clone() else {
 8260            return;
 8261        };
 8262
 8263        // Try to find a closest, enclosing node using tree-sitter that has a task
 8264        let Some((buffer, buffer_row, tasks)) = self
 8265            .find_enclosing_node_task(cx)
 8266            // Or find the task that's closest in row-distance.
 8267            .or_else(|| self.find_closest_task(cx))
 8268        else {
 8269            return;
 8270        };
 8271
 8272        let reveal_strategy = action.reveal;
 8273        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8274        cx.spawn_in(window, async move |_, cx| {
 8275            let context = task_context.await?;
 8276            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8277
 8278            let resolved = &mut resolved_task.resolved;
 8279            resolved.reveal = reveal_strategy;
 8280
 8281            workspace
 8282                .update_in(cx, |workspace, window, cx| {
 8283                    workspace.schedule_resolved_task(
 8284                        task_source_kind,
 8285                        resolved_task,
 8286                        false,
 8287                        window,
 8288                        cx,
 8289                    );
 8290                })
 8291                .ok()
 8292        })
 8293        .detach();
 8294    }
 8295
 8296    fn find_closest_task(
 8297        &mut self,
 8298        cx: &mut Context<Self>,
 8299    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8300        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8301
 8302        let ((buffer_id, row), tasks) = self
 8303            .tasks
 8304            .iter()
 8305            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8306
 8307        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8308        let tasks = Arc::new(tasks.to_owned());
 8309        Some((buffer, *row, tasks))
 8310    }
 8311
 8312    fn find_enclosing_node_task(
 8313        &mut self,
 8314        cx: &mut Context<Self>,
 8315    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8316        let snapshot = self.buffer.read(cx).snapshot(cx);
 8317        let offset = self.selections.newest::<usize>(cx).head();
 8318        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8319        let buffer_id = excerpt.buffer().remote_id();
 8320
 8321        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8322        let mut cursor = layer.node().walk();
 8323
 8324        while cursor.goto_first_child_for_byte(offset).is_some() {
 8325            if cursor.node().end_byte() == offset {
 8326                cursor.goto_next_sibling();
 8327            }
 8328        }
 8329
 8330        // Ascend to the smallest ancestor that contains the range and has a task.
 8331        loop {
 8332            let node = cursor.node();
 8333            let node_range = node.byte_range();
 8334            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8335
 8336            // Check if this node contains our offset
 8337            if node_range.start <= offset && node_range.end >= offset {
 8338                // If it contains offset, check for task
 8339                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8340                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8341                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8342                }
 8343            }
 8344
 8345            if !cursor.goto_parent() {
 8346                break;
 8347            }
 8348        }
 8349        None
 8350    }
 8351
 8352    fn render_run_indicator(
 8353        &self,
 8354        _style: &EditorStyle,
 8355        is_active: bool,
 8356        row: DisplayRow,
 8357        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8358        cx: &mut Context<Self>,
 8359    ) -> IconButton {
 8360        let color = Color::Muted;
 8361        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8362
 8363        IconButton::new(
 8364            ("run_indicator", row.0 as usize),
 8365            ui::IconName::PlayOutlined,
 8366        )
 8367        .shape(ui::IconButtonShape::Square)
 8368        .icon_size(IconSize::XSmall)
 8369        .icon_color(color)
 8370        .toggle_state(is_active)
 8371        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8372            let quick_launch = match e {
 8373                ClickEvent::Keyboard(_) => true,
 8374                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8375            };
 8376
 8377            window.focus(&editor.focus_handle(cx));
 8378            editor.toggle_code_actions(
 8379                &ToggleCodeActions {
 8380                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8381                    quick_launch,
 8382                },
 8383                window,
 8384                cx,
 8385            );
 8386        }))
 8387        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8388            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8389        }))
 8390    }
 8391
 8392    pub fn context_menu_visible(&self) -> bool {
 8393        !self.edit_prediction_preview_is_active()
 8394            && self
 8395                .context_menu
 8396                .borrow()
 8397                .as_ref()
 8398                .is_some_and(|menu| menu.visible())
 8399    }
 8400
 8401    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8402        self.context_menu
 8403            .borrow()
 8404            .as_ref()
 8405            .map(|menu| menu.origin())
 8406    }
 8407
 8408    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8409        self.context_menu_options = Some(options);
 8410    }
 8411
 8412    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8413    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8414
 8415    fn render_edit_prediction_popover(
 8416        &mut self,
 8417        text_bounds: &Bounds<Pixels>,
 8418        content_origin: gpui::Point<Pixels>,
 8419        right_margin: Pixels,
 8420        editor_snapshot: &EditorSnapshot,
 8421        visible_row_range: Range<DisplayRow>,
 8422        scroll_top: f32,
 8423        scroll_bottom: f32,
 8424        line_layouts: &[LineWithInvisibles],
 8425        line_height: Pixels,
 8426        scroll_pixel_position: gpui::Point<Pixels>,
 8427        newest_selection_head: Option<DisplayPoint>,
 8428        editor_width: Pixels,
 8429        style: &EditorStyle,
 8430        window: &mut Window,
 8431        cx: &mut App,
 8432    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8433        if self.mode().is_minimap() {
 8434            return None;
 8435        }
 8436        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8437
 8438        if self.edit_prediction_visible_in_cursor_popover(true) {
 8439            return None;
 8440        }
 8441
 8442        match &active_edit_prediction.completion {
 8443            EditPrediction::Move { target, .. } => {
 8444                let target_display_point = target.to_display_point(editor_snapshot);
 8445
 8446                if self.edit_prediction_requires_modifier() {
 8447                    if !self.edit_prediction_preview_is_active() {
 8448                        return None;
 8449                    }
 8450
 8451                    self.render_edit_prediction_modifier_jump_popover(
 8452                        text_bounds,
 8453                        content_origin,
 8454                        visible_row_range,
 8455                        line_layouts,
 8456                        line_height,
 8457                        scroll_pixel_position,
 8458                        newest_selection_head,
 8459                        target_display_point,
 8460                        window,
 8461                        cx,
 8462                    )
 8463                } else {
 8464                    self.render_edit_prediction_eager_jump_popover(
 8465                        text_bounds,
 8466                        content_origin,
 8467                        editor_snapshot,
 8468                        visible_row_range,
 8469                        scroll_top,
 8470                        scroll_bottom,
 8471                        line_height,
 8472                        scroll_pixel_position,
 8473                        target_display_point,
 8474                        editor_width,
 8475                        window,
 8476                        cx,
 8477                    )
 8478                }
 8479            }
 8480            EditPrediction::Edit {
 8481                display_mode: EditDisplayMode::Inline,
 8482                ..
 8483            } => None,
 8484            EditPrediction::Edit {
 8485                display_mode: EditDisplayMode::TabAccept,
 8486                edits,
 8487                ..
 8488            } => {
 8489                let range = &edits.first()?.0;
 8490                let target_display_point = range.end.to_display_point(editor_snapshot);
 8491
 8492                self.render_edit_prediction_end_of_line_popover(
 8493                    "Accept",
 8494                    editor_snapshot,
 8495                    visible_row_range,
 8496                    target_display_point,
 8497                    line_height,
 8498                    scroll_pixel_position,
 8499                    content_origin,
 8500                    editor_width,
 8501                    window,
 8502                    cx,
 8503                )
 8504            }
 8505            EditPrediction::Edit {
 8506                edits,
 8507                edit_preview,
 8508                display_mode: EditDisplayMode::DiffPopover,
 8509                snapshot,
 8510            } => self.render_edit_prediction_diff_popover(
 8511                text_bounds,
 8512                content_origin,
 8513                right_margin,
 8514                editor_snapshot,
 8515                visible_row_range,
 8516                line_layouts,
 8517                line_height,
 8518                scroll_pixel_position,
 8519                newest_selection_head,
 8520                editor_width,
 8521                style,
 8522                edits,
 8523                edit_preview,
 8524                snapshot,
 8525                window,
 8526                cx,
 8527            ),
 8528        }
 8529    }
 8530
 8531    fn render_edit_prediction_modifier_jump_popover(
 8532        &mut self,
 8533        text_bounds: &Bounds<Pixels>,
 8534        content_origin: gpui::Point<Pixels>,
 8535        visible_row_range: Range<DisplayRow>,
 8536        line_layouts: &[LineWithInvisibles],
 8537        line_height: Pixels,
 8538        scroll_pixel_position: gpui::Point<Pixels>,
 8539        newest_selection_head: Option<DisplayPoint>,
 8540        target_display_point: DisplayPoint,
 8541        window: &mut Window,
 8542        cx: &mut App,
 8543    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8544        let scrolled_content_origin =
 8545            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8546
 8547        const SCROLL_PADDING_Y: Pixels = px(12.);
 8548
 8549        if target_display_point.row() < visible_row_range.start {
 8550            return self.render_edit_prediction_scroll_popover(
 8551                |_| SCROLL_PADDING_Y,
 8552                IconName::ArrowUp,
 8553                visible_row_range,
 8554                line_layouts,
 8555                newest_selection_head,
 8556                scrolled_content_origin,
 8557                window,
 8558                cx,
 8559            );
 8560        } else if target_display_point.row() >= visible_row_range.end {
 8561            return self.render_edit_prediction_scroll_popover(
 8562                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8563                IconName::ArrowDown,
 8564                visible_row_range,
 8565                line_layouts,
 8566                newest_selection_head,
 8567                scrolled_content_origin,
 8568                window,
 8569                cx,
 8570            );
 8571        }
 8572
 8573        const POLE_WIDTH: Pixels = px(2.);
 8574
 8575        let line_layout =
 8576            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8577        let target_column = target_display_point.column() as usize;
 8578
 8579        let target_x = line_layout.x_for_index(target_column);
 8580        let target_y =
 8581            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8582
 8583        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8584
 8585        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8586        border_color.l += 0.001;
 8587
 8588        let mut element = v_flex()
 8589            .items_end()
 8590            .when(flag_on_right, |el| el.items_start())
 8591            .child(if flag_on_right {
 8592                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8593                    .rounded_bl(px(0.))
 8594                    .rounded_tl(px(0.))
 8595                    .border_l_2()
 8596                    .border_color(border_color)
 8597            } else {
 8598                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8599                    .rounded_br(px(0.))
 8600                    .rounded_tr(px(0.))
 8601                    .border_r_2()
 8602                    .border_color(border_color)
 8603            })
 8604            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8605            .into_any();
 8606
 8607        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8608
 8609        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8610            - point(
 8611                if flag_on_right {
 8612                    POLE_WIDTH
 8613                } else {
 8614                    size.width - POLE_WIDTH
 8615                },
 8616                size.height - line_height,
 8617            );
 8618
 8619        origin.x = origin.x.max(content_origin.x);
 8620
 8621        element.prepaint_at(origin, window, cx);
 8622
 8623        Some((element, origin))
 8624    }
 8625
 8626    fn render_edit_prediction_scroll_popover(
 8627        &mut self,
 8628        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8629        scroll_icon: IconName,
 8630        visible_row_range: Range<DisplayRow>,
 8631        line_layouts: &[LineWithInvisibles],
 8632        newest_selection_head: Option<DisplayPoint>,
 8633        scrolled_content_origin: gpui::Point<Pixels>,
 8634        window: &mut Window,
 8635        cx: &mut App,
 8636    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8637        let mut element = self
 8638            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8639            .into_any();
 8640
 8641        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8642
 8643        let cursor = newest_selection_head?;
 8644        let cursor_row_layout =
 8645            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8646        let cursor_column = cursor.column() as usize;
 8647
 8648        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8649
 8650        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8651
 8652        element.prepaint_at(origin, window, cx);
 8653        Some((element, origin))
 8654    }
 8655
 8656    fn render_edit_prediction_eager_jump_popover(
 8657        &mut self,
 8658        text_bounds: &Bounds<Pixels>,
 8659        content_origin: gpui::Point<Pixels>,
 8660        editor_snapshot: &EditorSnapshot,
 8661        visible_row_range: Range<DisplayRow>,
 8662        scroll_top: f32,
 8663        scroll_bottom: f32,
 8664        line_height: Pixels,
 8665        scroll_pixel_position: gpui::Point<Pixels>,
 8666        target_display_point: DisplayPoint,
 8667        editor_width: Pixels,
 8668        window: &mut Window,
 8669        cx: &mut App,
 8670    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8671        if target_display_point.row().as_f32() < scroll_top {
 8672            let mut element = self
 8673                .render_edit_prediction_line_popover(
 8674                    "Jump to Edit",
 8675                    Some(IconName::ArrowUp),
 8676                    window,
 8677                    cx,
 8678                )?
 8679                .into_any();
 8680
 8681            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8682            let offset = point(
 8683                (text_bounds.size.width - size.width) / 2.,
 8684                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8685            );
 8686
 8687            let origin = text_bounds.origin + offset;
 8688            element.prepaint_at(origin, window, cx);
 8689            Some((element, origin))
 8690        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8691            let mut element = self
 8692                .render_edit_prediction_line_popover(
 8693                    "Jump to Edit",
 8694                    Some(IconName::ArrowDown),
 8695                    window,
 8696                    cx,
 8697                )?
 8698                .into_any();
 8699
 8700            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8701            let offset = point(
 8702                (text_bounds.size.width - size.width) / 2.,
 8703                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8704            );
 8705
 8706            let origin = text_bounds.origin + offset;
 8707            element.prepaint_at(origin, window, cx);
 8708            Some((element, origin))
 8709        } else {
 8710            self.render_edit_prediction_end_of_line_popover(
 8711                "Jump to Edit",
 8712                editor_snapshot,
 8713                visible_row_range,
 8714                target_display_point,
 8715                line_height,
 8716                scroll_pixel_position,
 8717                content_origin,
 8718                editor_width,
 8719                window,
 8720                cx,
 8721            )
 8722        }
 8723    }
 8724
 8725    fn render_edit_prediction_end_of_line_popover(
 8726        self: &mut Editor,
 8727        label: &'static str,
 8728        editor_snapshot: &EditorSnapshot,
 8729        visible_row_range: Range<DisplayRow>,
 8730        target_display_point: DisplayPoint,
 8731        line_height: Pixels,
 8732        scroll_pixel_position: gpui::Point<Pixels>,
 8733        content_origin: gpui::Point<Pixels>,
 8734        editor_width: Pixels,
 8735        window: &mut Window,
 8736        cx: &mut App,
 8737    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8738        let target_line_end = DisplayPoint::new(
 8739            target_display_point.row(),
 8740            editor_snapshot.line_len(target_display_point.row()),
 8741        );
 8742
 8743        let mut element = self
 8744            .render_edit_prediction_line_popover(label, None, window, cx)?
 8745            .into_any();
 8746
 8747        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8748
 8749        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8750
 8751        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8752        let mut origin = start_point
 8753            + line_origin
 8754            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8755        origin.x = origin.x.max(content_origin.x);
 8756
 8757        let max_x = content_origin.x + editor_width - size.width;
 8758
 8759        if origin.x > max_x {
 8760            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8761
 8762            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8763                origin.y += offset;
 8764                IconName::ArrowUp
 8765            } else {
 8766                origin.y -= offset;
 8767                IconName::ArrowDown
 8768            };
 8769
 8770            element = self
 8771                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8772                .into_any();
 8773
 8774            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8775
 8776            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8777        }
 8778
 8779        element.prepaint_at(origin, window, cx);
 8780        Some((element, origin))
 8781    }
 8782
 8783    fn render_edit_prediction_diff_popover(
 8784        self: &Editor,
 8785        text_bounds: &Bounds<Pixels>,
 8786        content_origin: gpui::Point<Pixels>,
 8787        right_margin: Pixels,
 8788        editor_snapshot: &EditorSnapshot,
 8789        visible_row_range: Range<DisplayRow>,
 8790        line_layouts: &[LineWithInvisibles],
 8791        line_height: Pixels,
 8792        scroll_pixel_position: gpui::Point<Pixels>,
 8793        newest_selection_head: Option<DisplayPoint>,
 8794        editor_width: Pixels,
 8795        style: &EditorStyle,
 8796        edits: &Vec<(Range<Anchor>, String)>,
 8797        edit_preview: &Option<language::EditPreview>,
 8798        snapshot: &language::BufferSnapshot,
 8799        window: &mut Window,
 8800        cx: &mut App,
 8801    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8802        let edit_start = edits
 8803            .first()
 8804            .unwrap()
 8805            .0
 8806            .start
 8807            .to_display_point(editor_snapshot);
 8808        let edit_end = edits
 8809            .last()
 8810            .unwrap()
 8811            .0
 8812            .end
 8813            .to_display_point(editor_snapshot);
 8814
 8815        let is_visible = visible_row_range.contains(&edit_start.row())
 8816            || visible_row_range.contains(&edit_end.row());
 8817        if !is_visible {
 8818            return None;
 8819        }
 8820
 8821        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8822            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8823        } else {
 8824            // Fallback for providers without edit_preview
 8825            crate::edit_prediction_fallback_text(edits, cx)
 8826        };
 8827
 8828        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8829        let line_count = highlighted_edits.text.lines().count();
 8830
 8831        const BORDER_WIDTH: Pixels = px(1.);
 8832
 8833        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8834        let has_keybind = keybind.is_some();
 8835
 8836        let mut element = h_flex()
 8837            .items_start()
 8838            .child(
 8839                h_flex()
 8840                    .bg(cx.theme().colors().editor_background)
 8841                    .border(BORDER_WIDTH)
 8842                    .shadow_xs()
 8843                    .border_color(cx.theme().colors().border)
 8844                    .rounded_l_lg()
 8845                    .when(line_count > 1, |el| el.rounded_br_lg())
 8846                    .pr_1()
 8847                    .child(styled_text),
 8848            )
 8849            .child(
 8850                h_flex()
 8851                    .h(line_height + BORDER_WIDTH * 2.)
 8852                    .px_1p5()
 8853                    .gap_1()
 8854                    // Workaround: For some reason, there's a gap if we don't do this
 8855                    .ml(-BORDER_WIDTH)
 8856                    .shadow(vec![gpui::BoxShadow {
 8857                        color: gpui::black().opacity(0.05),
 8858                        offset: point(px(1.), px(1.)),
 8859                        blur_radius: px(2.),
 8860                        spread_radius: px(0.),
 8861                    }])
 8862                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8863                    .border(BORDER_WIDTH)
 8864                    .border_color(cx.theme().colors().border)
 8865                    .rounded_r_lg()
 8866                    .id("edit_prediction_diff_popover_keybind")
 8867                    .when(!has_keybind, |el| {
 8868                        let status_colors = cx.theme().status();
 8869
 8870                        el.bg(status_colors.error_background)
 8871                            .border_color(status_colors.error.opacity(0.6))
 8872                            .child(Icon::new(IconName::Info).color(Color::Error))
 8873                            .cursor_default()
 8874                            .hoverable_tooltip(move |_window, cx| {
 8875                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8876                            })
 8877                    })
 8878                    .children(keybind),
 8879            )
 8880            .into_any();
 8881
 8882        let longest_row =
 8883            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8884        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8885            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8886        } else {
 8887            layout_line(
 8888                longest_row,
 8889                editor_snapshot,
 8890                style,
 8891                editor_width,
 8892                |_| false,
 8893                window,
 8894                cx,
 8895            )
 8896            .width
 8897        };
 8898
 8899        let viewport_bounds =
 8900            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8901                right: -right_margin,
 8902                ..Default::default()
 8903            });
 8904
 8905        let x_after_longest =
 8906            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8907                - scroll_pixel_position.x;
 8908
 8909        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8910
 8911        // Fully visible if it can be displayed within the window (allow overlapping other
 8912        // panes). However, this is only allowed if the popover starts within text_bounds.
 8913        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8914            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8915
 8916        let mut origin = if can_position_to_the_right {
 8917            point(
 8918                x_after_longest,
 8919                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8920                    - scroll_pixel_position.y,
 8921            )
 8922        } else {
 8923            let cursor_row = newest_selection_head.map(|head| head.row());
 8924            let above_edit = edit_start
 8925                .row()
 8926                .0
 8927                .checked_sub(line_count as u32)
 8928                .map(DisplayRow);
 8929            let below_edit = Some(edit_end.row() + 1);
 8930            let above_cursor =
 8931                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8932            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8933
 8934            // Place the edit popover adjacent to the edit if there is a location
 8935            // available that is onscreen and does not obscure the cursor. Otherwise,
 8936            // place it adjacent to the cursor.
 8937            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8938                .into_iter()
 8939                .flatten()
 8940                .find(|&start_row| {
 8941                    let end_row = start_row + line_count as u32;
 8942                    visible_row_range.contains(&start_row)
 8943                        && visible_row_range.contains(&end_row)
 8944                        && cursor_row
 8945                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 8946                })?;
 8947
 8948            content_origin
 8949                + point(
 8950                    -scroll_pixel_position.x,
 8951                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8952                )
 8953        };
 8954
 8955        origin.x -= BORDER_WIDTH;
 8956
 8957        window.defer_draw(element, origin, 1);
 8958
 8959        // Do not return an element, since it will already be drawn due to defer_draw.
 8960        None
 8961    }
 8962
 8963    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8964        px(30.)
 8965    }
 8966
 8967    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8968        if self.read_only(cx) {
 8969            cx.theme().players().read_only()
 8970        } else {
 8971            self.style.as_ref().unwrap().local_player
 8972        }
 8973    }
 8974
 8975    fn render_edit_prediction_accept_keybind(
 8976        &self,
 8977        window: &mut Window,
 8978        cx: &App,
 8979    ) -> Option<AnyElement> {
 8980        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8981        let accept_keystroke = accept_binding.keystroke()?;
 8982
 8983        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8984
 8985        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8986            Color::Accent
 8987        } else {
 8988            Color::Muted
 8989        };
 8990
 8991        h_flex()
 8992            .px_0p5()
 8993            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8994            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8995            .text_size(TextSize::XSmall.rems(cx))
 8996            .child(h_flex().children(ui::render_modifiers(
 8997                &accept_keystroke.modifiers,
 8998                PlatformStyle::platform(),
 8999                Some(modifiers_color),
 9000                Some(IconSize::XSmall.rems().into()),
 9001                true,
 9002            )))
 9003            .when(is_platform_style_mac, |parent| {
 9004                parent.child(accept_keystroke.key.clone())
 9005            })
 9006            .when(!is_platform_style_mac, |parent| {
 9007                parent.child(
 9008                    Key::new(
 9009                        util::capitalize(&accept_keystroke.key),
 9010                        Some(Color::Default),
 9011                    )
 9012                    .size(Some(IconSize::XSmall.rems().into())),
 9013                )
 9014            })
 9015            .into_any()
 9016            .into()
 9017    }
 9018
 9019    fn render_edit_prediction_line_popover(
 9020        &self,
 9021        label: impl Into<SharedString>,
 9022        icon: Option<IconName>,
 9023        window: &mut Window,
 9024        cx: &App,
 9025    ) -> Option<Stateful<Div>> {
 9026        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9027
 9028        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9029        let has_keybind = keybind.is_some();
 9030
 9031        let result = h_flex()
 9032            .id("ep-line-popover")
 9033            .py_0p5()
 9034            .pl_1()
 9035            .pr(padding_right)
 9036            .gap_1()
 9037            .rounded_md()
 9038            .border_1()
 9039            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9040            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9041            .shadow_xs()
 9042            .when(!has_keybind, |el| {
 9043                let status_colors = cx.theme().status();
 9044
 9045                el.bg(status_colors.error_background)
 9046                    .border_color(status_colors.error.opacity(0.6))
 9047                    .pl_2()
 9048                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9049                    .cursor_default()
 9050                    .hoverable_tooltip(move |_window, cx| {
 9051                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9052                    })
 9053            })
 9054            .children(keybind)
 9055            .child(
 9056                Label::new(label)
 9057                    .size(LabelSize::Small)
 9058                    .when(!has_keybind, |el| {
 9059                        el.color(cx.theme().status().error.into()).strikethrough()
 9060                    }),
 9061            )
 9062            .when(!has_keybind, |el| {
 9063                el.child(
 9064                    h_flex().ml_1().child(
 9065                        Icon::new(IconName::Info)
 9066                            .size(IconSize::Small)
 9067                            .color(cx.theme().status().error.into()),
 9068                    ),
 9069                )
 9070            })
 9071            .when_some(icon, |element, icon| {
 9072                element.child(
 9073                    div()
 9074                        .mt(px(1.5))
 9075                        .child(Icon::new(icon).size(IconSize::Small)),
 9076                )
 9077            });
 9078
 9079        Some(result)
 9080    }
 9081
 9082    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9083        let accent_color = cx.theme().colors().text_accent;
 9084        let editor_bg_color = cx.theme().colors().editor_background;
 9085        editor_bg_color.blend(accent_color.opacity(0.1))
 9086    }
 9087
 9088    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9089        let accent_color = cx.theme().colors().text_accent;
 9090        let editor_bg_color = cx.theme().colors().editor_background;
 9091        editor_bg_color.blend(accent_color.opacity(0.6))
 9092    }
 9093    fn get_prediction_provider_icon_name(
 9094        provider: &Option<RegisteredEditPredictionProvider>,
 9095    ) -> IconName {
 9096        match provider {
 9097            Some(provider) => match provider.provider.name() {
 9098                "copilot" => IconName::Copilot,
 9099                "supermaven" => IconName::Supermaven,
 9100                _ => IconName::ZedPredict,
 9101            },
 9102            None => IconName::ZedPredict,
 9103        }
 9104    }
 9105
 9106    fn render_edit_prediction_cursor_popover(
 9107        &self,
 9108        min_width: Pixels,
 9109        max_width: Pixels,
 9110        cursor_point: Point,
 9111        style: &EditorStyle,
 9112        accept_keystroke: Option<&gpui::Keystroke>,
 9113        _window: &Window,
 9114        cx: &mut Context<Editor>,
 9115    ) -> Option<AnyElement> {
 9116        let provider = self.edit_prediction_provider.as_ref()?;
 9117        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9118
 9119        if provider.provider.needs_terms_acceptance(cx) {
 9120            return Some(
 9121                h_flex()
 9122                    .min_w(min_width)
 9123                    .flex_1()
 9124                    .px_2()
 9125                    .py_1()
 9126                    .gap_3()
 9127                    .elevation_2(cx)
 9128                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9129                    .id("accept-terms")
 9130                    .cursor_pointer()
 9131                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9132                    .on_click(cx.listener(|this, _event, window, cx| {
 9133                        cx.stop_propagation();
 9134                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9135                        window.dispatch_action(
 9136                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9137                            cx,
 9138                        );
 9139                    }))
 9140                    .child(
 9141                        h_flex()
 9142                            .flex_1()
 9143                            .gap_2()
 9144                            .child(Icon::new(provider_icon))
 9145                            .child(Label::new("Accept Terms of Service"))
 9146                            .child(div().w_full())
 9147                            .child(
 9148                                Icon::new(IconName::ArrowUpRight)
 9149                                    .color(Color::Muted)
 9150                                    .size(IconSize::Small),
 9151                            )
 9152                            .into_any_element(),
 9153                    )
 9154                    .into_any(),
 9155            );
 9156        }
 9157
 9158        let is_refreshing = provider.provider.is_refreshing(cx);
 9159
 9160        fn pending_completion_container(icon: IconName) -> Div {
 9161            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9162        }
 9163
 9164        let completion = match &self.active_edit_prediction {
 9165            Some(prediction) => {
 9166                if !self.has_visible_completions_menu() {
 9167                    const RADIUS: Pixels = px(6.);
 9168                    const BORDER_WIDTH: Pixels = px(1.);
 9169
 9170                    return Some(
 9171                        h_flex()
 9172                            .elevation_2(cx)
 9173                            .border(BORDER_WIDTH)
 9174                            .border_color(cx.theme().colors().border)
 9175                            .when(accept_keystroke.is_none(), |el| {
 9176                                el.border_color(cx.theme().status().error)
 9177                            })
 9178                            .rounded(RADIUS)
 9179                            .rounded_tl(px(0.))
 9180                            .overflow_hidden()
 9181                            .child(div().px_1p5().child(match &prediction.completion {
 9182                                EditPrediction::Move { target, snapshot } => {
 9183                                    use text::ToPoint as _;
 9184                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9185                                    {
 9186                                        Icon::new(IconName::ZedPredictDown)
 9187                                    } else {
 9188                                        Icon::new(IconName::ZedPredictUp)
 9189                                    }
 9190                                }
 9191                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9192                            }))
 9193                            .child(
 9194                                h_flex()
 9195                                    .gap_1()
 9196                                    .py_1()
 9197                                    .px_2()
 9198                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9199                                    .border_l_1()
 9200                                    .border_color(cx.theme().colors().border)
 9201                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9202                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9203                                        el.child(
 9204                                            Label::new("Hold")
 9205                                                .size(LabelSize::Small)
 9206                                                .when(accept_keystroke.is_none(), |el| {
 9207                                                    el.strikethrough()
 9208                                                })
 9209                                                .line_height_style(LineHeightStyle::UiLabel),
 9210                                        )
 9211                                    })
 9212                                    .id("edit_prediction_cursor_popover_keybind")
 9213                                    .when(accept_keystroke.is_none(), |el| {
 9214                                        let status_colors = cx.theme().status();
 9215
 9216                                        el.bg(status_colors.error_background)
 9217                                            .border_color(status_colors.error.opacity(0.6))
 9218                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9219                                            .cursor_default()
 9220                                            .hoverable_tooltip(move |_window, cx| {
 9221                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9222                                                    .into()
 9223                                            })
 9224                                    })
 9225                                    .when_some(
 9226                                        accept_keystroke.as_ref(),
 9227                                        |el, accept_keystroke| {
 9228                                            el.child(h_flex().children(ui::render_modifiers(
 9229                                                &accept_keystroke.modifiers,
 9230                                                PlatformStyle::platform(),
 9231                                                Some(Color::Default),
 9232                                                Some(IconSize::XSmall.rems().into()),
 9233                                                false,
 9234                                            )))
 9235                                        },
 9236                                    ),
 9237                            )
 9238                            .into_any(),
 9239                    );
 9240                }
 9241
 9242                self.render_edit_prediction_cursor_popover_preview(
 9243                    prediction,
 9244                    cursor_point,
 9245                    style,
 9246                    cx,
 9247                )?
 9248            }
 9249
 9250            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9251                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9252                    stale_completion,
 9253                    cursor_point,
 9254                    style,
 9255                    cx,
 9256                )?,
 9257
 9258                None => pending_completion_container(provider_icon)
 9259                    .child(Label::new("...").size(LabelSize::Small)),
 9260            },
 9261
 9262            None => pending_completion_container(provider_icon)
 9263                .child(Label::new("...").size(LabelSize::Small)),
 9264        };
 9265
 9266        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9267            completion
 9268                .with_animation(
 9269                    "loading-completion",
 9270                    Animation::new(Duration::from_secs(2))
 9271                        .repeat()
 9272                        .with_easing(pulsating_between(0.4, 0.8)),
 9273                    |label, delta| label.opacity(delta),
 9274                )
 9275                .into_any_element()
 9276        } else {
 9277            completion.into_any_element()
 9278        };
 9279
 9280        let has_completion = self.active_edit_prediction.is_some();
 9281
 9282        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9283        Some(
 9284            h_flex()
 9285                .min_w(min_width)
 9286                .max_w(max_width)
 9287                .flex_1()
 9288                .elevation_2(cx)
 9289                .border_color(cx.theme().colors().border)
 9290                .child(
 9291                    div()
 9292                        .flex_1()
 9293                        .py_1()
 9294                        .px_2()
 9295                        .overflow_hidden()
 9296                        .child(completion),
 9297                )
 9298                .when_some(accept_keystroke, |el, accept_keystroke| {
 9299                    if !accept_keystroke.modifiers.modified() {
 9300                        return el;
 9301                    }
 9302
 9303                    el.child(
 9304                        h_flex()
 9305                            .h_full()
 9306                            .border_l_1()
 9307                            .rounded_r_lg()
 9308                            .border_color(cx.theme().colors().border)
 9309                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9310                            .gap_1()
 9311                            .py_1()
 9312                            .px_2()
 9313                            .child(
 9314                                h_flex()
 9315                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9316                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9317                                    .child(h_flex().children(ui::render_modifiers(
 9318                                        &accept_keystroke.modifiers,
 9319                                        PlatformStyle::platform(),
 9320                                        Some(if !has_completion {
 9321                                            Color::Muted
 9322                                        } else {
 9323                                            Color::Default
 9324                                        }),
 9325                                        None,
 9326                                        false,
 9327                                    ))),
 9328                            )
 9329                            .child(Label::new("Preview").into_any_element())
 9330                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9331                    )
 9332                })
 9333                .into_any(),
 9334        )
 9335    }
 9336
 9337    fn render_edit_prediction_cursor_popover_preview(
 9338        &self,
 9339        completion: &EditPredictionState,
 9340        cursor_point: Point,
 9341        style: &EditorStyle,
 9342        cx: &mut Context<Editor>,
 9343    ) -> Option<Div> {
 9344        use text::ToPoint as _;
 9345
 9346        fn render_relative_row_jump(
 9347            prefix: impl Into<String>,
 9348            current_row: u32,
 9349            target_row: u32,
 9350        ) -> Div {
 9351            let (row_diff, arrow) = if target_row < current_row {
 9352                (current_row - target_row, IconName::ArrowUp)
 9353            } else {
 9354                (target_row - current_row, IconName::ArrowDown)
 9355            };
 9356
 9357            h_flex()
 9358                .child(
 9359                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9360                        .color(Color::Muted)
 9361                        .size(LabelSize::Small),
 9362                )
 9363                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9364        }
 9365
 9366        let supports_jump = self
 9367            .edit_prediction_provider
 9368            .as_ref()
 9369            .map(|provider| provider.provider.supports_jump_to_edit())
 9370            .unwrap_or(true);
 9371
 9372        match &completion.completion {
 9373            EditPrediction::Move {
 9374                target, snapshot, ..
 9375            } => {
 9376                if !supports_jump {
 9377                    return None;
 9378                }
 9379
 9380                Some(
 9381                    h_flex()
 9382                        .px_2()
 9383                        .gap_2()
 9384                        .flex_1()
 9385                        .child(
 9386                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9387                                Icon::new(IconName::ZedPredictDown)
 9388                            } else {
 9389                                Icon::new(IconName::ZedPredictUp)
 9390                            },
 9391                        )
 9392                        .child(Label::new("Jump to Edit")),
 9393                )
 9394            }
 9395
 9396            EditPrediction::Edit {
 9397                edits,
 9398                edit_preview,
 9399                snapshot,
 9400                display_mode: _,
 9401            } => {
 9402                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9403
 9404                let (highlighted_edits, has_more_lines) =
 9405                    if let Some(edit_preview) = edit_preview.as_ref() {
 9406                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9407                            .first_line_preview()
 9408                    } else {
 9409                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9410                    };
 9411
 9412                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9413                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9414
 9415                let preview = h_flex()
 9416                    .gap_1()
 9417                    .min_w_16()
 9418                    .child(styled_text)
 9419                    .when(has_more_lines, |parent| parent.child(""));
 9420
 9421                let left = if supports_jump && first_edit_row != cursor_point.row {
 9422                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9423                        .into_any_element()
 9424                } else {
 9425                    let icon_name =
 9426                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9427                    Icon::new(icon_name).into_any_element()
 9428                };
 9429
 9430                Some(
 9431                    h_flex()
 9432                        .h_full()
 9433                        .flex_1()
 9434                        .gap_2()
 9435                        .pr_1()
 9436                        .overflow_x_hidden()
 9437                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9438                        .child(left)
 9439                        .child(preview),
 9440                )
 9441            }
 9442        }
 9443    }
 9444
 9445    pub fn render_context_menu(
 9446        &self,
 9447        style: &EditorStyle,
 9448        max_height_in_lines: u32,
 9449        window: &mut Window,
 9450        cx: &mut Context<Editor>,
 9451    ) -> Option<AnyElement> {
 9452        let menu = self.context_menu.borrow();
 9453        let menu = menu.as_ref()?;
 9454        if !menu.visible() {
 9455            return None;
 9456        };
 9457        Some(menu.render(style, max_height_in_lines, window, cx))
 9458    }
 9459
 9460    fn render_context_menu_aside(
 9461        &mut self,
 9462        max_size: Size<Pixels>,
 9463        window: &mut Window,
 9464        cx: &mut Context<Editor>,
 9465    ) -> Option<AnyElement> {
 9466        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9467            if menu.visible() {
 9468                menu.render_aside(max_size, window, cx)
 9469            } else {
 9470                None
 9471            }
 9472        })
 9473    }
 9474
 9475    fn hide_context_menu(
 9476        &mut self,
 9477        window: &mut Window,
 9478        cx: &mut Context<Self>,
 9479    ) -> Option<CodeContextMenu> {
 9480        cx.notify();
 9481        self.completion_tasks.clear();
 9482        let context_menu = self.context_menu.borrow_mut().take();
 9483        self.stale_edit_prediction_in_menu.take();
 9484        self.update_visible_edit_prediction(window, cx);
 9485        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9486            && let Some(completion_provider) = &self.completion_provider
 9487        {
 9488            completion_provider.selection_changed(None, window, cx);
 9489        }
 9490        context_menu
 9491    }
 9492
 9493    fn show_snippet_choices(
 9494        &mut self,
 9495        choices: &Vec<String>,
 9496        selection: Range<Anchor>,
 9497        cx: &mut Context<Self>,
 9498    ) {
 9499        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9500            (Some(a), Some(b)) if a == b => a,
 9501            _ => {
 9502                log::error!("expected anchor range to have matching buffer IDs");
 9503                return;
 9504            }
 9505        };
 9506        let multi_buffer = self.buffer().read(cx);
 9507        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9508            return;
 9509        };
 9510
 9511        let id = post_inc(&mut self.next_completion_id);
 9512        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9513        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9514            CompletionsMenu::new_snippet_choices(
 9515                id,
 9516                true,
 9517                choices,
 9518                selection,
 9519                buffer,
 9520                snippet_sort_order,
 9521            ),
 9522        ));
 9523    }
 9524
 9525    pub fn insert_snippet(
 9526        &mut self,
 9527        insertion_ranges: &[Range<usize>],
 9528        snippet: Snippet,
 9529        window: &mut Window,
 9530        cx: &mut Context<Self>,
 9531    ) -> Result<()> {
 9532        struct Tabstop<T> {
 9533            is_end_tabstop: bool,
 9534            ranges: Vec<Range<T>>,
 9535            choices: Option<Vec<String>>,
 9536        }
 9537
 9538        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9539            let snippet_text: Arc<str> = snippet.text.clone().into();
 9540            let edits = insertion_ranges
 9541                .iter()
 9542                .cloned()
 9543                .map(|range| (range, snippet_text.clone()));
 9544            let autoindent_mode = AutoindentMode::Block {
 9545                original_indent_columns: Vec::new(),
 9546            };
 9547            buffer.edit(edits, Some(autoindent_mode), cx);
 9548
 9549            let snapshot = &*buffer.read(cx);
 9550            let snippet = &snippet;
 9551            snippet
 9552                .tabstops
 9553                .iter()
 9554                .map(|tabstop| {
 9555                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9556                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9557                    });
 9558                    let mut tabstop_ranges = tabstop
 9559                        .ranges
 9560                        .iter()
 9561                        .flat_map(|tabstop_range| {
 9562                            let mut delta = 0_isize;
 9563                            insertion_ranges.iter().map(move |insertion_range| {
 9564                                let insertion_start = insertion_range.start as isize + delta;
 9565                                delta +=
 9566                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9567
 9568                                let start = ((insertion_start + tabstop_range.start) as usize)
 9569                                    .min(snapshot.len());
 9570                                let end = ((insertion_start + tabstop_range.end) as usize)
 9571                                    .min(snapshot.len());
 9572                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9573                            })
 9574                        })
 9575                        .collect::<Vec<_>>();
 9576                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9577
 9578                    Tabstop {
 9579                        is_end_tabstop,
 9580                        ranges: tabstop_ranges,
 9581                        choices: tabstop.choices.clone(),
 9582                    }
 9583                })
 9584                .collect::<Vec<_>>()
 9585        });
 9586        if let Some(tabstop) = tabstops.first() {
 9587            self.change_selections(Default::default(), window, cx, |s| {
 9588                // Reverse order so that the first range is the newest created selection.
 9589                // Completions will use it and autoscroll will prioritize it.
 9590                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9591            });
 9592
 9593            if let Some(choices) = &tabstop.choices
 9594                && let Some(selection) = tabstop.ranges.first()
 9595            {
 9596                self.show_snippet_choices(choices, selection.clone(), cx)
 9597            }
 9598
 9599            // If we're already at the last tabstop and it's at the end of the snippet,
 9600            // we're done, we don't need to keep the state around.
 9601            if !tabstop.is_end_tabstop {
 9602                let choices = tabstops
 9603                    .iter()
 9604                    .map(|tabstop| tabstop.choices.clone())
 9605                    .collect();
 9606
 9607                let ranges = tabstops
 9608                    .into_iter()
 9609                    .map(|tabstop| tabstop.ranges)
 9610                    .collect::<Vec<_>>();
 9611
 9612                self.snippet_stack.push(SnippetState {
 9613                    active_index: 0,
 9614                    ranges,
 9615                    choices,
 9616                });
 9617            }
 9618
 9619            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9620            if self.autoclose_regions.is_empty() {
 9621                let snapshot = self.buffer.read(cx).snapshot(cx);
 9622                let mut all_selections = self.selections.all::<Point>(cx);
 9623                for selection in &mut all_selections {
 9624                    let selection_head = selection.head();
 9625                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9626                        continue;
 9627                    };
 9628
 9629                    let mut bracket_pair = None;
 9630                    let max_lookup_length = scope
 9631                        .brackets()
 9632                        .map(|(pair, _)| {
 9633                            pair.start
 9634                                .as_str()
 9635                                .chars()
 9636                                .count()
 9637                                .max(pair.end.as_str().chars().count())
 9638                        })
 9639                        .max();
 9640                    if let Some(max_lookup_length) = max_lookup_length {
 9641                        let next_text = snapshot
 9642                            .chars_at(selection_head)
 9643                            .take(max_lookup_length)
 9644                            .collect::<String>();
 9645                        let prev_text = snapshot
 9646                            .reversed_chars_at(selection_head)
 9647                            .take(max_lookup_length)
 9648                            .collect::<String>();
 9649
 9650                        for (pair, enabled) in scope.brackets() {
 9651                            if enabled
 9652                                && pair.close
 9653                                && prev_text.starts_with(pair.start.as_str())
 9654                                && next_text.starts_with(pair.end.as_str())
 9655                            {
 9656                                bracket_pair = Some(pair.clone());
 9657                                break;
 9658                            }
 9659                        }
 9660                    }
 9661
 9662                    if let Some(pair) = bracket_pair {
 9663                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9664                        let autoclose_enabled =
 9665                            self.use_autoclose && snapshot_settings.use_autoclose;
 9666                        if autoclose_enabled {
 9667                            let start = snapshot.anchor_after(selection_head);
 9668                            let end = snapshot.anchor_after(selection_head);
 9669                            self.autoclose_regions.push(AutocloseRegion {
 9670                                selection_id: selection.id,
 9671                                range: start..end,
 9672                                pair,
 9673                            });
 9674                        }
 9675                    }
 9676                }
 9677            }
 9678        }
 9679        Ok(())
 9680    }
 9681
 9682    pub fn move_to_next_snippet_tabstop(
 9683        &mut self,
 9684        window: &mut Window,
 9685        cx: &mut Context<Self>,
 9686    ) -> bool {
 9687        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9688    }
 9689
 9690    pub fn move_to_prev_snippet_tabstop(
 9691        &mut self,
 9692        window: &mut Window,
 9693        cx: &mut Context<Self>,
 9694    ) -> bool {
 9695        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9696    }
 9697
 9698    pub fn move_to_snippet_tabstop(
 9699        &mut self,
 9700        bias: Bias,
 9701        window: &mut Window,
 9702        cx: &mut Context<Self>,
 9703    ) -> bool {
 9704        if let Some(mut snippet) = self.snippet_stack.pop() {
 9705            match bias {
 9706                Bias::Left => {
 9707                    if snippet.active_index > 0 {
 9708                        snippet.active_index -= 1;
 9709                    } else {
 9710                        self.snippet_stack.push(snippet);
 9711                        return false;
 9712                    }
 9713                }
 9714                Bias::Right => {
 9715                    if snippet.active_index + 1 < snippet.ranges.len() {
 9716                        snippet.active_index += 1;
 9717                    } else {
 9718                        self.snippet_stack.push(snippet);
 9719                        return false;
 9720                    }
 9721                }
 9722            }
 9723            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9724                self.change_selections(Default::default(), window, cx, |s| {
 9725                    // Reverse order so that the first range is the newest created selection.
 9726                    // Completions will use it and autoscroll will prioritize it.
 9727                    s.select_ranges(current_ranges.iter().rev().cloned())
 9728                });
 9729
 9730                if let Some(choices) = &snippet.choices[snippet.active_index]
 9731                    && let Some(selection) = current_ranges.first()
 9732                {
 9733                    self.show_snippet_choices(choices, selection.clone(), cx);
 9734                }
 9735
 9736                // If snippet state is not at the last tabstop, push it back on the stack
 9737                if snippet.active_index + 1 < snippet.ranges.len() {
 9738                    self.snippet_stack.push(snippet);
 9739                }
 9740                return true;
 9741            }
 9742        }
 9743
 9744        false
 9745    }
 9746
 9747    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9748        self.transact(window, cx, |this, window, cx| {
 9749            this.select_all(&SelectAll, window, cx);
 9750            this.insert("", window, cx);
 9751        });
 9752    }
 9753
 9754    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9756        self.transact(window, cx, |this, window, cx| {
 9757            this.select_autoclose_pair(window, cx);
 9758            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9759            if !this.linked_edit_ranges.is_empty() {
 9760                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9761                let snapshot = this.buffer.read(cx).snapshot(cx);
 9762
 9763                for selection in selections.iter() {
 9764                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9765                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9766                    if selection_start.buffer_id != selection_end.buffer_id {
 9767                        continue;
 9768                    }
 9769                    if let Some(ranges) =
 9770                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9771                    {
 9772                        for (buffer, entries) in ranges {
 9773                            linked_ranges.entry(buffer).or_default().extend(entries);
 9774                        }
 9775                    }
 9776                }
 9777            }
 9778
 9779            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9780            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9781            for selection in &mut selections {
 9782                if selection.is_empty() {
 9783                    let old_head = selection.head();
 9784                    let mut new_head =
 9785                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9786                            .to_point(&display_map);
 9787                    if let Some((buffer, line_buffer_range)) = display_map
 9788                        .buffer_snapshot
 9789                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9790                    {
 9791                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9792                        let indent_len = match indent_size.kind {
 9793                            IndentKind::Space => {
 9794                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9795                            }
 9796                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9797                        };
 9798                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9799                            let indent_len = indent_len.get();
 9800                            new_head = cmp::min(
 9801                                new_head,
 9802                                MultiBufferPoint::new(
 9803                                    old_head.row,
 9804                                    ((old_head.column - 1) / indent_len) * indent_len,
 9805                                ),
 9806                            );
 9807                        }
 9808                    }
 9809
 9810                    selection.set_head(new_head, SelectionGoal::None);
 9811                }
 9812            }
 9813
 9814            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9815            this.insert("", window, cx);
 9816            let empty_str: Arc<str> = Arc::from("");
 9817            for (buffer, edits) in linked_ranges {
 9818                let snapshot = buffer.read(cx).snapshot();
 9819                use text::ToPoint as TP;
 9820
 9821                let edits = edits
 9822                    .into_iter()
 9823                    .map(|range| {
 9824                        let end_point = TP::to_point(&range.end, &snapshot);
 9825                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9826
 9827                        if end_point == start_point {
 9828                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9829                                .saturating_sub(1);
 9830                            start_point =
 9831                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9832                        };
 9833
 9834                        (start_point..end_point, empty_str.clone())
 9835                    })
 9836                    .sorted_by_key(|(range, _)| range.start)
 9837                    .collect::<Vec<_>>();
 9838                buffer.update(cx, |this, cx| {
 9839                    this.edit(edits, None, cx);
 9840                })
 9841            }
 9842            this.refresh_edit_prediction(true, false, window, cx);
 9843            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9844        });
 9845    }
 9846
 9847    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9848        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9849        self.transact(window, cx, |this, window, cx| {
 9850            this.change_selections(Default::default(), window, cx, |s| {
 9851                s.move_with(|map, selection| {
 9852                    if selection.is_empty() {
 9853                        let cursor = movement::right(map, selection.head());
 9854                        selection.end = cursor;
 9855                        selection.reversed = true;
 9856                        selection.goal = SelectionGoal::None;
 9857                    }
 9858                })
 9859            });
 9860            this.insert("", window, cx);
 9861            this.refresh_edit_prediction(true, false, window, cx);
 9862        });
 9863    }
 9864
 9865    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9866        if self.mode.is_single_line() {
 9867            cx.propagate();
 9868            return;
 9869        }
 9870
 9871        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9872        if self.move_to_prev_snippet_tabstop(window, cx) {
 9873            return;
 9874        }
 9875        self.outdent(&Outdent, window, cx);
 9876    }
 9877
 9878    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9879        if self.mode.is_single_line() {
 9880            cx.propagate();
 9881            return;
 9882        }
 9883
 9884        if self.move_to_next_snippet_tabstop(window, cx) {
 9885            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9886            return;
 9887        }
 9888        if self.read_only(cx) {
 9889            return;
 9890        }
 9891        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9892        let mut selections = self.selections.all_adjusted(cx);
 9893        let buffer = self.buffer.read(cx);
 9894        let snapshot = buffer.snapshot(cx);
 9895        let rows_iter = selections.iter().map(|s| s.head().row);
 9896        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9897
 9898        let has_some_cursor_in_whitespace = selections
 9899            .iter()
 9900            .filter(|selection| selection.is_empty())
 9901            .any(|selection| {
 9902                let cursor = selection.head();
 9903                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9904                cursor.column < current_indent.len
 9905            });
 9906
 9907        let mut edits = Vec::new();
 9908        let mut prev_edited_row = 0;
 9909        let mut row_delta = 0;
 9910        for selection in &mut selections {
 9911            if selection.start.row != prev_edited_row {
 9912                row_delta = 0;
 9913            }
 9914            prev_edited_row = selection.end.row;
 9915
 9916            // If the selection is non-empty, then increase the indentation of the selected lines.
 9917            if !selection.is_empty() {
 9918                row_delta =
 9919                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9920                continue;
 9921            }
 9922
 9923            let cursor = selection.head();
 9924            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9925            if let Some(suggested_indent) =
 9926                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9927            {
 9928                // Don't do anything if already at suggested indent
 9929                // and there is any other cursor which is not
 9930                if has_some_cursor_in_whitespace
 9931                    && cursor.column == current_indent.len
 9932                    && current_indent.len == suggested_indent.len
 9933                {
 9934                    continue;
 9935                }
 9936
 9937                // Adjust line and move cursor to suggested indent
 9938                // if cursor is not at suggested indent
 9939                if cursor.column < suggested_indent.len
 9940                    && cursor.column <= current_indent.len
 9941                    && current_indent.len <= suggested_indent.len
 9942                {
 9943                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9944                    selection.end = selection.start;
 9945                    if row_delta == 0 {
 9946                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9947                            cursor.row,
 9948                            current_indent,
 9949                            suggested_indent,
 9950                        ));
 9951                        row_delta = suggested_indent.len - current_indent.len;
 9952                    }
 9953                    continue;
 9954                }
 9955
 9956                // If current indent is more than suggested indent
 9957                // only move cursor to current indent and skip indent
 9958                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9959                    selection.start = Point::new(cursor.row, current_indent.len);
 9960                    selection.end = selection.start;
 9961                    continue;
 9962                }
 9963            }
 9964
 9965            // Otherwise, insert a hard or soft tab.
 9966            let settings = buffer.language_settings_at(cursor, cx);
 9967            let tab_size = if settings.hard_tabs {
 9968                IndentSize::tab()
 9969            } else {
 9970                let tab_size = settings.tab_size.get();
 9971                let indent_remainder = snapshot
 9972                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9973                    .flat_map(str::chars)
 9974                    .fold(row_delta % tab_size, |counter: u32, c| {
 9975                        if c == '\t' {
 9976                            0
 9977                        } else {
 9978                            (counter + 1) % tab_size
 9979                        }
 9980                    });
 9981
 9982                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9983                IndentSize::spaces(chars_to_next_tab_stop)
 9984            };
 9985            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9986            selection.end = selection.start;
 9987            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9988            row_delta += tab_size.len;
 9989        }
 9990
 9991        self.transact(window, cx, |this, window, cx| {
 9992            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9993            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9994            this.refresh_edit_prediction(true, false, window, cx);
 9995        });
 9996    }
 9997
 9998    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9999        if self.read_only(cx) {
10000            return;
10001        }
10002        if self.mode.is_single_line() {
10003            cx.propagate();
10004            return;
10005        }
10006
10007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10008        let mut selections = self.selections.all::<Point>(cx);
10009        let mut prev_edited_row = 0;
10010        let mut row_delta = 0;
10011        let mut edits = Vec::new();
10012        let buffer = self.buffer.read(cx);
10013        let snapshot = buffer.snapshot(cx);
10014        for selection in &mut selections {
10015            if selection.start.row != prev_edited_row {
10016                row_delta = 0;
10017            }
10018            prev_edited_row = selection.end.row;
10019
10020            row_delta =
10021                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10022        }
10023
10024        self.transact(window, cx, |this, window, cx| {
10025            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10026            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10027        });
10028    }
10029
10030    fn indent_selection(
10031        buffer: &MultiBuffer,
10032        snapshot: &MultiBufferSnapshot,
10033        selection: &mut Selection<Point>,
10034        edits: &mut Vec<(Range<Point>, String)>,
10035        delta_for_start_row: u32,
10036        cx: &App,
10037    ) -> u32 {
10038        let settings = buffer.language_settings_at(selection.start, cx);
10039        let tab_size = settings.tab_size.get();
10040        let indent_kind = if settings.hard_tabs {
10041            IndentKind::Tab
10042        } else {
10043            IndentKind::Space
10044        };
10045        let mut start_row = selection.start.row;
10046        let mut end_row = selection.end.row + 1;
10047
10048        // If a selection ends at the beginning of a line, don't indent
10049        // that last line.
10050        if selection.end.column == 0 && selection.end.row > selection.start.row {
10051            end_row -= 1;
10052        }
10053
10054        // Avoid re-indenting a row that has already been indented by a
10055        // previous selection, but still update this selection's column
10056        // to reflect that indentation.
10057        if delta_for_start_row > 0 {
10058            start_row += 1;
10059            selection.start.column += delta_for_start_row;
10060            if selection.end.row == selection.start.row {
10061                selection.end.column += delta_for_start_row;
10062            }
10063        }
10064
10065        let mut delta_for_end_row = 0;
10066        let has_multiple_rows = start_row + 1 != end_row;
10067        for row in start_row..end_row {
10068            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10069            let indent_delta = match (current_indent.kind, indent_kind) {
10070                (IndentKind::Space, IndentKind::Space) => {
10071                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10072                    IndentSize::spaces(columns_to_next_tab_stop)
10073                }
10074                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10075                (_, IndentKind::Tab) => IndentSize::tab(),
10076            };
10077
10078            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10079                0
10080            } else {
10081                selection.start.column
10082            };
10083            let row_start = Point::new(row, start);
10084            edits.push((
10085                row_start..row_start,
10086                indent_delta.chars().collect::<String>(),
10087            ));
10088
10089            // Update this selection's endpoints to reflect the indentation.
10090            if row == selection.start.row {
10091                selection.start.column += indent_delta.len;
10092            }
10093            if row == selection.end.row {
10094                selection.end.column += indent_delta.len;
10095                delta_for_end_row = indent_delta.len;
10096            }
10097        }
10098
10099        if selection.start.row == selection.end.row {
10100            delta_for_start_row + delta_for_end_row
10101        } else {
10102            delta_for_end_row
10103        }
10104    }
10105
10106    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10107        if self.read_only(cx) {
10108            return;
10109        }
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10117        let selections = self.selections.all::<Point>(cx);
10118        let mut deletion_ranges = Vec::new();
10119        let mut last_outdent = None;
10120        {
10121            let buffer = self.buffer.read(cx);
10122            let snapshot = buffer.snapshot(cx);
10123            for selection in &selections {
10124                let settings = buffer.language_settings_at(selection.start, cx);
10125                let tab_size = settings.tab_size.get();
10126                let mut rows = selection.spanned_rows(false, &display_map);
10127
10128                // Avoid re-outdenting a row that has already been outdented by a
10129                // previous selection.
10130                if let Some(last_row) = last_outdent
10131                    && last_row == rows.start
10132                {
10133                    rows.start = rows.start.next_row();
10134                }
10135                let has_multiple_rows = rows.len() > 1;
10136                for row in rows.iter_rows() {
10137                    let indent_size = snapshot.indent_size_for_line(row);
10138                    if indent_size.len > 0 {
10139                        let deletion_len = match indent_size.kind {
10140                            IndentKind::Space => {
10141                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10142                                if columns_to_prev_tab_stop == 0 {
10143                                    tab_size
10144                                } else {
10145                                    columns_to_prev_tab_stop
10146                                }
10147                            }
10148                            IndentKind::Tab => 1,
10149                        };
10150                        let start = if has_multiple_rows
10151                            || deletion_len > selection.start.column
10152                            || indent_size.len < selection.start.column
10153                        {
10154                            0
10155                        } else {
10156                            selection.start.column - deletion_len
10157                        };
10158                        deletion_ranges.push(
10159                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10160                        );
10161                        last_outdent = Some(row);
10162                    }
10163                }
10164            }
10165        }
10166
10167        self.transact(window, cx, |this, window, cx| {
10168            this.buffer.update(cx, |buffer, cx| {
10169                let empty_str: Arc<str> = Arc::default();
10170                buffer.edit(
10171                    deletion_ranges
10172                        .into_iter()
10173                        .map(|range| (range, empty_str.clone())),
10174                    None,
10175                    cx,
10176                );
10177            });
10178            let selections = this.selections.all::<usize>(cx);
10179            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10180        });
10181    }
10182
10183    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10184        if self.read_only(cx) {
10185            return;
10186        }
10187        if self.mode.is_single_line() {
10188            cx.propagate();
10189            return;
10190        }
10191
10192        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10193        let selections = self
10194            .selections
10195            .all::<usize>(cx)
10196            .into_iter()
10197            .map(|s| s.range());
10198
10199        self.transact(window, cx, |this, window, cx| {
10200            this.buffer.update(cx, |buffer, cx| {
10201                buffer.autoindent_ranges(selections, cx);
10202            });
10203            let selections = this.selections.all::<usize>(cx);
10204            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10205        });
10206    }
10207
10208    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10211        let selections = self.selections.all::<Point>(cx);
10212
10213        let mut new_cursors = Vec::new();
10214        let mut edit_ranges = Vec::new();
10215        let mut selections = selections.iter().peekable();
10216        while let Some(selection) = selections.next() {
10217            let mut rows = selection.spanned_rows(false, &display_map);
10218            let goal_display_column = selection.head().to_display_point(&display_map).column();
10219
10220            // Accumulate contiguous regions of rows that we want to delete.
10221            while let Some(next_selection) = selections.peek() {
10222                let next_rows = next_selection.spanned_rows(false, &display_map);
10223                if next_rows.start <= rows.end {
10224                    rows.end = next_rows.end;
10225                    selections.next().unwrap();
10226                } else {
10227                    break;
10228                }
10229            }
10230
10231            let buffer = &display_map.buffer_snapshot;
10232            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10233            let edit_end;
10234            let cursor_buffer_row;
10235            if buffer.max_point().row >= rows.end.0 {
10236                // If there's a line after the range, delete the \n from the end of the row range
10237                // and position the cursor on the next line.
10238                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10239                cursor_buffer_row = rows.end;
10240            } else {
10241                // If there isn't a line after the range, delete the \n from the line before the
10242                // start of the row range and position the cursor there.
10243                edit_start = edit_start.saturating_sub(1);
10244                edit_end = buffer.len();
10245                cursor_buffer_row = rows.start.previous_row();
10246            }
10247
10248            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10249            *cursor.column_mut() =
10250                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10251
10252            new_cursors.push((
10253                selection.id,
10254                buffer.anchor_after(cursor.to_point(&display_map)),
10255            ));
10256            edit_ranges.push(edit_start..edit_end);
10257        }
10258
10259        self.transact(window, cx, |this, window, cx| {
10260            let buffer = this.buffer.update(cx, |buffer, cx| {
10261                let empty_str: Arc<str> = Arc::default();
10262                buffer.edit(
10263                    edit_ranges
10264                        .into_iter()
10265                        .map(|range| (range, empty_str.clone())),
10266                    None,
10267                    cx,
10268                );
10269                buffer.snapshot(cx)
10270            });
10271            let new_selections = new_cursors
10272                .into_iter()
10273                .map(|(id, cursor)| {
10274                    let cursor = cursor.to_point(&buffer);
10275                    Selection {
10276                        id,
10277                        start: cursor,
10278                        end: cursor,
10279                        reversed: false,
10280                        goal: SelectionGoal::None,
10281                    }
10282                })
10283                .collect();
10284
10285            this.change_selections(Default::default(), window, cx, |s| {
10286                s.select(new_selections);
10287            });
10288        });
10289    }
10290
10291    pub fn join_lines_impl(
10292        &mut self,
10293        insert_whitespace: bool,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) {
10297        if self.read_only(cx) {
10298            return;
10299        }
10300        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10301        for selection in self.selections.all::<Point>(cx) {
10302            let start = MultiBufferRow(selection.start.row);
10303            // Treat single line selections as if they include the next line. Otherwise this action
10304            // would do nothing for single line selections individual cursors.
10305            let end = if selection.start.row == selection.end.row {
10306                MultiBufferRow(selection.start.row + 1)
10307            } else {
10308                MultiBufferRow(selection.end.row)
10309            };
10310
10311            if let Some(last_row_range) = row_ranges.last_mut()
10312                && start <= last_row_range.end
10313            {
10314                last_row_range.end = end;
10315                continue;
10316            }
10317            row_ranges.push(start..end);
10318        }
10319
10320        let snapshot = self.buffer.read(cx).snapshot(cx);
10321        let mut cursor_positions = Vec::new();
10322        for row_range in &row_ranges {
10323            let anchor = snapshot.anchor_before(Point::new(
10324                row_range.end.previous_row().0,
10325                snapshot.line_len(row_range.end.previous_row()),
10326            ));
10327            cursor_positions.push(anchor..anchor);
10328        }
10329
10330        self.transact(window, cx, |this, window, cx| {
10331            for row_range in row_ranges.into_iter().rev() {
10332                for row in row_range.iter_rows().rev() {
10333                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10334                    let next_line_row = row.next_row();
10335                    let indent = snapshot.indent_size_for_line(next_line_row);
10336                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10337
10338                    let replace =
10339                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10340                            " "
10341                        } else {
10342                            ""
10343                        };
10344
10345                    this.buffer.update(cx, |buffer, cx| {
10346                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10347                    });
10348                }
10349            }
10350
10351            this.change_selections(Default::default(), window, cx, |s| {
10352                s.select_anchor_ranges(cursor_positions)
10353            });
10354        });
10355    }
10356
10357    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10358        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10359        self.join_lines_impl(true, window, cx);
10360    }
10361
10362    pub fn sort_lines_case_sensitive(
10363        &mut self,
10364        _: &SortLinesCaseSensitive,
10365        window: &mut Window,
10366        cx: &mut Context<Self>,
10367    ) {
10368        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10369    }
10370
10371    pub fn sort_lines_by_length(
10372        &mut self,
10373        _: &SortLinesByLength,
10374        window: &mut Window,
10375        cx: &mut Context<Self>,
10376    ) {
10377        self.manipulate_immutable_lines(window, cx, |lines| {
10378            lines.sort_by_key(|&line| line.chars().count())
10379        })
10380    }
10381
10382    pub fn sort_lines_case_insensitive(
10383        &mut self,
10384        _: &SortLinesCaseInsensitive,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        self.manipulate_immutable_lines(window, cx, |lines| {
10389            lines.sort_by_key(|line| line.to_lowercase())
10390        })
10391    }
10392
10393    pub fn unique_lines_case_insensitive(
10394        &mut self,
10395        _: &UniqueLinesCaseInsensitive,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) {
10399        self.manipulate_immutable_lines(window, cx, |lines| {
10400            let mut seen = HashSet::default();
10401            lines.retain(|line| seen.insert(line.to_lowercase()));
10402        })
10403    }
10404
10405    pub fn unique_lines_case_sensitive(
10406        &mut self,
10407        _: &UniqueLinesCaseSensitive,
10408        window: &mut Window,
10409        cx: &mut Context<Self>,
10410    ) {
10411        self.manipulate_immutable_lines(window, cx, |lines| {
10412            let mut seen = HashSet::default();
10413            lines.retain(|line| seen.insert(*line));
10414        })
10415    }
10416
10417    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10418        let Some(project) = self.project.clone() else {
10419            return;
10420        };
10421        self.reload(project, window, cx)
10422            .detach_and_notify_err(window, cx);
10423    }
10424
10425    pub fn restore_file(
10426        &mut self,
10427        _: &::git::RestoreFile,
10428        window: &mut Window,
10429        cx: &mut Context<Self>,
10430    ) {
10431        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10432        let mut buffer_ids = HashSet::default();
10433        let snapshot = self.buffer().read(cx).snapshot(cx);
10434        for selection in self.selections.all::<usize>(cx) {
10435            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10436        }
10437
10438        let buffer = self.buffer().read(cx);
10439        let ranges = buffer_ids
10440            .into_iter()
10441            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10442            .collect::<Vec<_>>();
10443
10444        self.restore_hunks_in_ranges(ranges, window, cx);
10445    }
10446
10447    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10448        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10449        let selections = self
10450            .selections
10451            .all(cx)
10452            .into_iter()
10453            .map(|s| s.range())
10454            .collect();
10455        self.restore_hunks_in_ranges(selections, window, cx);
10456    }
10457
10458    pub fn restore_hunks_in_ranges(
10459        &mut self,
10460        ranges: Vec<Range<Point>>,
10461        window: &mut Window,
10462        cx: &mut Context<Editor>,
10463    ) {
10464        let mut revert_changes = HashMap::default();
10465        let chunk_by = self
10466            .snapshot(window, cx)
10467            .hunks_for_ranges(ranges)
10468            .into_iter()
10469            .chunk_by(|hunk| hunk.buffer_id);
10470        for (buffer_id, hunks) in &chunk_by {
10471            let hunks = hunks.collect::<Vec<_>>();
10472            for hunk in &hunks {
10473                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10474            }
10475            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10476        }
10477        drop(chunk_by);
10478        if !revert_changes.is_empty() {
10479            self.transact(window, cx, |editor, window, cx| {
10480                editor.restore(revert_changes, window, cx);
10481            });
10482        }
10483    }
10484
10485    pub fn open_active_item_in_terminal(
10486        &mut self,
10487        _: &OpenInTerminal,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) {
10491        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10492            let project_path = buffer.read(cx).project_path(cx)?;
10493            let project = self.project()?.read(cx);
10494            let entry = project.entry_for_path(&project_path, cx)?;
10495            let parent = match &entry.canonical_path {
10496                Some(canonical_path) => canonical_path.to_path_buf(),
10497                None => project.absolute_path(&project_path, cx)?,
10498            }
10499            .parent()?
10500            .to_path_buf();
10501            Some(parent)
10502        }) {
10503            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10504        }
10505    }
10506
10507    fn set_breakpoint_context_menu(
10508        &mut self,
10509        display_row: DisplayRow,
10510        position: Option<Anchor>,
10511        clicked_point: gpui::Point<Pixels>,
10512        window: &mut Window,
10513        cx: &mut Context<Self>,
10514    ) {
10515        let source = self
10516            .buffer
10517            .read(cx)
10518            .snapshot(cx)
10519            .anchor_before(Point::new(display_row.0, 0u32));
10520
10521        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10522
10523        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10524            self,
10525            source,
10526            clicked_point,
10527            context_menu,
10528            window,
10529            cx,
10530        );
10531    }
10532
10533    fn add_edit_breakpoint_block(
10534        &mut self,
10535        anchor: Anchor,
10536        breakpoint: &Breakpoint,
10537        edit_action: BreakpointPromptEditAction,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        let weak_editor = cx.weak_entity();
10542        let bp_prompt = cx.new(|cx| {
10543            BreakpointPromptEditor::new(
10544                weak_editor,
10545                anchor,
10546                breakpoint.clone(),
10547                edit_action,
10548                window,
10549                cx,
10550            )
10551        });
10552
10553        let height = bp_prompt.update(cx, |this, cx| {
10554            this.prompt
10555                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10556        });
10557        let cloned_prompt = bp_prompt.clone();
10558        let blocks = vec![BlockProperties {
10559            style: BlockStyle::Sticky,
10560            placement: BlockPlacement::Above(anchor),
10561            height: Some(height),
10562            render: Arc::new(move |cx| {
10563                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10564                cloned_prompt.clone().into_any_element()
10565            }),
10566            priority: 0,
10567        }];
10568
10569        let focus_handle = bp_prompt.focus_handle(cx);
10570        window.focus(&focus_handle);
10571
10572        let block_ids = self.insert_blocks(blocks, None, cx);
10573        bp_prompt.update(cx, |prompt, _| {
10574            prompt.add_block_ids(block_ids);
10575        });
10576    }
10577
10578    pub(crate) fn breakpoint_at_row(
10579        &self,
10580        row: u32,
10581        window: &mut Window,
10582        cx: &mut Context<Self>,
10583    ) -> Option<(Anchor, Breakpoint)> {
10584        let snapshot = self.snapshot(window, cx);
10585        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10586
10587        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10588    }
10589
10590    pub(crate) fn breakpoint_at_anchor(
10591        &self,
10592        breakpoint_position: Anchor,
10593        snapshot: &EditorSnapshot,
10594        cx: &mut Context<Self>,
10595    ) -> Option<(Anchor, Breakpoint)> {
10596        let project = self.project.clone()?;
10597
10598        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10599            snapshot
10600                .buffer_snapshot
10601                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10602        })?;
10603
10604        let enclosing_excerpt = breakpoint_position.excerpt_id;
10605        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10606        let buffer_snapshot = buffer.read(cx).snapshot();
10607
10608        let row = buffer_snapshot
10609            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10610            .row;
10611
10612        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10613        let anchor_end = snapshot
10614            .buffer_snapshot
10615            .anchor_after(Point::new(row, line_len));
10616
10617        self.breakpoint_store
10618            .as_ref()?
10619            .read_with(cx, |breakpoint_store, cx| {
10620                breakpoint_store
10621                    .breakpoints(
10622                        &buffer,
10623                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10624                        &buffer_snapshot,
10625                        cx,
10626                    )
10627                    .next()
10628                    .and_then(|(bp, _)| {
10629                        let breakpoint_row = buffer_snapshot
10630                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10631                            .row;
10632
10633                        if breakpoint_row == row {
10634                            snapshot
10635                                .buffer_snapshot
10636                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10637                                .map(|position| (position, bp.bp.clone()))
10638                        } else {
10639                            None
10640                        }
10641                    })
10642            })
10643    }
10644
10645    pub fn edit_log_breakpoint(
10646        &mut self,
10647        _: &EditLogBreakpoint,
10648        window: &mut Window,
10649        cx: &mut Context<Self>,
10650    ) {
10651        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10652            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10653                message: None,
10654                state: BreakpointState::Enabled,
10655                condition: None,
10656                hit_condition: None,
10657            });
10658
10659            self.add_edit_breakpoint_block(
10660                anchor,
10661                &breakpoint,
10662                BreakpointPromptEditAction::Log,
10663                window,
10664                cx,
10665            );
10666        }
10667    }
10668
10669    fn breakpoints_at_cursors(
10670        &self,
10671        window: &mut Window,
10672        cx: &mut Context<Self>,
10673    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10674        let snapshot = self.snapshot(window, cx);
10675        let cursors = self
10676            .selections
10677            .disjoint_anchors()
10678            .iter()
10679            .map(|selection| {
10680                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10681
10682                let breakpoint_position = self
10683                    .breakpoint_at_row(cursor_position.row, window, cx)
10684                    .map(|bp| bp.0)
10685                    .unwrap_or_else(|| {
10686                        snapshot
10687                            .display_snapshot
10688                            .buffer_snapshot
10689                            .anchor_after(Point::new(cursor_position.row, 0))
10690                    });
10691
10692                let breakpoint = self
10693                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10694                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10695
10696                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10697            })
10698            // 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.
10699            .collect::<HashMap<Anchor, _>>();
10700
10701        cursors.into_iter().collect()
10702    }
10703
10704    pub fn enable_breakpoint(
10705        &mut self,
10706        _: &crate::actions::EnableBreakpoint,
10707        window: &mut Window,
10708        cx: &mut Context<Self>,
10709    ) {
10710        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10711            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10712                continue;
10713            };
10714            self.edit_breakpoint_at_anchor(
10715                anchor,
10716                breakpoint,
10717                BreakpointEditAction::InvertState,
10718                cx,
10719            );
10720        }
10721    }
10722
10723    pub fn disable_breakpoint(
10724        &mut self,
10725        _: &crate::actions::DisableBreakpoint,
10726        window: &mut Window,
10727        cx: &mut Context<Self>,
10728    ) {
10729        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10730            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10731                continue;
10732            };
10733            self.edit_breakpoint_at_anchor(
10734                anchor,
10735                breakpoint,
10736                BreakpointEditAction::InvertState,
10737                cx,
10738            );
10739        }
10740    }
10741
10742    pub fn toggle_breakpoint(
10743        &mut self,
10744        _: &crate::actions::ToggleBreakpoint,
10745        window: &mut Window,
10746        cx: &mut Context<Self>,
10747    ) {
10748        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10749            if let Some(breakpoint) = breakpoint {
10750                self.edit_breakpoint_at_anchor(
10751                    anchor,
10752                    breakpoint,
10753                    BreakpointEditAction::Toggle,
10754                    cx,
10755                );
10756            } else {
10757                self.edit_breakpoint_at_anchor(
10758                    anchor,
10759                    Breakpoint::new_standard(),
10760                    BreakpointEditAction::Toggle,
10761                    cx,
10762                );
10763            }
10764        }
10765    }
10766
10767    pub fn edit_breakpoint_at_anchor(
10768        &mut self,
10769        breakpoint_position: Anchor,
10770        breakpoint: Breakpoint,
10771        edit_action: BreakpointEditAction,
10772        cx: &mut Context<Self>,
10773    ) {
10774        let Some(breakpoint_store) = &self.breakpoint_store else {
10775            return;
10776        };
10777
10778        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10779            if breakpoint_position == Anchor::min() {
10780                self.buffer()
10781                    .read(cx)
10782                    .excerpt_buffer_ids()
10783                    .into_iter()
10784                    .next()
10785            } else {
10786                None
10787            }
10788        }) else {
10789            return;
10790        };
10791
10792        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10793            return;
10794        };
10795
10796        breakpoint_store.update(cx, |breakpoint_store, cx| {
10797            breakpoint_store.toggle_breakpoint(
10798                buffer,
10799                BreakpointWithPosition {
10800                    position: breakpoint_position.text_anchor,
10801                    bp: breakpoint,
10802                },
10803                edit_action,
10804                cx,
10805            );
10806        });
10807
10808        cx.notify();
10809    }
10810
10811    #[cfg(any(test, feature = "test-support"))]
10812    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10813        self.breakpoint_store.clone()
10814    }
10815
10816    pub fn prepare_restore_change(
10817        &self,
10818        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10819        hunk: &MultiBufferDiffHunk,
10820        cx: &mut App,
10821    ) -> Option<()> {
10822        if hunk.is_created_file() {
10823            return None;
10824        }
10825        let buffer = self.buffer.read(cx);
10826        let diff = buffer.diff_for(hunk.buffer_id)?;
10827        let buffer = buffer.buffer(hunk.buffer_id)?;
10828        let buffer = buffer.read(cx);
10829        let original_text = diff
10830            .read(cx)
10831            .base_text()
10832            .as_rope()
10833            .slice(hunk.diff_base_byte_range.clone());
10834        let buffer_snapshot = buffer.snapshot();
10835        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10836        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10837            probe
10838                .0
10839                .start
10840                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10841                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10842        }) {
10843            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10844            Some(())
10845        } else {
10846            None
10847        }
10848    }
10849
10850    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10851        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10852    }
10853
10854    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10855        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10856    }
10857
10858    fn manipulate_lines<M>(
10859        &mut self,
10860        window: &mut Window,
10861        cx: &mut Context<Self>,
10862        mut manipulate: M,
10863    ) where
10864        M: FnMut(&str) -> LineManipulationResult,
10865    {
10866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10867
10868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10869        let buffer = self.buffer.read(cx).snapshot(cx);
10870
10871        let mut edits = Vec::new();
10872
10873        let selections = self.selections.all::<Point>(cx);
10874        let mut selections = selections.iter().peekable();
10875        let mut contiguous_row_selections = Vec::new();
10876        let mut new_selections = Vec::new();
10877        let mut added_lines = 0;
10878        let mut removed_lines = 0;
10879
10880        while let Some(selection) = selections.next() {
10881            let (start_row, end_row) = consume_contiguous_rows(
10882                &mut contiguous_row_selections,
10883                selection,
10884                &display_map,
10885                &mut selections,
10886            );
10887
10888            let start_point = Point::new(start_row.0, 0);
10889            let end_point = Point::new(
10890                end_row.previous_row().0,
10891                buffer.line_len(end_row.previous_row()),
10892            );
10893            let text = buffer
10894                .text_for_range(start_point..end_point)
10895                .collect::<String>();
10896
10897            let LineManipulationResult {
10898                new_text,
10899                line_count_before,
10900                line_count_after,
10901            } = manipulate(&text);
10902
10903            edits.push((start_point..end_point, new_text));
10904
10905            // Selections must change based on added and removed line count
10906            let start_row =
10907                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10908            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10909            new_selections.push(Selection {
10910                id: selection.id,
10911                start: start_row,
10912                end: end_row,
10913                goal: SelectionGoal::None,
10914                reversed: selection.reversed,
10915            });
10916
10917            if line_count_after > line_count_before {
10918                added_lines += line_count_after - line_count_before;
10919            } else if line_count_before > line_count_after {
10920                removed_lines += line_count_before - line_count_after;
10921            }
10922        }
10923
10924        self.transact(window, cx, |this, window, cx| {
10925            let buffer = this.buffer.update(cx, |buffer, cx| {
10926                buffer.edit(edits, None, cx);
10927                buffer.snapshot(cx)
10928            });
10929
10930            // Recalculate offsets on newly edited buffer
10931            let new_selections = new_selections
10932                .iter()
10933                .map(|s| {
10934                    let start_point = Point::new(s.start.0, 0);
10935                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10936                    Selection {
10937                        id: s.id,
10938                        start: buffer.point_to_offset(start_point),
10939                        end: buffer.point_to_offset(end_point),
10940                        goal: s.goal,
10941                        reversed: s.reversed,
10942                    }
10943                })
10944                .collect();
10945
10946            this.change_selections(Default::default(), window, cx, |s| {
10947                s.select(new_selections);
10948            });
10949
10950            this.request_autoscroll(Autoscroll::fit(), cx);
10951        });
10952    }
10953
10954    fn manipulate_immutable_lines<Fn>(
10955        &mut self,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958        mut callback: Fn,
10959    ) where
10960        Fn: FnMut(&mut Vec<&str>),
10961    {
10962        self.manipulate_lines(window, cx, |text| {
10963            let mut lines: Vec<&str> = text.split('\n').collect();
10964            let line_count_before = lines.len();
10965
10966            callback(&mut lines);
10967
10968            LineManipulationResult {
10969                new_text: lines.join("\n"),
10970                line_count_before,
10971                line_count_after: lines.len(),
10972            }
10973        });
10974    }
10975
10976    fn manipulate_mutable_lines<Fn>(
10977        &mut self,
10978        window: &mut Window,
10979        cx: &mut Context<Self>,
10980        mut callback: Fn,
10981    ) where
10982        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10983    {
10984        self.manipulate_lines(window, cx, |text| {
10985            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10986            let line_count_before = lines.len();
10987
10988            callback(&mut lines);
10989
10990            LineManipulationResult {
10991                new_text: lines.join("\n"),
10992                line_count_before,
10993                line_count_after: lines.len(),
10994            }
10995        });
10996    }
10997
10998    pub fn convert_indentation_to_spaces(
10999        &mut self,
11000        _: &ConvertIndentationToSpaces,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003    ) {
11004        let settings = self.buffer.read(cx).language_settings(cx);
11005        let tab_size = settings.tab_size.get() as usize;
11006
11007        self.manipulate_mutable_lines(window, cx, |lines| {
11008            // Allocates a reasonably sized scratch buffer once for the whole loop
11009            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11010            // Avoids recomputing spaces that could be inserted many times
11011            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11012                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11013                .collect();
11014
11015            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11016                let mut chars = line.as_ref().chars();
11017                let mut col = 0;
11018                let mut changed = false;
11019
11020                for ch in chars.by_ref() {
11021                    match ch {
11022                        ' ' => {
11023                            reindented_line.push(' ');
11024                            col += 1;
11025                        }
11026                        '\t' => {
11027                            // \t are converted to spaces depending on the current column
11028                            let spaces_len = tab_size - (col % tab_size);
11029                            reindented_line.extend(&space_cache[spaces_len - 1]);
11030                            col += spaces_len;
11031                            changed = true;
11032                        }
11033                        _ => {
11034                            // If we dont append before break, the character is consumed
11035                            reindented_line.push(ch);
11036                            break;
11037                        }
11038                    }
11039                }
11040
11041                if !changed {
11042                    reindented_line.clear();
11043                    continue;
11044                }
11045                // Append the rest of the line and replace old reference with new one
11046                reindented_line.extend(chars);
11047                *line = Cow::Owned(reindented_line.clone());
11048                reindented_line.clear();
11049            }
11050        });
11051    }
11052
11053    pub fn convert_indentation_to_tabs(
11054        &mut self,
11055        _: &ConvertIndentationToTabs,
11056        window: &mut Window,
11057        cx: &mut Context<Self>,
11058    ) {
11059        let settings = self.buffer.read(cx).language_settings(cx);
11060        let tab_size = settings.tab_size.get() as usize;
11061
11062        self.manipulate_mutable_lines(window, cx, |lines| {
11063            // Allocates a reasonably sized buffer once for the whole loop
11064            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11065            // Avoids recomputing spaces that could be inserted many times
11066            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11067                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11068                .collect();
11069
11070            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11071                let mut chars = line.chars();
11072                let mut spaces_count = 0;
11073                let mut first_non_indent_char = None;
11074                let mut changed = false;
11075
11076                for ch in chars.by_ref() {
11077                    match ch {
11078                        ' ' => {
11079                            // Keep track of spaces. Append \t when we reach tab_size
11080                            spaces_count += 1;
11081                            changed = true;
11082                            if spaces_count == tab_size {
11083                                reindented_line.push('\t');
11084                                spaces_count = 0;
11085                            }
11086                        }
11087                        '\t' => {
11088                            reindented_line.push('\t');
11089                            spaces_count = 0;
11090                        }
11091                        _ => {
11092                            // Dont append it yet, we might have remaining spaces
11093                            first_non_indent_char = Some(ch);
11094                            break;
11095                        }
11096                    }
11097                }
11098
11099                if !changed {
11100                    reindented_line.clear();
11101                    continue;
11102                }
11103                // Remaining spaces that didn't make a full tab stop
11104                if spaces_count > 0 {
11105                    reindented_line.extend(&space_cache[spaces_count - 1]);
11106                }
11107                // If we consume an extra character that was not indentation, add it back
11108                if let Some(extra_char) = first_non_indent_char {
11109                    reindented_line.push(extra_char);
11110                }
11111                // Append the rest of the line and replace old reference with new one
11112                reindented_line.extend(chars);
11113                *line = Cow::Owned(reindented_line.clone());
11114                reindented_line.clear();
11115            }
11116        });
11117    }
11118
11119    pub fn convert_to_upper_case(
11120        &mut self,
11121        _: &ConvertToUpperCase,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124    ) {
11125        self.manipulate_text(window, cx, |text| text.to_uppercase())
11126    }
11127
11128    pub fn convert_to_lower_case(
11129        &mut self,
11130        _: &ConvertToLowerCase,
11131        window: &mut Window,
11132        cx: &mut Context<Self>,
11133    ) {
11134        self.manipulate_text(window, cx, |text| text.to_lowercase())
11135    }
11136
11137    pub fn convert_to_title_case(
11138        &mut self,
11139        _: &ConvertToTitleCase,
11140        window: &mut Window,
11141        cx: &mut Context<Self>,
11142    ) {
11143        self.manipulate_text(window, cx, |text| {
11144            text.split('\n')
11145                .map(|line| line.to_case(Case::Title))
11146                .join("\n")
11147        })
11148    }
11149
11150    pub fn convert_to_snake_case(
11151        &mut self,
11152        _: &ConvertToSnakeCase,
11153        window: &mut Window,
11154        cx: &mut Context<Self>,
11155    ) {
11156        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11157    }
11158
11159    pub fn convert_to_kebab_case(
11160        &mut self,
11161        _: &ConvertToKebabCase,
11162        window: &mut Window,
11163        cx: &mut Context<Self>,
11164    ) {
11165        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11166    }
11167
11168    pub fn convert_to_upper_camel_case(
11169        &mut self,
11170        _: &ConvertToUpperCamelCase,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        self.manipulate_text(window, cx, |text| {
11175            text.split('\n')
11176                .map(|line| line.to_case(Case::UpperCamel))
11177                .join("\n")
11178        })
11179    }
11180
11181    pub fn convert_to_lower_camel_case(
11182        &mut self,
11183        _: &ConvertToLowerCamelCase,
11184        window: &mut Window,
11185        cx: &mut Context<Self>,
11186    ) {
11187        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11188    }
11189
11190    pub fn convert_to_opposite_case(
11191        &mut self,
11192        _: &ConvertToOppositeCase,
11193        window: &mut Window,
11194        cx: &mut Context<Self>,
11195    ) {
11196        self.manipulate_text(window, cx, |text| {
11197            text.chars()
11198                .fold(String::with_capacity(text.len()), |mut t, c| {
11199                    if c.is_uppercase() {
11200                        t.extend(c.to_lowercase());
11201                    } else {
11202                        t.extend(c.to_uppercase());
11203                    }
11204                    t
11205                })
11206        })
11207    }
11208
11209    pub fn convert_to_sentence_case(
11210        &mut self,
11211        _: &ConvertToSentenceCase,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11216    }
11217
11218    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11219        self.manipulate_text(window, cx, |text| {
11220            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11221            if has_upper_case_characters {
11222                text.to_lowercase()
11223            } else {
11224                text.to_uppercase()
11225            }
11226        })
11227    }
11228
11229    pub fn convert_to_rot13(
11230        &mut self,
11231        _: &ConvertToRot13,
11232        window: &mut Window,
11233        cx: &mut Context<Self>,
11234    ) {
11235        self.manipulate_text(window, cx, |text| {
11236            text.chars()
11237                .map(|c| match c {
11238                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11239                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11240                    _ => c,
11241                })
11242                .collect()
11243        })
11244    }
11245
11246    pub fn convert_to_rot47(
11247        &mut self,
11248        _: &ConvertToRot47,
11249        window: &mut Window,
11250        cx: &mut Context<Self>,
11251    ) {
11252        self.manipulate_text(window, cx, |text| {
11253            text.chars()
11254                .map(|c| {
11255                    let code_point = c as u32;
11256                    if code_point >= 33 && code_point <= 126 {
11257                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11258                    }
11259                    c
11260                })
11261                .collect()
11262        })
11263    }
11264
11265    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11266    where
11267        Fn: FnMut(&str) -> String,
11268    {
11269        let buffer = self.buffer.read(cx).snapshot(cx);
11270
11271        let mut new_selections = Vec::new();
11272        let mut edits = Vec::new();
11273        let mut selection_adjustment = 0i32;
11274
11275        for selection in self.selections.all::<usize>(cx) {
11276            let selection_is_empty = selection.is_empty();
11277
11278            let (start, end) = if selection_is_empty {
11279                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11280                (word_range.start, word_range.end)
11281            } else {
11282                (selection.start, selection.end)
11283            };
11284
11285            let text = buffer.text_for_range(start..end).collect::<String>();
11286            let old_length = text.len() as i32;
11287            let text = callback(&text);
11288
11289            new_selections.push(Selection {
11290                start: (start as i32 - selection_adjustment) as usize,
11291                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11292                goal: SelectionGoal::None,
11293                ..selection
11294            });
11295
11296            selection_adjustment += old_length - text.len() as i32;
11297
11298            edits.push((start..end, text));
11299        }
11300
11301        self.transact(window, cx, |this, window, cx| {
11302            this.buffer.update(cx, |buffer, cx| {
11303                buffer.edit(edits, None, cx);
11304            });
11305
11306            this.change_selections(Default::default(), window, cx, |s| {
11307                s.select(new_selections);
11308            });
11309
11310            this.request_autoscroll(Autoscroll::fit(), cx);
11311        });
11312    }
11313
11314    pub fn move_selection_on_drop(
11315        &mut self,
11316        selection: &Selection<Anchor>,
11317        target: DisplayPoint,
11318        is_cut: bool,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11323        let buffer = &display_map.buffer_snapshot;
11324        let mut edits = Vec::new();
11325        let insert_point = display_map
11326            .clip_point(target, Bias::Left)
11327            .to_point(&display_map);
11328        let text = buffer
11329            .text_for_range(selection.start..selection.end)
11330            .collect::<String>();
11331        if is_cut {
11332            edits.push(((selection.start..selection.end), String::new()));
11333        }
11334        let insert_anchor = buffer.anchor_before(insert_point);
11335        edits.push(((insert_anchor..insert_anchor), text));
11336        let last_edit_start = insert_anchor.bias_left(buffer);
11337        let last_edit_end = insert_anchor.bias_right(buffer);
11338        self.transact(window, cx, |this, window, cx| {
11339            this.buffer.update(cx, |buffer, cx| {
11340                buffer.edit(edits, None, cx);
11341            });
11342            this.change_selections(Default::default(), window, cx, |s| {
11343                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11344            });
11345        });
11346    }
11347
11348    pub fn clear_selection_drag_state(&mut self) {
11349        self.selection_drag_state = SelectionDragState::None;
11350    }
11351
11352    pub fn duplicate(
11353        &mut self,
11354        upwards: bool,
11355        whole_lines: bool,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11360
11361        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11362        let buffer = &display_map.buffer_snapshot;
11363        let selections = self.selections.all::<Point>(cx);
11364
11365        let mut edits = Vec::new();
11366        let mut selections_iter = selections.iter().peekable();
11367        while let Some(selection) = selections_iter.next() {
11368            let mut rows = selection.spanned_rows(false, &display_map);
11369            // duplicate line-wise
11370            if whole_lines || selection.start == selection.end {
11371                // Avoid duplicating the same lines twice.
11372                while let Some(next_selection) = selections_iter.peek() {
11373                    let next_rows = next_selection.spanned_rows(false, &display_map);
11374                    if next_rows.start < rows.end {
11375                        rows.end = next_rows.end;
11376                        selections_iter.next().unwrap();
11377                    } else {
11378                        break;
11379                    }
11380                }
11381
11382                // Copy the text from the selected row region and splice it either at the start
11383                // or end of the region.
11384                let start = Point::new(rows.start.0, 0);
11385                let end = Point::new(
11386                    rows.end.previous_row().0,
11387                    buffer.line_len(rows.end.previous_row()),
11388                );
11389                let text = buffer
11390                    .text_for_range(start..end)
11391                    .chain(Some("\n"))
11392                    .collect::<String>();
11393                let insert_location = if upwards {
11394                    Point::new(rows.end.0, 0)
11395                } else {
11396                    start
11397                };
11398                edits.push((insert_location..insert_location, text));
11399            } else {
11400                // duplicate character-wise
11401                let start = selection.start;
11402                let end = selection.end;
11403                let text = buffer.text_for_range(start..end).collect::<String>();
11404                edits.push((selection.end..selection.end, text));
11405            }
11406        }
11407
11408        self.transact(window, cx, |this, _, cx| {
11409            this.buffer.update(cx, |buffer, cx| {
11410                buffer.edit(edits, None, cx);
11411            });
11412
11413            this.request_autoscroll(Autoscroll::fit(), cx);
11414        });
11415    }
11416
11417    pub fn duplicate_line_up(
11418        &mut self,
11419        _: &DuplicateLineUp,
11420        window: &mut Window,
11421        cx: &mut Context<Self>,
11422    ) {
11423        self.duplicate(true, true, window, cx);
11424    }
11425
11426    pub fn duplicate_line_down(
11427        &mut self,
11428        _: &DuplicateLineDown,
11429        window: &mut Window,
11430        cx: &mut Context<Self>,
11431    ) {
11432        self.duplicate(false, true, window, cx);
11433    }
11434
11435    pub fn duplicate_selection(
11436        &mut self,
11437        _: &DuplicateSelection,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        self.duplicate(false, false, window, cx);
11442    }
11443
11444    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11445        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11446        if self.mode.is_single_line() {
11447            cx.propagate();
11448            return;
11449        }
11450
11451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11452        let buffer = self.buffer.read(cx).snapshot(cx);
11453
11454        let mut edits = Vec::new();
11455        let mut unfold_ranges = Vec::new();
11456        let mut refold_creases = Vec::new();
11457
11458        let selections = self.selections.all::<Point>(cx);
11459        let mut selections = selections.iter().peekable();
11460        let mut contiguous_row_selections = Vec::new();
11461        let mut new_selections = Vec::new();
11462
11463        while let Some(selection) = selections.next() {
11464            // Find all the selections that span a contiguous row range
11465            let (start_row, end_row) = consume_contiguous_rows(
11466                &mut contiguous_row_selections,
11467                selection,
11468                &display_map,
11469                &mut selections,
11470            );
11471
11472            // Move the text spanned by the row range to be before the line preceding the row range
11473            if start_row.0 > 0 {
11474                let range_to_move = Point::new(
11475                    start_row.previous_row().0,
11476                    buffer.line_len(start_row.previous_row()),
11477                )
11478                    ..Point::new(
11479                        end_row.previous_row().0,
11480                        buffer.line_len(end_row.previous_row()),
11481                    );
11482                let insertion_point = display_map
11483                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11484                    .0;
11485
11486                // Don't move lines across excerpts
11487                if buffer
11488                    .excerpt_containing(insertion_point..range_to_move.end)
11489                    .is_some()
11490                {
11491                    let text = buffer
11492                        .text_for_range(range_to_move.clone())
11493                        .flat_map(|s| s.chars())
11494                        .skip(1)
11495                        .chain(['\n'])
11496                        .collect::<String>();
11497
11498                    edits.push((
11499                        buffer.anchor_after(range_to_move.start)
11500                            ..buffer.anchor_before(range_to_move.end),
11501                        String::new(),
11502                    ));
11503                    let insertion_anchor = buffer.anchor_after(insertion_point);
11504                    edits.push((insertion_anchor..insertion_anchor, text));
11505
11506                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11507
11508                    // Move selections up
11509                    new_selections.extend(contiguous_row_selections.drain(..).map(
11510                        |mut selection| {
11511                            selection.start.row -= row_delta;
11512                            selection.end.row -= row_delta;
11513                            selection
11514                        },
11515                    ));
11516
11517                    // Move folds up
11518                    unfold_ranges.push(range_to_move.clone());
11519                    for fold in display_map.folds_in_range(
11520                        buffer.anchor_before(range_to_move.start)
11521                            ..buffer.anchor_after(range_to_move.end),
11522                    ) {
11523                        let mut start = fold.range.start.to_point(&buffer);
11524                        let mut end = fold.range.end.to_point(&buffer);
11525                        start.row -= row_delta;
11526                        end.row -= row_delta;
11527                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11528                    }
11529                }
11530            }
11531
11532            // If we didn't move line(s), preserve the existing selections
11533            new_selections.append(&mut contiguous_row_selections);
11534        }
11535
11536        self.transact(window, cx, |this, window, cx| {
11537            this.unfold_ranges(&unfold_ranges, true, true, cx);
11538            this.buffer.update(cx, |buffer, cx| {
11539                for (range, text) in edits {
11540                    buffer.edit([(range, text)], None, cx);
11541                }
11542            });
11543            this.fold_creases(refold_creases, true, window, cx);
11544            this.change_selections(Default::default(), window, cx, |s| {
11545                s.select(new_selections);
11546            })
11547        });
11548    }
11549
11550    pub fn move_line_down(
11551        &mut self,
11552        _: &MoveLineDown,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11557        if self.mode.is_single_line() {
11558            cx.propagate();
11559            return;
11560        }
11561
11562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11563        let buffer = self.buffer.read(cx).snapshot(cx);
11564
11565        let mut edits = Vec::new();
11566        let mut unfold_ranges = Vec::new();
11567        let mut refold_creases = Vec::new();
11568
11569        let selections = self.selections.all::<Point>(cx);
11570        let mut selections = selections.iter().peekable();
11571        let mut contiguous_row_selections = Vec::new();
11572        let mut new_selections = Vec::new();
11573
11574        while let Some(selection) = selections.next() {
11575            // Find all the selections that span a contiguous row range
11576            let (start_row, end_row) = consume_contiguous_rows(
11577                &mut contiguous_row_selections,
11578                selection,
11579                &display_map,
11580                &mut selections,
11581            );
11582
11583            // Move the text spanned by the row range to be after the last line of the row range
11584            if end_row.0 <= buffer.max_point().row {
11585                let range_to_move =
11586                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11587                let insertion_point = display_map
11588                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11589                    .0;
11590
11591                // Don't move lines across excerpt boundaries
11592                if buffer
11593                    .excerpt_containing(range_to_move.start..insertion_point)
11594                    .is_some()
11595                {
11596                    let mut text = String::from("\n");
11597                    text.extend(buffer.text_for_range(range_to_move.clone()));
11598                    text.pop(); // Drop trailing newline
11599                    edits.push((
11600                        buffer.anchor_after(range_to_move.start)
11601                            ..buffer.anchor_before(range_to_move.end),
11602                        String::new(),
11603                    ));
11604                    let insertion_anchor = buffer.anchor_after(insertion_point);
11605                    edits.push((insertion_anchor..insertion_anchor, text));
11606
11607                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11608
11609                    // Move selections down
11610                    new_selections.extend(contiguous_row_selections.drain(..).map(
11611                        |mut selection| {
11612                            selection.start.row += row_delta;
11613                            selection.end.row += row_delta;
11614                            selection
11615                        },
11616                    ));
11617
11618                    // Move folds down
11619                    unfold_ranges.push(range_to_move.clone());
11620                    for fold in display_map.folds_in_range(
11621                        buffer.anchor_before(range_to_move.start)
11622                            ..buffer.anchor_after(range_to_move.end),
11623                    ) {
11624                        let mut start = fold.range.start.to_point(&buffer);
11625                        let mut end = fold.range.end.to_point(&buffer);
11626                        start.row += row_delta;
11627                        end.row += row_delta;
11628                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11629                    }
11630                }
11631            }
11632
11633            // If we didn't move line(s), preserve the existing selections
11634            new_selections.append(&mut contiguous_row_selections);
11635        }
11636
11637        self.transact(window, cx, |this, window, cx| {
11638            this.unfold_ranges(&unfold_ranges, true, true, cx);
11639            this.buffer.update(cx, |buffer, cx| {
11640                for (range, text) in edits {
11641                    buffer.edit([(range, text)], None, cx);
11642                }
11643            });
11644            this.fold_creases(refold_creases, true, window, cx);
11645            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11646        });
11647    }
11648
11649    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11650        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11651        let text_layout_details = &self.text_layout_details(window);
11652        self.transact(window, cx, |this, window, cx| {
11653            let edits = this.change_selections(Default::default(), window, cx, |s| {
11654                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11655                s.move_with(|display_map, selection| {
11656                    if !selection.is_empty() {
11657                        return;
11658                    }
11659
11660                    let mut head = selection.head();
11661                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11662                    if head.column() == display_map.line_len(head.row()) {
11663                        transpose_offset = display_map
11664                            .buffer_snapshot
11665                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11666                    }
11667
11668                    if transpose_offset == 0 {
11669                        return;
11670                    }
11671
11672                    *head.column_mut() += 1;
11673                    head = display_map.clip_point(head, Bias::Right);
11674                    let goal = SelectionGoal::HorizontalPosition(
11675                        display_map
11676                            .x_for_display_point(head, text_layout_details)
11677                            .into(),
11678                    );
11679                    selection.collapse_to(head, goal);
11680
11681                    let transpose_start = display_map
11682                        .buffer_snapshot
11683                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11684                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11685                        let transpose_end = display_map
11686                            .buffer_snapshot
11687                            .clip_offset(transpose_offset + 1, Bias::Right);
11688                        if let Some(ch) =
11689                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11690                        {
11691                            edits.push((transpose_start..transpose_offset, String::new()));
11692                            edits.push((transpose_end..transpose_end, ch.to_string()));
11693                        }
11694                    }
11695                });
11696                edits
11697            });
11698            this.buffer
11699                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11700            let selections = this.selections.all::<usize>(cx);
11701            this.change_selections(Default::default(), window, cx, |s| {
11702                s.select(selections);
11703            });
11704        });
11705    }
11706
11707    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11709        if self.mode.is_single_line() {
11710            cx.propagate();
11711            return;
11712        }
11713
11714        self.rewrap_impl(RewrapOptions::default(), cx)
11715    }
11716
11717    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11718        let buffer = self.buffer.read(cx).snapshot(cx);
11719        let selections = self.selections.all::<Point>(cx);
11720
11721        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11722        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11723            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11724                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11725                .peekable();
11726
11727            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11728                row
11729            } else {
11730                return Vec::new();
11731            };
11732
11733            let language_settings = buffer.language_settings_at(selection.head(), cx);
11734            let language_scope = buffer.language_scope_at(selection.head());
11735
11736            let indent_and_prefix_for_row =
11737                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11738                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11739                    let (comment_prefix, rewrap_prefix) =
11740                        if let Some(language_scope) = &language_scope {
11741                            let indent_end = Point::new(row, indent.len);
11742                            let comment_prefix = language_scope
11743                                .line_comment_prefixes()
11744                                .iter()
11745                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11746                                .map(|prefix| prefix.to_string());
11747                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11748                            let line_text_after_indent = buffer
11749                                .text_for_range(indent_end..line_end)
11750                                .collect::<String>();
11751                            let rewrap_prefix = language_scope
11752                                .rewrap_prefixes()
11753                                .iter()
11754                                .find_map(|prefix_regex| {
11755                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11756                                        if mat.start() == 0 {
11757                                            Some(mat.as_str().to_string())
11758                                        } else {
11759                                            None
11760                                        }
11761                                    })
11762                                })
11763                                .flatten();
11764                            (comment_prefix, rewrap_prefix)
11765                        } else {
11766                            (None, None)
11767                        };
11768                    (indent, comment_prefix, rewrap_prefix)
11769                };
11770
11771            let mut ranges = Vec::new();
11772            let from_empty_selection = selection.is_empty();
11773
11774            let mut current_range_start = first_row;
11775            let mut prev_row = first_row;
11776            let (
11777                mut current_range_indent,
11778                mut current_range_comment_prefix,
11779                mut current_range_rewrap_prefix,
11780            ) = indent_and_prefix_for_row(first_row);
11781
11782            for row in non_blank_rows_iter.skip(1) {
11783                let has_paragraph_break = row > prev_row + 1;
11784
11785                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11786                    indent_and_prefix_for_row(row);
11787
11788                let has_indent_change = row_indent != current_range_indent;
11789                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11790
11791                let has_boundary_change = has_comment_change
11792                    || row_rewrap_prefix.is_some()
11793                    || (has_indent_change && current_range_comment_prefix.is_some());
11794
11795                if has_paragraph_break || has_boundary_change {
11796                    ranges.push((
11797                        language_settings.clone(),
11798                        Point::new(current_range_start, 0)
11799                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11800                        current_range_indent,
11801                        current_range_comment_prefix.clone(),
11802                        current_range_rewrap_prefix.clone(),
11803                        from_empty_selection,
11804                    ));
11805                    current_range_start = row;
11806                    current_range_indent = row_indent;
11807                    current_range_comment_prefix = row_comment_prefix;
11808                    current_range_rewrap_prefix = row_rewrap_prefix;
11809                }
11810                prev_row = row;
11811            }
11812
11813            ranges.push((
11814                language_settings.clone(),
11815                Point::new(current_range_start, 0)
11816                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11817                current_range_indent,
11818                current_range_comment_prefix,
11819                current_range_rewrap_prefix,
11820                from_empty_selection,
11821            ));
11822
11823            ranges
11824        });
11825
11826        let mut edits = Vec::new();
11827        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11828
11829        for (
11830            language_settings,
11831            wrap_range,
11832            indent_size,
11833            comment_prefix,
11834            rewrap_prefix,
11835            from_empty_selection,
11836        ) in wrap_ranges
11837        {
11838            let mut start_row = wrap_range.start.row;
11839            let mut end_row = wrap_range.end.row;
11840
11841            // Skip selections that overlap with a range that has already been rewrapped.
11842            let selection_range = start_row..end_row;
11843            if rewrapped_row_ranges
11844                .iter()
11845                .any(|range| range.overlaps(&selection_range))
11846            {
11847                continue;
11848            }
11849
11850            let tab_size = language_settings.tab_size;
11851
11852            let indent_prefix = indent_size.chars().collect::<String>();
11853            let mut line_prefix = indent_prefix.clone();
11854            let mut inside_comment = false;
11855            if let Some(prefix) = &comment_prefix {
11856                line_prefix.push_str(prefix);
11857                inside_comment = true;
11858            }
11859            if let Some(prefix) = &rewrap_prefix {
11860                line_prefix.push_str(prefix);
11861            }
11862
11863            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11864                RewrapBehavior::InComments => inside_comment,
11865                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11866                RewrapBehavior::Anywhere => true,
11867            };
11868
11869            let should_rewrap = options.override_language_settings
11870                || allow_rewrap_based_on_language
11871                || self.hard_wrap.is_some();
11872            if !should_rewrap {
11873                continue;
11874            }
11875
11876            if from_empty_selection {
11877                'expand_upwards: while start_row > 0 {
11878                    let prev_row = start_row - 1;
11879                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11880                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11881                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11882                    {
11883                        start_row = prev_row;
11884                    } else {
11885                        break 'expand_upwards;
11886                    }
11887                }
11888
11889                'expand_downwards: while end_row < buffer.max_point().row {
11890                    let next_row = end_row + 1;
11891                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11892                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11893                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11894                    {
11895                        end_row = next_row;
11896                    } else {
11897                        break 'expand_downwards;
11898                    }
11899                }
11900            }
11901
11902            let start = Point::new(start_row, 0);
11903            let start_offset = start.to_offset(&buffer);
11904            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11905            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11906            let Some(lines_without_prefixes) = selection_text
11907                .lines()
11908                .enumerate()
11909                .map(|(ix, line)| {
11910                    let line_trimmed = line.trim_start();
11911                    if rewrap_prefix.is_some() && ix > 0 {
11912                        Ok(line_trimmed)
11913                    } else {
11914                        line_trimmed
11915                            .strip_prefix(&line_prefix.trim_start())
11916                            .with_context(|| {
11917                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11918                            })
11919                    }
11920                })
11921                .collect::<Result<Vec<_>, _>>()
11922                .log_err()
11923            else {
11924                continue;
11925            };
11926
11927            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11928                buffer
11929                    .language_settings_at(Point::new(start_row, 0), cx)
11930                    .preferred_line_length as usize
11931            });
11932
11933            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11934                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11935            } else {
11936                line_prefix.clone()
11937            };
11938
11939            let wrapped_text = wrap_with_prefix(
11940                line_prefix,
11941                subsequent_lines_prefix,
11942                lines_without_prefixes.join("\n"),
11943                wrap_column,
11944                tab_size,
11945                options.preserve_existing_whitespace,
11946            );
11947
11948            // TODO: should always use char-based diff while still supporting cursor behavior that
11949            // matches vim.
11950            let mut diff_options = DiffOptions::default();
11951            if options.override_language_settings {
11952                diff_options.max_word_diff_len = 0;
11953                diff_options.max_word_diff_line_count = 0;
11954            } else {
11955                diff_options.max_word_diff_len = usize::MAX;
11956                diff_options.max_word_diff_line_count = usize::MAX;
11957            }
11958
11959            for (old_range, new_text) in
11960                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11961            {
11962                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11963                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11964                edits.push((edit_start..edit_end, new_text));
11965            }
11966
11967            rewrapped_row_ranges.push(start_row..=end_row);
11968        }
11969
11970        self.buffer
11971            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11972    }
11973
11974    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11975        let mut text = String::new();
11976        let buffer = self.buffer.read(cx).snapshot(cx);
11977        let mut selections = self.selections.all::<Point>(cx);
11978        let mut clipboard_selections = Vec::with_capacity(selections.len());
11979        {
11980            let max_point = buffer.max_point();
11981            let mut is_first = true;
11982            for selection in &mut selections {
11983                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11984                if is_entire_line {
11985                    selection.start = Point::new(selection.start.row, 0);
11986                    if !selection.is_empty() && selection.end.column == 0 {
11987                        selection.end = cmp::min(max_point, selection.end);
11988                    } else {
11989                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11990                    }
11991                    selection.goal = SelectionGoal::None;
11992                }
11993                if is_first {
11994                    is_first = false;
11995                } else {
11996                    text += "\n";
11997                }
11998                let mut len = 0;
11999                for chunk in buffer.text_for_range(selection.start..selection.end) {
12000                    text.push_str(chunk);
12001                    len += chunk.len();
12002                }
12003                clipboard_selections.push(ClipboardSelection {
12004                    len,
12005                    is_entire_line,
12006                    first_line_indent: buffer
12007                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12008                        .len,
12009                });
12010            }
12011        }
12012
12013        self.transact(window, cx, |this, window, cx| {
12014            this.change_selections(Default::default(), window, cx, |s| {
12015                s.select(selections);
12016            });
12017            this.insert("", window, cx);
12018        });
12019        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12020    }
12021
12022    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12024        let item = self.cut_common(window, cx);
12025        cx.write_to_clipboard(item);
12026    }
12027
12028    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12029        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12030        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12031            s.move_with(|snapshot, sel| {
12032                if sel.is_empty() {
12033                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12034                }
12035            });
12036        });
12037        let item = self.cut_common(window, cx);
12038        cx.set_global(KillRing(item))
12039    }
12040
12041    pub fn kill_ring_yank(
12042        &mut self,
12043        _: &KillRingYank,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12048        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12049            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12050                (kill_ring.text().to_string(), kill_ring.metadata_json())
12051            } else {
12052                return;
12053            }
12054        } else {
12055            return;
12056        };
12057        self.do_paste(&text, metadata, false, window, cx);
12058    }
12059
12060    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12061        self.do_copy(true, cx);
12062    }
12063
12064    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12065        self.do_copy(false, cx);
12066    }
12067
12068    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12069        let selections = self.selections.all::<Point>(cx);
12070        let buffer = self.buffer.read(cx).read(cx);
12071        let mut text = String::new();
12072
12073        let mut clipboard_selections = Vec::with_capacity(selections.len());
12074        {
12075            let max_point = buffer.max_point();
12076            let mut is_first = true;
12077            for selection in &selections {
12078                let mut start = selection.start;
12079                let mut end = selection.end;
12080                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12081                if is_entire_line {
12082                    start = Point::new(start.row, 0);
12083                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12084                }
12085
12086                let mut trimmed_selections = Vec::new();
12087                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12088                    let row = MultiBufferRow(start.row);
12089                    let first_indent = buffer.indent_size_for_line(row);
12090                    if first_indent.len == 0 || start.column > first_indent.len {
12091                        trimmed_selections.push(start..end);
12092                    } else {
12093                        trimmed_selections.push(
12094                            Point::new(row.0, first_indent.len)
12095                                ..Point::new(row.0, buffer.line_len(row)),
12096                        );
12097                        for row in start.row + 1..=end.row {
12098                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12099                            if row == end.row {
12100                                line_len = end.column;
12101                            }
12102                            if line_len == 0 {
12103                                trimmed_selections
12104                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12105                                continue;
12106                            }
12107                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12108                            if row_indent_size.len >= first_indent.len {
12109                                trimmed_selections.push(
12110                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12111                                );
12112                            } else {
12113                                trimmed_selections.clear();
12114                                trimmed_selections.push(start..end);
12115                                break;
12116                            }
12117                        }
12118                    }
12119                } else {
12120                    trimmed_selections.push(start..end);
12121                }
12122
12123                for trimmed_range in trimmed_selections {
12124                    if is_first {
12125                        is_first = false;
12126                    } else {
12127                        text += "\n";
12128                    }
12129                    let mut len = 0;
12130                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12131                        text.push_str(chunk);
12132                        len += chunk.len();
12133                    }
12134                    clipboard_selections.push(ClipboardSelection {
12135                        len,
12136                        is_entire_line,
12137                        first_line_indent: buffer
12138                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12139                            .len,
12140                    });
12141                }
12142            }
12143        }
12144
12145        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12146            text,
12147            clipboard_selections,
12148        ));
12149    }
12150
12151    pub fn do_paste(
12152        &mut self,
12153        text: &String,
12154        clipboard_selections: Option<Vec<ClipboardSelection>>,
12155        handle_entire_lines: bool,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        if self.read_only(cx) {
12160            return;
12161        }
12162
12163        let clipboard_text = Cow::Borrowed(text);
12164
12165        self.transact(window, cx, |this, window, cx| {
12166            let had_active_edit_prediction = this.has_active_edit_prediction();
12167
12168            if let Some(mut clipboard_selections) = clipboard_selections {
12169                let old_selections = this.selections.all::<usize>(cx);
12170                let all_selections_were_entire_line =
12171                    clipboard_selections.iter().all(|s| s.is_entire_line);
12172                let first_selection_indent_column =
12173                    clipboard_selections.first().map(|s| s.first_line_indent);
12174                if clipboard_selections.len() != old_selections.len() {
12175                    clipboard_selections.drain(..);
12176                }
12177                let cursor_offset = this.selections.last::<usize>(cx).head();
12178                let mut auto_indent_on_paste = true;
12179
12180                this.buffer.update(cx, |buffer, cx| {
12181                    let snapshot = buffer.read(cx);
12182                    auto_indent_on_paste = snapshot
12183                        .language_settings_at(cursor_offset, cx)
12184                        .auto_indent_on_paste;
12185
12186                    let mut start_offset = 0;
12187                    let mut edits = Vec::new();
12188                    let mut original_indent_columns = Vec::new();
12189                    for (ix, selection) in old_selections.iter().enumerate() {
12190                        let to_insert;
12191                        let entire_line;
12192                        let original_indent_column;
12193                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12194                            let end_offset = start_offset + clipboard_selection.len;
12195                            to_insert = &clipboard_text[start_offset..end_offset];
12196                            entire_line = clipboard_selection.is_entire_line;
12197                            start_offset = end_offset + 1;
12198                            original_indent_column = Some(clipboard_selection.first_line_indent);
12199                        } else {
12200                            to_insert = clipboard_text.as_str();
12201                            entire_line = all_selections_were_entire_line;
12202                            original_indent_column = first_selection_indent_column
12203                        }
12204
12205                        // If the corresponding selection was empty when this slice of the
12206                        // clipboard text was written, then the entire line containing the
12207                        // selection was copied. If this selection is also currently empty,
12208                        // then paste the line before the current line of the buffer.
12209                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12210                            let column = selection.start.to_point(&snapshot).column as usize;
12211                            let line_start = selection.start - column;
12212                            line_start..line_start
12213                        } else {
12214                            selection.range()
12215                        };
12216
12217                        edits.push((range, to_insert));
12218                        original_indent_columns.push(original_indent_column);
12219                    }
12220                    drop(snapshot);
12221
12222                    buffer.edit(
12223                        edits,
12224                        if auto_indent_on_paste {
12225                            Some(AutoindentMode::Block {
12226                                original_indent_columns,
12227                            })
12228                        } else {
12229                            None
12230                        },
12231                        cx,
12232                    );
12233                });
12234
12235                let selections = this.selections.all::<usize>(cx);
12236                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12237            } else {
12238                this.insert(&clipboard_text, window, cx);
12239            }
12240
12241            let trigger_in_words =
12242                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12243
12244            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12245        });
12246    }
12247
12248    pub fn diff_clipboard_with_selection(
12249        &mut self,
12250        _: &DiffClipboardWithSelection,
12251        window: &mut Window,
12252        cx: &mut Context<Self>,
12253    ) {
12254        let selections = self.selections.all::<usize>(cx);
12255
12256        if selections.is_empty() {
12257            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12258            return;
12259        };
12260
12261        let clipboard_text = match cx.read_from_clipboard() {
12262            Some(item) => match item.entries().first() {
12263                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12264                _ => None,
12265            },
12266            None => None,
12267        };
12268
12269        let Some(clipboard_text) = clipboard_text else {
12270            log::warn!("Clipboard doesn't contain text.");
12271            return;
12272        };
12273
12274        window.dispatch_action(
12275            Box::new(DiffClipboardWithSelectionData {
12276                clipboard_text,
12277                editor: cx.entity(),
12278            }),
12279            cx,
12280        );
12281    }
12282
12283    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12285        if let Some(item) = cx.read_from_clipboard() {
12286            let entries = item.entries();
12287
12288            match entries.first() {
12289                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12290                // of all the pasted entries.
12291                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12292                    .do_paste(
12293                        clipboard_string.text(),
12294                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12295                        true,
12296                        window,
12297                        cx,
12298                    ),
12299                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12300            }
12301        }
12302    }
12303
12304    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12305        if self.read_only(cx) {
12306            return;
12307        }
12308
12309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12310
12311        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12312            if let Some((selections, _)) =
12313                self.selection_history.transaction(transaction_id).cloned()
12314            {
12315                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12316                    s.select_anchors(selections.to_vec());
12317                });
12318            } else {
12319                log::error!(
12320                    "No entry in selection_history found for undo. \
12321                     This may correspond to a bug where undo does not update the selection. \
12322                     If this is occurring, please add details to \
12323                     https://github.com/zed-industries/zed/issues/22692"
12324                );
12325            }
12326            self.request_autoscroll(Autoscroll::fit(), cx);
12327            self.unmark_text(window, cx);
12328            self.refresh_edit_prediction(true, false, window, cx);
12329            cx.emit(EditorEvent::Edited { transaction_id });
12330            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12331        }
12332    }
12333
12334    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12335        if self.read_only(cx) {
12336            return;
12337        }
12338
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340
12341        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12342            if let Some((_, Some(selections))) =
12343                self.selection_history.transaction(transaction_id).cloned()
12344            {
12345                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12346                    s.select_anchors(selections.to_vec());
12347                });
12348            } else {
12349                log::error!(
12350                    "No entry in selection_history found for redo. \
12351                     This may correspond to a bug where undo does not update the selection. \
12352                     If this is occurring, please add details to \
12353                     https://github.com/zed-industries/zed/issues/22692"
12354                );
12355            }
12356            self.request_autoscroll(Autoscroll::fit(), cx);
12357            self.unmark_text(window, cx);
12358            self.refresh_edit_prediction(true, false, window, cx);
12359            cx.emit(EditorEvent::Edited { transaction_id });
12360        }
12361    }
12362
12363    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12364        self.buffer
12365            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12366    }
12367
12368    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12369        self.buffer
12370            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12371    }
12372
12373    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12375        self.change_selections(Default::default(), window, cx, |s| {
12376            s.move_with(|map, selection| {
12377                let cursor = if selection.is_empty() {
12378                    movement::left(map, selection.start)
12379                } else {
12380                    selection.start
12381                };
12382                selection.collapse_to(cursor, SelectionGoal::None);
12383            });
12384        })
12385    }
12386
12387    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12389        self.change_selections(Default::default(), window, cx, |s| {
12390            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12391        })
12392    }
12393
12394    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12396        self.change_selections(Default::default(), window, cx, |s| {
12397            s.move_with(|map, selection| {
12398                let cursor = if selection.is_empty() {
12399                    movement::right(map, selection.end)
12400                } else {
12401                    selection.end
12402                };
12403                selection.collapse_to(cursor, SelectionGoal::None)
12404            });
12405        })
12406    }
12407
12408    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12410        self.change_selections(Default::default(), window, cx, |s| {
12411            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12412        })
12413    }
12414
12415    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12416        if self.take_rename(true, window, cx).is_some() {
12417            return;
12418        }
12419
12420        if self.mode.is_single_line() {
12421            cx.propagate();
12422            return;
12423        }
12424
12425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12426
12427        let text_layout_details = &self.text_layout_details(window);
12428        let selection_count = self.selections.count();
12429        let first_selection = self.selections.first_anchor();
12430
12431        self.change_selections(Default::default(), window, cx, |s| {
12432            s.move_with(|map, selection| {
12433                if !selection.is_empty() {
12434                    selection.goal = SelectionGoal::None;
12435                }
12436                let (cursor, goal) = movement::up(
12437                    map,
12438                    selection.start,
12439                    selection.goal,
12440                    false,
12441                    text_layout_details,
12442                );
12443                selection.collapse_to(cursor, goal);
12444            });
12445        });
12446
12447        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12448        {
12449            cx.propagate();
12450        }
12451    }
12452
12453    pub fn move_up_by_lines(
12454        &mut self,
12455        action: &MoveUpByLines,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) {
12459        if self.take_rename(true, window, cx).is_some() {
12460            return;
12461        }
12462
12463        if self.mode.is_single_line() {
12464            cx.propagate();
12465            return;
12466        }
12467
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12469
12470        let text_layout_details = &self.text_layout_details(window);
12471
12472        self.change_selections(Default::default(), window, cx, |s| {
12473            s.move_with(|map, selection| {
12474                if !selection.is_empty() {
12475                    selection.goal = SelectionGoal::None;
12476                }
12477                let (cursor, goal) = movement::up_by_rows(
12478                    map,
12479                    selection.start,
12480                    action.lines,
12481                    selection.goal,
12482                    false,
12483                    text_layout_details,
12484                );
12485                selection.collapse_to(cursor, goal);
12486            });
12487        })
12488    }
12489
12490    pub fn move_down_by_lines(
12491        &mut self,
12492        action: &MoveDownByLines,
12493        window: &mut Window,
12494        cx: &mut Context<Self>,
12495    ) {
12496        if self.take_rename(true, window, cx).is_some() {
12497            return;
12498        }
12499
12500        if self.mode.is_single_line() {
12501            cx.propagate();
12502            return;
12503        }
12504
12505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12506
12507        let text_layout_details = &self.text_layout_details(window);
12508
12509        self.change_selections(Default::default(), window, cx, |s| {
12510            s.move_with(|map, selection| {
12511                if !selection.is_empty() {
12512                    selection.goal = SelectionGoal::None;
12513                }
12514                let (cursor, goal) = movement::down_by_rows(
12515                    map,
12516                    selection.start,
12517                    action.lines,
12518                    selection.goal,
12519                    false,
12520                    text_layout_details,
12521                );
12522                selection.collapse_to(cursor, goal);
12523            });
12524        })
12525    }
12526
12527    pub fn select_down_by_lines(
12528        &mut self,
12529        action: &SelectDownByLines,
12530        window: &mut Window,
12531        cx: &mut Context<Self>,
12532    ) {
12533        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12534        let text_layout_details = &self.text_layout_details(window);
12535        self.change_selections(Default::default(), window, cx, |s| {
12536            s.move_heads_with(|map, head, goal| {
12537                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12538            })
12539        })
12540    }
12541
12542    pub fn select_up_by_lines(
12543        &mut self,
12544        action: &SelectUpByLines,
12545        window: &mut Window,
12546        cx: &mut Context<Self>,
12547    ) {
12548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12549        let text_layout_details = &self.text_layout_details(window);
12550        self.change_selections(Default::default(), window, cx, |s| {
12551            s.move_heads_with(|map, head, goal| {
12552                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12553            })
12554        })
12555    }
12556
12557    pub fn select_page_up(
12558        &mut self,
12559        _: &SelectPageUp,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        let Some(row_count) = self.visible_row_count() else {
12564            return;
12565        };
12566
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12568
12569        let text_layout_details = &self.text_layout_details(window);
12570
12571        self.change_selections(Default::default(), window, cx, |s| {
12572            s.move_heads_with(|map, head, goal| {
12573                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12574            })
12575        })
12576    }
12577
12578    pub fn move_page_up(
12579        &mut self,
12580        action: &MovePageUp,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if self.take_rename(true, window, cx).is_some() {
12585            return;
12586        }
12587
12588        if self
12589            .context_menu
12590            .borrow_mut()
12591            .as_mut()
12592            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12593            .unwrap_or(false)
12594        {
12595            return;
12596        }
12597
12598        if matches!(self.mode, EditorMode::SingleLine) {
12599            cx.propagate();
12600            return;
12601        }
12602
12603        let Some(row_count) = self.visible_row_count() else {
12604            return;
12605        };
12606
12607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12608
12609        let effects = if action.center_cursor {
12610            SelectionEffects::scroll(Autoscroll::center())
12611        } else {
12612            SelectionEffects::default()
12613        };
12614
12615        let text_layout_details = &self.text_layout_details(window);
12616
12617        self.change_selections(effects, window, cx, |s| {
12618            s.move_with(|map, selection| {
12619                if !selection.is_empty() {
12620                    selection.goal = SelectionGoal::None;
12621                }
12622                let (cursor, goal) = movement::up_by_rows(
12623                    map,
12624                    selection.end,
12625                    row_count,
12626                    selection.goal,
12627                    false,
12628                    text_layout_details,
12629                );
12630                selection.collapse_to(cursor, goal);
12631            });
12632        });
12633    }
12634
12635    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12637        let text_layout_details = &self.text_layout_details(window);
12638        self.change_selections(Default::default(), window, cx, |s| {
12639            s.move_heads_with(|map, head, goal| {
12640                movement::up(map, head, goal, false, text_layout_details)
12641            })
12642        })
12643    }
12644
12645    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12646        self.take_rename(true, window, cx);
12647
12648        if self.mode.is_single_line() {
12649            cx.propagate();
12650            return;
12651        }
12652
12653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12654
12655        let text_layout_details = &self.text_layout_details(window);
12656        let selection_count = self.selections.count();
12657        let first_selection = self.selections.first_anchor();
12658
12659        self.change_selections(Default::default(), window, cx, |s| {
12660            s.move_with(|map, selection| {
12661                if !selection.is_empty() {
12662                    selection.goal = SelectionGoal::None;
12663                }
12664                let (cursor, goal) = movement::down(
12665                    map,
12666                    selection.end,
12667                    selection.goal,
12668                    false,
12669                    text_layout_details,
12670                );
12671                selection.collapse_to(cursor, goal);
12672            });
12673        });
12674
12675        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12676        {
12677            cx.propagate();
12678        }
12679    }
12680
12681    pub fn select_page_down(
12682        &mut self,
12683        _: &SelectPageDown,
12684        window: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        let Some(row_count) = self.visible_row_count() else {
12688            return;
12689        };
12690
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12692
12693        let text_layout_details = &self.text_layout_details(window);
12694
12695        self.change_selections(Default::default(), window, cx, |s| {
12696            s.move_heads_with(|map, head, goal| {
12697                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12698            })
12699        })
12700    }
12701
12702    pub fn move_page_down(
12703        &mut self,
12704        action: &MovePageDown,
12705        window: &mut Window,
12706        cx: &mut Context<Self>,
12707    ) {
12708        if self.take_rename(true, window, cx).is_some() {
12709            return;
12710        }
12711
12712        if self
12713            .context_menu
12714            .borrow_mut()
12715            .as_mut()
12716            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12717            .unwrap_or(false)
12718        {
12719            return;
12720        }
12721
12722        if matches!(self.mode, EditorMode::SingleLine) {
12723            cx.propagate();
12724            return;
12725        }
12726
12727        let Some(row_count) = self.visible_row_count() else {
12728            return;
12729        };
12730
12731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12732
12733        let effects = if action.center_cursor {
12734            SelectionEffects::scroll(Autoscroll::center())
12735        } else {
12736            SelectionEffects::default()
12737        };
12738
12739        let text_layout_details = &self.text_layout_details(window);
12740        self.change_selections(effects, window, cx, |s| {
12741            s.move_with(|map, selection| {
12742                if !selection.is_empty() {
12743                    selection.goal = SelectionGoal::None;
12744                }
12745                let (cursor, goal) = movement::down_by_rows(
12746                    map,
12747                    selection.end,
12748                    row_count,
12749                    selection.goal,
12750                    false,
12751                    text_layout_details,
12752                );
12753                selection.collapse_to(cursor, goal);
12754            });
12755        });
12756    }
12757
12758    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12760        let text_layout_details = &self.text_layout_details(window);
12761        self.change_selections(Default::default(), window, cx, |s| {
12762            s.move_heads_with(|map, head, goal| {
12763                movement::down(map, head, goal, false, text_layout_details)
12764            })
12765        });
12766    }
12767
12768    pub fn context_menu_first(
12769        &mut self,
12770        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
12776        }
12777    }
12778
12779    pub fn context_menu_prev(
12780        &mut self,
12781        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
12787        }
12788    }
12789
12790    pub fn context_menu_next(
12791        &mut self,
12792        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
12798        }
12799    }
12800
12801    pub fn context_menu_last(
12802        &mut self,
12803        _: &ContextMenuLast,
12804        window: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12808            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12809        }
12810    }
12811
12812    pub fn signature_help_prev(
12813        &mut self,
12814        _: &SignatureHelpPrevious,
12815        _: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        if let Some(popover) = self.signature_help_state.popover_mut() {
12819            if popover.current_signature == 0 {
12820                popover.current_signature = popover.signatures.len() - 1;
12821            } else {
12822                popover.current_signature -= 1;
12823            }
12824            cx.notify();
12825        }
12826    }
12827
12828    pub fn signature_help_next(
12829        &mut self,
12830        _: &SignatureHelpNext,
12831        _: &mut Window,
12832        cx: &mut Context<Self>,
12833    ) {
12834        if let Some(popover) = self.signature_help_state.popover_mut() {
12835            if popover.current_signature + 1 == popover.signatures.len() {
12836                popover.current_signature = 0;
12837            } else {
12838                popover.current_signature += 1;
12839            }
12840            cx.notify();
12841        }
12842    }
12843
12844    pub fn move_to_previous_word_start(
12845        &mut self,
12846        _: &MoveToPreviousWordStart,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12851        self.change_selections(Default::default(), window, cx, |s| {
12852            s.move_cursors_with(|map, head, _| {
12853                (
12854                    movement::previous_word_start(map, head),
12855                    SelectionGoal::None,
12856                )
12857            });
12858        })
12859    }
12860
12861    pub fn move_to_previous_subword_start(
12862        &mut self,
12863        _: &MoveToPreviousSubwordStart,
12864        window: &mut Window,
12865        cx: &mut Context<Self>,
12866    ) {
12867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12868        self.change_selections(Default::default(), window, cx, |s| {
12869            s.move_cursors_with(|map, head, _| {
12870                (
12871                    movement::previous_subword_start(map, head),
12872                    SelectionGoal::None,
12873                )
12874            });
12875        })
12876    }
12877
12878    pub fn select_to_previous_word_start(
12879        &mut self,
12880        _: &SelectToPreviousWordStart,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12885        self.change_selections(Default::default(), window, cx, |s| {
12886            s.move_heads_with(|map, head, _| {
12887                (
12888                    movement::previous_word_start(map, head),
12889                    SelectionGoal::None,
12890                )
12891            });
12892        })
12893    }
12894
12895    pub fn select_to_previous_subword_start(
12896        &mut self,
12897        _: &SelectToPreviousSubwordStart,
12898        window: &mut Window,
12899        cx: &mut Context<Self>,
12900    ) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, _| {
12904                (
12905                    movement::previous_subword_start(map, head),
12906                    SelectionGoal::None,
12907                )
12908            });
12909        })
12910    }
12911
12912    pub fn delete_to_previous_word_start(
12913        &mut self,
12914        action: &DeleteToPreviousWordStart,
12915        window: &mut Window,
12916        cx: &mut Context<Self>,
12917    ) {
12918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12919        self.transact(window, cx, |this, window, cx| {
12920            this.select_autoclose_pair(window, cx);
12921            this.change_selections(Default::default(), window, cx, |s| {
12922                s.move_with(|map, selection| {
12923                    if selection.is_empty() {
12924                        let cursor = if action.ignore_newlines {
12925                            movement::previous_word_start(map, selection.head())
12926                        } else {
12927                            movement::previous_word_start_or_newline(map, selection.head())
12928                        };
12929                        selection.set_head(cursor, SelectionGoal::None);
12930                    }
12931                });
12932            });
12933            this.insert("", window, cx);
12934        });
12935    }
12936
12937    pub fn delete_to_previous_subword_start(
12938        &mut self,
12939        _: &DeleteToPreviousSubwordStart,
12940        window: &mut Window,
12941        cx: &mut Context<Self>,
12942    ) {
12943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12944        self.transact(window, cx, |this, window, cx| {
12945            this.select_autoclose_pair(window, cx);
12946            this.change_selections(Default::default(), window, cx, |s| {
12947                s.move_with(|map, selection| {
12948                    if selection.is_empty() {
12949                        let cursor = movement::previous_subword_start(map, selection.head());
12950                        selection.set_head(cursor, SelectionGoal::None);
12951                    }
12952                });
12953            });
12954            this.insert("", window, cx);
12955        });
12956    }
12957
12958    pub fn move_to_next_word_end(
12959        &mut self,
12960        _: &MoveToNextWordEnd,
12961        window: &mut Window,
12962        cx: &mut Context<Self>,
12963    ) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12965        self.change_selections(Default::default(), window, cx, |s| {
12966            s.move_cursors_with(|map, head, _| {
12967                (movement::next_word_end(map, head), SelectionGoal::None)
12968            });
12969        })
12970    }
12971
12972    pub fn move_to_next_subword_end(
12973        &mut self,
12974        _: &MoveToNextSubwordEnd,
12975        window: &mut Window,
12976        cx: &mut Context<Self>,
12977    ) {
12978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12979        self.change_selections(Default::default(), window, cx, |s| {
12980            s.move_cursors_with(|map, head, _| {
12981                (movement::next_subword_end(map, head), SelectionGoal::None)
12982            });
12983        })
12984    }
12985
12986    pub fn select_to_next_word_end(
12987        &mut self,
12988        _: &SelectToNextWordEnd,
12989        window: &mut Window,
12990        cx: &mut Context<Self>,
12991    ) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12993        self.change_selections(Default::default(), window, cx, |s| {
12994            s.move_heads_with(|map, head, _| {
12995                (movement::next_word_end(map, head), SelectionGoal::None)
12996            });
12997        })
12998    }
12999
13000    pub fn select_to_next_subword_end(
13001        &mut self,
13002        _: &SelectToNextSubwordEnd,
13003        window: &mut Window,
13004        cx: &mut Context<Self>,
13005    ) {
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_heads_with(|map, head, _| {
13009                (movement::next_subword_end(map, head), SelectionGoal::None)
13010            });
13011        })
13012    }
13013
13014    pub fn delete_to_next_word_end(
13015        &mut self,
13016        action: &DeleteToNextWordEnd,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13021        self.transact(window, cx, |this, window, cx| {
13022            this.change_selections(Default::default(), window, cx, |s| {
13023                s.move_with(|map, selection| {
13024                    if selection.is_empty() {
13025                        let cursor = if action.ignore_newlines {
13026                            movement::next_word_end(map, selection.head())
13027                        } else {
13028                            movement::next_word_end_or_newline(map, selection.head())
13029                        };
13030                        selection.set_head(cursor, SelectionGoal::None);
13031                    }
13032                });
13033            });
13034            this.insert("", window, cx);
13035        });
13036    }
13037
13038    pub fn delete_to_next_subword_end(
13039        &mut self,
13040        _: &DeleteToNextSubwordEnd,
13041        window: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13045        self.transact(window, cx, |this, window, cx| {
13046            this.change_selections(Default::default(), window, cx, |s| {
13047                s.move_with(|map, selection| {
13048                    if selection.is_empty() {
13049                        let cursor = movement::next_subword_end(map, selection.head());
13050                        selection.set_head(cursor, SelectionGoal::None);
13051                    }
13052                });
13053            });
13054            this.insert("", window, cx);
13055        });
13056    }
13057
13058    pub fn move_to_beginning_of_line(
13059        &mut self,
13060        action: &MoveToBeginningOfLine,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13065        self.change_selections(Default::default(), window, cx, |s| {
13066            s.move_cursors_with(|map, head, _| {
13067                (
13068                    movement::indented_line_beginning(
13069                        map,
13070                        head,
13071                        action.stop_at_soft_wraps,
13072                        action.stop_at_indent,
13073                    ),
13074                    SelectionGoal::None,
13075                )
13076            });
13077        })
13078    }
13079
13080    pub fn select_to_beginning_of_line(
13081        &mut self,
13082        action: &SelectToBeginningOfLine,
13083        window: &mut Window,
13084        cx: &mut Context<Self>,
13085    ) {
13086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13087        self.change_selections(Default::default(), window, cx, |s| {
13088            s.move_heads_with(|map, head, _| {
13089                (
13090                    movement::indented_line_beginning(
13091                        map,
13092                        head,
13093                        action.stop_at_soft_wraps,
13094                        action.stop_at_indent,
13095                    ),
13096                    SelectionGoal::None,
13097                )
13098            });
13099        });
13100    }
13101
13102    pub fn delete_to_beginning_of_line(
13103        &mut self,
13104        action: &DeleteToBeginningOfLine,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13109        self.transact(window, cx, |this, window, cx| {
13110            this.change_selections(Default::default(), window, cx, |s| {
13111                s.move_with(|_, selection| {
13112                    selection.reversed = true;
13113                });
13114            });
13115
13116            this.select_to_beginning_of_line(
13117                &SelectToBeginningOfLine {
13118                    stop_at_soft_wraps: false,
13119                    stop_at_indent: action.stop_at_indent,
13120                },
13121                window,
13122                cx,
13123            );
13124            this.backspace(&Backspace, window, cx);
13125        });
13126    }
13127
13128    pub fn move_to_end_of_line(
13129        &mut self,
13130        action: &MoveToEndOfLine,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13135        self.change_selections(Default::default(), window, cx, |s| {
13136            s.move_cursors_with(|map, head, _| {
13137                (
13138                    movement::line_end(map, head, action.stop_at_soft_wraps),
13139                    SelectionGoal::None,
13140                )
13141            });
13142        })
13143    }
13144
13145    pub fn select_to_end_of_line(
13146        &mut self,
13147        action: &SelectToEndOfLine,
13148        window: &mut Window,
13149        cx: &mut Context<Self>,
13150    ) {
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13152        self.change_selections(Default::default(), window, cx, |s| {
13153            s.move_heads_with(|map, head, _| {
13154                (
13155                    movement::line_end(map, head, action.stop_at_soft_wraps),
13156                    SelectionGoal::None,
13157                )
13158            });
13159        })
13160    }
13161
13162    pub fn delete_to_end_of_line(
13163        &mut self,
13164        _: &DeleteToEndOfLine,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13169        self.transact(window, cx, |this, window, cx| {
13170            this.select_to_end_of_line(
13171                &SelectToEndOfLine {
13172                    stop_at_soft_wraps: false,
13173                },
13174                window,
13175                cx,
13176            );
13177            this.delete(&Delete, window, cx);
13178        });
13179    }
13180
13181    pub fn cut_to_end_of_line(
13182        &mut self,
13183        _: &CutToEndOfLine,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13188        self.transact(window, cx, |this, window, cx| {
13189            this.select_to_end_of_line(
13190                &SelectToEndOfLine {
13191                    stop_at_soft_wraps: false,
13192                },
13193                window,
13194                cx,
13195            );
13196            this.cut(&Cut, window, cx);
13197        });
13198    }
13199
13200    pub fn move_to_start_of_paragraph(
13201        &mut self,
13202        _: &MoveToStartOfParagraph,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        if matches!(self.mode, EditorMode::SingleLine) {
13207            cx.propagate();
13208            return;
13209        }
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13211        self.change_selections(Default::default(), window, cx, |s| {
13212            s.move_with(|map, selection| {
13213                selection.collapse_to(
13214                    movement::start_of_paragraph(map, selection.head(), 1),
13215                    SelectionGoal::None,
13216                )
13217            });
13218        })
13219    }
13220
13221    pub fn move_to_end_of_paragraph(
13222        &mut self,
13223        _: &MoveToEndOfParagraph,
13224        window: &mut Window,
13225        cx: &mut Context<Self>,
13226    ) {
13227        if matches!(self.mode, EditorMode::SingleLine) {
13228            cx.propagate();
13229            return;
13230        }
13231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13232        self.change_selections(Default::default(), window, cx, |s| {
13233            s.move_with(|map, selection| {
13234                selection.collapse_to(
13235                    movement::end_of_paragraph(map, selection.head(), 1),
13236                    SelectionGoal::None,
13237                )
13238            });
13239        })
13240    }
13241
13242    pub fn select_to_start_of_paragraph(
13243        &mut self,
13244        _: &SelectToStartOfParagraph,
13245        window: &mut Window,
13246        cx: &mut Context<Self>,
13247    ) {
13248        if matches!(self.mode, EditorMode::SingleLine) {
13249            cx.propagate();
13250            return;
13251        }
13252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13253        self.change_selections(Default::default(), window, cx, |s| {
13254            s.move_heads_with(|map, head, _| {
13255                (
13256                    movement::start_of_paragraph(map, head, 1),
13257                    SelectionGoal::None,
13258                )
13259            });
13260        })
13261    }
13262
13263    pub fn select_to_end_of_paragraph(
13264        &mut self,
13265        _: &SelectToEndOfParagraph,
13266        window: &mut Window,
13267        cx: &mut Context<Self>,
13268    ) {
13269        if matches!(self.mode, EditorMode::SingleLine) {
13270            cx.propagate();
13271            return;
13272        }
13273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13274        self.change_selections(Default::default(), window, cx, |s| {
13275            s.move_heads_with(|map, head, _| {
13276                (
13277                    movement::end_of_paragraph(map, head, 1),
13278                    SelectionGoal::None,
13279                )
13280            });
13281        })
13282    }
13283
13284    pub fn move_to_start_of_excerpt(
13285        &mut self,
13286        _: &MoveToStartOfExcerpt,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        if matches!(self.mode, EditorMode::SingleLine) {
13291            cx.propagate();
13292            return;
13293        }
13294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13295        self.change_selections(Default::default(), window, cx, |s| {
13296            s.move_with(|map, selection| {
13297                selection.collapse_to(
13298                    movement::start_of_excerpt(
13299                        map,
13300                        selection.head(),
13301                        workspace::searchable::Direction::Prev,
13302                    ),
13303                    SelectionGoal::None,
13304                )
13305            });
13306        })
13307    }
13308
13309    pub fn move_to_start_of_next_excerpt(
13310        &mut self,
13311        _: &MoveToStartOfNextExcerpt,
13312        window: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        if matches!(self.mode, EditorMode::SingleLine) {
13316            cx.propagate();
13317            return;
13318        }
13319
13320        self.change_selections(Default::default(), window, cx, |s| {
13321            s.move_with(|map, selection| {
13322                selection.collapse_to(
13323                    movement::start_of_excerpt(
13324                        map,
13325                        selection.head(),
13326                        workspace::searchable::Direction::Next,
13327                    ),
13328                    SelectionGoal::None,
13329                )
13330            });
13331        })
13332    }
13333
13334    pub fn move_to_end_of_excerpt(
13335        &mut self,
13336        _: &MoveToEndOfExcerpt,
13337        window: &mut Window,
13338        cx: &mut Context<Self>,
13339    ) {
13340        if matches!(self.mode, EditorMode::SingleLine) {
13341            cx.propagate();
13342            return;
13343        }
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345        self.change_selections(Default::default(), window, cx, |s| {
13346            s.move_with(|map, selection| {
13347                selection.collapse_to(
13348                    movement::end_of_excerpt(
13349                        map,
13350                        selection.head(),
13351                        workspace::searchable::Direction::Next,
13352                    ),
13353                    SelectionGoal::None,
13354                )
13355            });
13356        })
13357    }
13358
13359    pub fn move_to_end_of_previous_excerpt(
13360        &mut self,
13361        _: &MoveToEndOfPreviousExcerpt,
13362        window: &mut Window,
13363        cx: &mut Context<Self>,
13364    ) {
13365        if matches!(self.mode, EditorMode::SingleLine) {
13366            cx.propagate();
13367            return;
13368        }
13369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13370        self.change_selections(Default::default(), window, cx, |s| {
13371            s.move_with(|map, selection| {
13372                selection.collapse_to(
13373                    movement::end_of_excerpt(
13374                        map,
13375                        selection.head(),
13376                        workspace::searchable::Direction::Prev,
13377                    ),
13378                    SelectionGoal::None,
13379                )
13380            });
13381        })
13382    }
13383
13384    pub fn select_to_start_of_excerpt(
13385        &mut self,
13386        _: &SelectToStartOfExcerpt,
13387        window: &mut Window,
13388        cx: &mut Context<Self>,
13389    ) {
13390        if matches!(self.mode, EditorMode::SingleLine) {
13391            cx.propagate();
13392            return;
13393        }
13394        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13395        self.change_selections(Default::default(), window, cx, |s| {
13396            s.move_heads_with(|map, head, _| {
13397                (
13398                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13399                    SelectionGoal::None,
13400                )
13401            });
13402        })
13403    }
13404
13405    pub fn select_to_start_of_next_excerpt(
13406        &mut self,
13407        _: &SelectToStartOfNextExcerpt,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) {
13411        if matches!(self.mode, EditorMode::SingleLine) {
13412            cx.propagate();
13413            return;
13414        }
13415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13416        self.change_selections(Default::default(), window, cx, |s| {
13417            s.move_heads_with(|map, head, _| {
13418                (
13419                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13420                    SelectionGoal::None,
13421                )
13422            });
13423        })
13424    }
13425
13426    pub fn select_to_end_of_excerpt(
13427        &mut self,
13428        _: &SelectToEndOfExcerpt,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        if matches!(self.mode, EditorMode::SingleLine) {
13433            cx.propagate();
13434            return;
13435        }
13436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13437        self.change_selections(Default::default(), window, cx, |s| {
13438            s.move_heads_with(|map, head, _| {
13439                (
13440                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13441                    SelectionGoal::None,
13442                )
13443            });
13444        })
13445    }
13446
13447    pub fn select_to_end_of_previous_excerpt(
13448        &mut self,
13449        _: &SelectToEndOfPreviousExcerpt,
13450        window: &mut Window,
13451        cx: &mut Context<Self>,
13452    ) {
13453        if matches!(self.mode, EditorMode::SingleLine) {
13454            cx.propagate();
13455            return;
13456        }
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_heads_with(|map, head, _| {
13460                (
13461                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13462                    SelectionGoal::None,
13463                )
13464            });
13465        })
13466    }
13467
13468    pub fn move_to_beginning(
13469        &mut self,
13470        _: &MoveToBeginning,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        if matches!(self.mode, EditorMode::SingleLine) {
13475            cx.propagate();
13476            return;
13477        }
13478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13479        self.change_selections(Default::default(), window, cx, |s| {
13480            s.select_ranges(vec![0..0]);
13481        });
13482    }
13483
13484    pub fn select_to_beginning(
13485        &mut self,
13486        _: &SelectToBeginning,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        let mut selection = self.selections.last::<Point>(cx);
13491        selection.set_head(Point::zero(), SelectionGoal::None);
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.select(vec![selection]);
13495        });
13496    }
13497
13498    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13499        if matches!(self.mode, EditorMode::SingleLine) {
13500            cx.propagate();
13501            return;
13502        }
13503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13504        let cursor = self.buffer.read(cx).read(cx).len();
13505        self.change_selections(Default::default(), window, cx, |s| {
13506            s.select_ranges(vec![cursor..cursor])
13507        });
13508    }
13509
13510    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13511        self.nav_history = nav_history;
13512    }
13513
13514    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13515        self.nav_history.as_ref()
13516    }
13517
13518    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13519        self.push_to_nav_history(
13520            self.selections.newest_anchor().head(),
13521            None,
13522            false,
13523            true,
13524            cx,
13525        );
13526    }
13527
13528    fn push_to_nav_history(
13529        &mut self,
13530        cursor_anchor: Anchor,
13531        new_position: Option<Point>,
13532        is_deactivate: bool,
13533        always: bool,
13534        cx: &mut Context<Self>,
13535    ) {
13536        if let Some(nav_history) = self.nav_history.as_mut() {
13537            let buffer = self.buffer.read(cx).read(cx);
13538            let cursor_position = cursor_anchor.to_point(&buffer);
13539            let scroll_state = self.scroll_manager.anchor();
13540            let scroll_top_row = scroll_state.top_row(&buffer);
13541            drop(buffer);
13542
13543            if let Some(new_position) = new_position {
13544                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13545                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13546                    return;
13547                }
13548            }
13549
13550            nav_history.push(
13551                Some(NavigationData {
13552                    cursor_anchor,
13553                    cursor_position,
13554                    scroll_anchor: scroll_state,
13555                    scroll_top_row,
13556                }),
13557                cx,
13558            );
13559            cx.emit(EditorEvent::PushedToNavHistory {
13560                anchor: cursor_anchor,
13561                is_deactivate,
13562            })
13563        }
13564    }
13565
13566    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13568        let buffer = self.buffer.read(cx).snapshot(cx);
13569        let mut selection = self.selections.first::<usize>(cx);
13570        selection.set_head(buffer.len(), SelectionGoal::None);
13571        self.change_selections(Default::default(), window, cx, |s| {
13572            s.select(vec![selection]);
13573        });
13574    }
13575
13576    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13578        let end = self.buffer.read(cx).read(cx).len();
13579        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13580            s.select_ranges(vec![0..end]);
13581        });
13582    }
13583
13584    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13587        let mut selections = self.selections.all::<Point>(cx);
13588        let max_point = display_map.buffer_snapshot.max_point();
13589        for selection in &mut selections {
13590            let rows = selection.spanned_rows(true, &display_map);
13591            selection.start = Point::new(rows.start.0, 0);
13592            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13593            selection.reversed = false;
13594        }
13595        self.change_selections(Default::default(), window, cx, |s| {
13596            s.select(selections);
13597        });
13598    }
13599
13600    pub fn split_selection_into_lines(
13601        &mut self,
13602        action: &SplitSelectionIntoLines,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        let selections = self
13607            .selections
13608            .all::<Point>(cx)
13609            .into_iter()
13610            .map(|selection| selection.start..selection.end)
13611            .collect::<Vec<_>>();
13612        self.unfold_ranges(&selections, true, true, cx);
13613
13614        let mut new_selection_ranges = Vec::new();
13615        {
13616            let buffer = self.buffer.read(cx).read(cx);
13617            for selection in selections {
13618                for row in selection.start.row..selection.end.row {
13619                    let line_start = Point::new(row, 0);
13620                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13621
13622                    if action.keep_selections {
13623                        // Keep the selection range for each line
13624                        let selection_start = if row == selection.start.row {
13625                            selection.start
13626                        } else {
13627                            line_start
13628                        };
13629                        new_selection_ranges.push(selection_start..line_end);
13630                    } else {
13631                        // Collapse to cursor at end of line
13632                        new_selection_ranges.push(line_end..line_end);
13633                    }
13634                }
13635
13636                let is_multiline_selection = selection.start.row != selection.end.row;
13637                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13638                // so this action feels more ergonomic when paired with other selection operations
13639                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13640                if !should_skip_last {
13641                    if action.keep_selections {
13642                        if is_multiline_selection {
13643                            let line_start = Point::new(selection.end.row, 0);
13644                            new_selection_ranges.push(line_start..selection.end);
13645                        } else {
13646                            new_selection_ranges.push(selection.start..selection.end);
13647                        }
13648                    } else {
13649                        new_selection_ranges.push(selection.end..selection.end);
13650                    }
13651                }
13652            }
13653        }
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.select_ranges(new_selection_ranges);
13656        });
13657    }
13658
13659    pub fn add_selection_above(
13660        &mut self,
13661        _: &AddSelectionAbove,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.add_selection(true, window, cx);
13666    }
13667
13668    pub fn add_selection_below(
13669        &mut self,
13670        _: &AddSelectionBelow,
13671        window: &mut Window,
13672        cx: &mut Context<Self>,
13673    ) {
13674        self.add_selection(false, window, cx);
13675    }
13676
13677    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13679
13680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13681        let all_selections = self.selections.all::<Point>(cx);
13682        let text_layout_details = self.text_layout_details(window);
13683
13684        let (mut columnar_selections, new_selections_to_columnarize) = {
13685            if let Some(state) = self.add_selections_state.as_ref() {
13686                let columnar_selection_ids: HashSet<_> = state
13687                    .groups
13688                    .iter()
13689                    .flat_map(|group| group.stack.iter())
13690                    .copied()
13691                    .collect();
13692
13693                all_selections
13694                    .into_iter()
13695                    .partition(|s| columnar_selection_ids.contains(&s.id))
13696            } else {
13697                (Vec::new(), all_selections)
13698            }
13699        };
13700
13701        let mut state = self
13702            .add_selections_state
13703            .take()
13704            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13705
13706        for selection in new_selections_to_columnarize {
13707            let range = selection.display_range(&display_map).sorted();
13708            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13709            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13710            let positions = start_x.min(end_x)..start_x.max(end_x);
13711            let mut stack = Vec::new();
13712            for row in range.start.row().0..=range.end.row().0 {
13713                if let Some(selection) = self.selections.build_columnar_selection(
13714                    &display_map,
13715                    DisplayRow(row),
13716                    &positions,
13717                    selection.reversed,
13718                    &text_layout_details,
13719                ) {
13720                    stack.push(selection.id);
13721                    columnar_selections.push(selection);
13722                }
13723            }
13724            if !stack.is_empty() {
13725                if above {
13726                    stack.reverse();
13727                }
13728                state.groups.push(AddSelectionsGroup { above, stack });
13729            }
13730        }
13731
13732        let mut final_selections = Vec::new();
13733        let end_row = if above {
13734            DisplayRow(0)
13735        } else {
13736            display_map.max_point().row()
13737        };
13738
13739        let mut last_added_item_per_group = HashMap::default();
13740        for group in state.groups.iter_mut() {
13741            if let Some(last_id) = group.stack.last() {
13742                last_added_item_per_group.insert(*last_id, group);
13743            }
13744        }
13745
13746        for selection in columnar_selections {
13747            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13748                if above == group.above {
13749                    let range = selection.display_range(&display_map).sorted();
13750                    debug_assert_eq!(range.start.row(), range.end.row());
13751                    let mut row = range.start.row();
13752                    let positions =
13753                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13754                            px(start)..px(end)
13755                        } else {
13756                            let start_x =
13757                                display_map.x_for_display_point(range.start, &text_layout_details);
13758                            let end_x =
13759                                display_map.x_for_display_point(range.end, &text_layout_details);
13760                            start_x.min(end_x)..start_x.max(end_x)
13761                        };
13762
13763                    let mut maybe_new_selection = None;
13764                    while row != end_row {
13765                        if above {
13766                            row.0 -= 1;
13767                        } else {
13768                            row.0 += 1;
13769                        }
13770                        if let Some(new_selection) = self.selections.build_columnar_selection(
13771                            &display_map,
13772                            row,
13773                            &positions,
13774                            selection.reversed,
13775                            &text_layout_details,
13776                        ) {
13777                            maybe_new_selection = Some(new_selection);
13778                            break;
13779                        }
13780                    }
13781
13782                    if let Some(new_selection) = maybe_new_selection {
13783                        group.stack.push(new_selection.id);
13784                        if above {
13785                            final_selections.push(new_selection);
13786                            final_selections.push(selection);
13787                        } else {
13788                            final_selections.push(selection);
13789                            final_selections.push(new_selection);
13790                        }
13791                    } else {
13792                        final_selections.push(selection);
13793                    }
13794                } else {
13795                    group.stack.pop();
13796                }
13797            } else {
13798                final_selections.push(selection);
13799            }
13800        }
13801
13802        self.change_selections(Default::default(), window, cx, |s| {
13803            s.select(final_selections);
13804        });
13805
13806        let final_selection_ids: HashSet<_> = self
13807            .selections
13808            .all::<Point>(cx)
13809            .iter()
13810            .map(|s| s.id)
13811            .collect();
13812        state.groups.retain_mut(|group| {
13813            // selections might get merged above so we remove invalid items from stacks
13814            group.stack.retain(|id| final_selection_ids.contains(id));
13815
13816            // single selection in stack can be treated as initial state
13817            group.stack.len() > 1
13818        });
13819
13820        if !state.groups.is_empty() {
13821            self.add_selections_state = Some(state);
13822        }
13823    }
13824
13825    fn select_match_ranges(
13826        &mut self,
13827        range: Range<usize>,
13828        reversed: bool,
13829        replace_newest: bool,
13830        auto_scroll: Option<Autoscroll>,
13831        window: &mut Window,
13832        cx: &mut Context<Editor>,
13833    ) {
13834        self.unfold_ranges(
13835            std::slice::from_ref(&range),
13836            false,
13837            auto_scroll.is_some(),
13838            cx,
13839        );
13840        let effects = if let Some(scroll) = auto_scroll {
13841            SelectionEffects::scroll(scroll)
13842        } else {
13843            SelectionEffects::no_scroll()
13844        };
13845        self.change_selections(effects, window, cx, |s| {
13846            if replace_newest {
13847                s.delete(s.newest_anchor().id);
13848            }
13849            if reversed {
13850                s.insert_range(range.end..range.start);
13851            } else {
13852                s.insert_range(range);
13853            }
13854        });
13855    }
13856
13857    pub fn select_next_match_internal(
13858        &mut self,
13859        display_map: &DisplaySnapshot,
13860        replace_newest: bool,
13861        autoscroll: Option<Autoscroll>,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) -> Result<()> {
13865        let buffer = &display_map.buffer_snapshot;
13866        let mut selections = self.selections.all::<usize>(cx);
13867        if let Some(mut select_next_state) = self.select_next_state.take() {
13868            let query = &select_next_state.query;
13869            if !select_next_state.done {
13870                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13871                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13872                let mut next_selected_range = None;
13873
13874                let bytes_after_last_selection =
13875                    buffer.bytes_in_range(last_selection.end..buffer.len());
13876                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13877                let query_matches = query
13878                    .stream_find_iter(bytes_after_last_selection)
13879                    .map(|result| (last_selection.end, result))
13880                    .chain(
13881                        query
13882                            .stream_find_iter(bytes_before_first_selection)
13883                            .map(|result| (0, result)),
13884                    );
13885
13886                for (start_offset, query_match) in query_matches {
13887                    let query_match = query_match.unwrap(); // can only fail due to I/O
13888                    let offset_range =
13889                        start_offset + query_match.start()..start_offset + query_match.end();
13890
13891                    if !select_next_state.wordwise
13892                        || (!buffer.is_inside_word(offset_range.start, false)
13893                            && !buffer.is_inside_word(offset_range.end, false))
13894                    {
13895                        // TODO: This is n^2, because we might check all the selections
13896                        if !selections
13897                            .iter()
13898                            .any(|selection| selection.range().overlaps(&offset_range))
13899                        {
13900                            next_selected_range = Some(offset_range);
13901                            break;
13902                        }
13903                    }
13904                }
13905
13906                if let Some(next_selected_range) = next_selected_range {
13907                    self.select_match_ranges(
13908                        next_selected_range,
13909                        last_selection.reversed,
13910                        replace_newest,
13911                        autoscroll,
13912                        window,
13913                        cx,
13914                    );
13915                } else {
13916                    select_next_state.done = true;
13917                }
13918            }
13919
13920            self.select_next_state = Some(select_next_state);
13921        } else {
13922            let mut only_carets = true;
13923            let mut same_text_selected = true;
13924            let mut selected_text = None;
13925
13926            let mut selections_iter = selections.iter().peekable();
13927            while let Some(selection) = selections_iter.next() {
13928                if selection.start != selection.end {
13929                    only_carets = false;
13930                }
13931
13932                if same_text_selected {
13933                    if selected_text.is_none() {
13934                        selected_text =
13935                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13936                    }
13937
13938                    if let Some(next_selection) = selections_iter.peek() {
13939                        if next_selection.range().len() == selection.range().len() {
13940                            let next_selected_text = buffer
13941                                .text_for_range(next_selection.range())
13942                                .collect::<String>();
13943                            if Some(next_selected_text) != selected_text {
13944                                same_text_selected = false;
13945                                selected_text = None;
13946                            }
13947                        } else {
13948                            same_text_selected = false;
13949                            selected_text = None;
13950                        }
13951                    }
13952                }
13953            }
13954
13955            if only_carets {
13956                for selection in &mut selections {
13957                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13958                    selection.start = word_range.start;
13959                    selection.end = word_range.end;
13960                    selection.goal = SelectionGoal::None;
13961                    selection.reversed = false;
13962                    self.select_match_ranges(
13963                        selection.start..selection.end,
13964                        selection.reversed,
13965                        replace_newest,
13966                        autoscroll,
13967                        window,
13968                        cx,
13969                    );
13970                }
13971
13972                if selections.len() == 1 {
13973                    let selection = selections
13974                        .last()
13975                        .expect("ensured that there's only one selection");
13976                    let query = buffer
13977                        .text_for_range(selection.start..selection.end)
13978                        .collect::<String>();
13979                    let is_empty = query.is_empty();
13980                    let select_state = SelectNextState {
13981                        query: AhoCorasick::new(&[query])?,
13982                        wordwise: true,
13983                        done: is_empty,
13984                    };
13985                    self.select_next_state = Some(select_state);
13986                } else {
13987                    self.select_next_state = None;
13988                }
13989            } else if let Some(selected_text) = selected_text {
13990                self.select_next_state = Some(SelectNextState {
13991                    query: AhoCorasick::new(&[selected_text])?,
13992                    wordwise: false,
13993                    done: false,
13994                });
13995                self.select_next_match_internal(
13996                    display_map,
13997                    replace_newest,
13998                    autoscroll,
13999                    window,
14000                    cx,
14001                )?;
14002            }
14003        }
14004        Ok(())
14005    }
14006
14007    pub fn select_all_matches(
14008        &mut self,
14009        _action: &SelectAllMatches,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) -> Result<()> {
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014
14015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14016
14017        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14018        let Some(select_next_state) = self.select_next_state.as_mut() else {
14019            return Ok(());
14020        };
14021        if select_next_state.done {
14022            return Ok(());
14023        }
14024
14025        let mut new_selections = Vec::new();
14026
14027        let reversed = self.selections.oldest::<usize>(cx).reversed;
14028        let buffer = &display_map.buffer_snapshot;
14029        let query_matches = select_next_state
14030            .query
14031            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14032
14033        for query_match in query_matches.into_iter() {
14034            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14035            let offset_range = if reversed {
14036                query_match.end()..query_match.start()
14037            } else {
14038                query_match.start()..query_match.end()
14039            };
14040
14041            if !select_next_state.wordwise
14042                || (!buffer.is_inside_word(offset_range.start, false)
14043                    && !buffer.is_inside_word(offset_range.end, false))
14044            {
14045                new_selections.push(offset_range.start..offset_range.end);
14046            }
14047        }
14048
14049        select_next_state.done = true;
14050
14051        if new_selections.is_empty() {
14052            log::error!("bug: new_selections is empty in select_all_matches");
14053            return Ok(());
14054        }
14055
14056        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14057        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14058            selections.select_ranges(new_selections)
14059        });
14060
14061        Ok(())
14062    }
14063
14064    pub fn select_next(
14065        &mut self,
14066        action: &SelectNext,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) -> Result<()> {
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14072        self.select_next_match_internal(
14073            &display_map,
14074            action.replace_newest,
14075            Some(Autoscroll::newest()),
14076            window,
14077            cx,
14078        )?;
14079        Ok(())
14080    }
14081
14082    pub fn select_previous(
14083        &mut self,
14084        action: &SelectPrevious,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) -> Result<()> {
14088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14089        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14090        let buffer = &display_map.buffer_snapshot;
14091        let mut selections = self.selections.all::<usize>(cx);
14092        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14093            let query = &select_prev_state.query;
14094            if !select_prev_state.done {
14095                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14096                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14097                let mut next_selected_range = None;
14098                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14099                let bytes_before_last_selection =
14100                    buffer.reversed_bytes_in_range(0..last_selection.start);
14101                let bytes_after_first_selection =
14102                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14103                let query_matches = query
14104                    .stream_find_iter(bytes_before_last_selection)
14105                    .map(|result| (last_selection.start, result))
14106                    .chain(
14107                        query
14108                            .stream_find_iter(bytes_after_first_selection)
14109                            .map(|result| (buffer.len(), result)),
14110                    );
14111                for (end_offset, query_match) in query_matches {
14112                    let query_match = query_match.unwrap(); // can only fail due to I/O
14113                    let offset_range =
14114                        end_offset - query_match.end()..end_offset - query_match.start();
14115
14116                    if !select_prev_state.wordwise
14117                        || (!buffer.is_inside_word(offset_range.start, false)
14118                            && !buffer.is_inside_word(offset_range.end, false))
14119                    {
14120                        next_selected_range = Some(offset_range);
14121                        break;
14122                    }
14123                }
14124
14125                if let Some(next_selected_range) = next_selected_range {
14126                    self.select_match_ranges(
14127                        next_selected_range,
14128                        last_selection.reversed,
14129                        action.replace_newest,
14130                        Some(Autoscroll::newest()),
14131                        window,
14132                        cx,
14133                    );
14134                } else {
14135                    select_prev_state.done = true;
14136                }
14137            }
14138
14139            self.select_prev_state = Some(select_prev_state);
14140        } else {
14141            let mut only_carets = true;
14142            let mut same_text_selected = true;
14143            let mut selected_text = None;
14144
14145            let mut selections_iter = selections.iter().peekable();
14146            while let Some(selection) = selections_iter.next() {
14147                if selection.start != selection.end {
14148                    only_carets = false;
14149                }
14150
14151                if same_text_selected {
14152                    if selected_text.is_none() {
14153                        selected_text =
14154                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14155                    }
14156
14157                    if let Some(next_selection) = selections_iter.peek() {
14158                        if next_selection.range().len() == selection.range().len() {
14159                            let next_selected_text = buffer
14160                                .text_for_range(next_selection.range())
14161                                .collect::<String>();
14162                            if Some(next_selected_text) != selected_text {
14163                                same_text_selected = false;
14164                                selected_text = None;
14165                            }
14166                        } else {
14167                            same_text_selected = false;
14168                            selected_text = None;
14169                        }
14170                    }
14171                }
14172            }
14173
14174            if only_carets {
14175                for selection in &mut selections {
14176                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14177                    selection.start = word_range.start;
14178                    selection.end = word_range.end;
14179                    selection.goal = SelectionGoal::None;
14180                    selection.reversed = false;
14181                    self.select_match_ranges(
14182                        selection.start..selection.end,
14183                        selection.reversed,
14184                        action.replace_newest,
14185                        Some(Autoscroll::newest()),
14186                        window,
14187                        cx,
14188                    );
14189                }
14190                if selections.len() == 1 {
14191                    let selection = selections
14192                        .last()
14193                        .expect("ensured that there's only one selection");
14194                    let query = buffer
14195                        .text_for_range(selection.start..selection.end)
14196                        .collect::<String>();
14197                    let is_empty = query.is_empty();
14198                    let select_state = SelectNextState {
14199                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14200                        wordwise: true,
14201                        done: is_empty,
14202                    };
14203                    self.select_prev_state = Some(select_state);
14204                } else {
14205                    self.select_prev_state = None;
14206                }
14207            } else if let Some(selected_text) = selected_text {
14208                self.select_prev_state = Some(SelectNextState {
14209                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14210                    wordwise: false,
14211                    done: false,
14212                });
14213                self.select_previous(action, window, cx)?;
14214            }
14215        }
14216        Ok(())
14217    }
14218
14219    pub fn find_next_match(
14220        &mut self,
14221        _: &FindNextMatch,
14222        window: &mut Window,
14223        cx: &mut Context<Self>,
14224    ) -> Result<()> {
14225        let selections = self.selections.disjoint_anchors();
14226        match selections.first() {
14227            Some(first) if selections.len() >= 2 => {
14228                self.change_selections(Default::default(), window, cx, |s| {
14229                    s.select_ranges([first.range()]);
14230                });
14231            }
14232            _ => self.select_next(
14233                &SelectNext {
14234                    replace_newest: true,
14235                },
14236                window,
14237                cx,
14238            )?,
14239        }
14240        Ok(())
14241    }
14242
14243    pub fn find_previous_match(
14244        &mut self,
14245        _: &FindPreviousMatch,
14246        window: &mut Window,
14247        cx: &mut Context<Self>,
14248    ) -> Result<()> {
14249        let selections = self.selections.disjoint_anchors();
14250        match selections.last() {
14251            Some(last) if selections.len() >= 2 => {
14252                self.change_selections(Default::default(), window, cx, |s| {
14253                    s.select_ranges([last.range()]);
14254                });
14255            }
14256            _ => self.select_previous(
14257                &SelectPrevious {
14258                    replace_newest: true,
14259                },
14260                window,
14261                cx,
14262            )?,
14263        }
14264        Ok(())
14265    }
14266
14267    pub fn toggle_comments(
14268        &mut self,
14269        action: &ToggleComments,
14270        window: &mut Window,
14271        cx: &mut Context<Self>,
14272    ) {
14273        if self.read_only(cx) {
14274            return;
14275        }
14276        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14277        let text_layout_details = &self.text_layout_details(window);
14278        self.transact(window, cx, |this, window, cx| {
14279            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14280            let mut edits = Vec::new();
14281            let mut selection_edit_ranges = Vec::new();
14282            let mut last_toggled_row = None;
14283            let snapshot = this.buffer.read(cx).read(cx);
14284            let empty_str: Arc<str> = Arc::default();
14285            let mut suffixes_inserted = Vec::new();
14286            let ignore_indent = action.ignore_indent;
14287
14288            fn comment_prefix_range(
14289                snapshot: &MultiBufferSnapshot,
14290                row: MultiBufferRow,
14291                comment_prefix: &str,
14292                comment_prefix_whitespace: &str,
14293                ignore_indent: bool,
14294            ) -> Range<Point> {
14295                let indent_size = if ignore_indent {
14296                    0
14297                } else {
14298                    snapshot.indent_size_for_line(row).len
14299                };
14300
14301                let start = Point::new(row.0, indent_size);
14302
14303                let mut line_bytes = snapshot
14304                    .bytes_in_range(start..snapshot.max_point())
14305                    .flatten()
14306                    .copied();
14307
14308                // If this line currently begins with the line comment prefix, then record
14309                // the range containing the prefix.
14310                if line_bytes
14311                    .by_ref()
14312                    .take(comment_prefix.len())
14313                    .eq(comment_prefix.bytes())
14314                {
14315                    // Include any whitespace that matches the comment prefix.
14316                    let matching_whitespace_len = line_bytes
14317                        .zip(comment_prefix_whitespace.bytes())
14318                        .take_while(|(a, b)| a == b)
14319                        .count() as u32;
14320                    let end = Point::new(
14321                        start.row,
14322                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14323                    );
14324                    start..end
14325                } else {
14326                    start..start
14327                }
14328            }
14329
14330            fn comment_suffix_range(
14331                snapshot: &MultiBufferSnapshot,
14332                row: MultiBufferRow,
14333                comment_suffix: &str,
14334                comment_suffix_has_leading_space: bool,
14335            ) -> Range<Point> {
14336                let end = Point::new(row.0, snapshot.line_len(row));
14337                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14338
14339                let mut line_end_bytes = snapshot
14340                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14341                    .flatten()
14342                    .copied();
14343
14344                let leading_space_len = if suffix_start_column > 0
14345                    && line_end_bytes.next() == Some(b' ')
14346                    && comment_suffix_has_leading_space
14347                {
14348                    1
14349                } else {
14350                    0
14351                };
14352
14353                // If this line currently begins with the line comment prefix, then record
14354                // the range containing the prefix.
14355                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14356                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14357                    start..end
14358                } else {
14359                    end..end
14360                }
14361            }
14362
14363            // TODO: Handle selections that cross excerpts
14364            for selection in &mut selections {
14365                let start_column = snapshot
14366                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14367                    .len;
14368                let language = if let Some(language) =
14369                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14370                {
14371                    language
14372                } else {
14373                    continue;
14374                };
14375
14376                selection_edit_ranges.clear();
14377
14378                // If multiple selections contain a given row, avoid processing that
14379                // row more than once.
14380                let mut start_row = MultiBufferRow(selection.start.row);
14381                if last_toggled_row == Some(start_row) {
14382                    start_row = start_row.next_row();
14383                }
14384                let end_row =
14385                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14386                        MultiBufferRow(selection.end.row - 1)
14387                    } else {
14388                        MultiBufferRow(selection.end.row)
14389                    };
14390                last_toggled_row = Some(end_row);
14391
14392                if start_row > end_row {
14393                    continue;
14394                }
14395
14396                // If the language has line comments, toggle those.
14397                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14398
14399                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14400                if ignore_indent {
14401                    full_comment_prefixes = full_comment_prefixes
14402                        .into_iter()
14403                        .map(|s| Arc::from(s.trim_end()))
14404                        .collect();
14405                }
14406
14407                if !full_comment_prefixes.is_empty() {
14408                    let first_prefix = full_comment_prefixes
14409                        .first()
14410                        .expect("prefixes is non-empty");
14411                    let prefix_trimmed_lengths = full_comment_prefixes
14412                        .iter()
14413                        .map(|p| p.trim_end_matches(' ').len())
14414                        .collect::<SmallVec<[usize; 4]>>();
14415
14416                    let mut all_selection_lines_are_comments = true;
14417
14418                    for row in start_row.0..=end_row.0 {
14419                        let row = MultiBufferRow(row);
14420                        if start_row < end_row && snapshot.is_line_blank(row) {
14421                            continue;
14422                        }
14423
14424                        let prefix_range = full_comment_prefixes
14425                            .iter()
14426                            .zip(prefix_trimmed_lengths.iter().copied())
14427                            .map(|(prefix, trimmed_prefix_len)| {
14428                                comment_prefix_range(
14429                                    snapshot.deref(),
14430                                    row,
14431                                    &prefix[..trimmed_prefix_len],
14432                                    &prefix[trimmed_prefix_len..],
14433                                    ignore_indent,
14434                                )
14435                            })
14436                            .max_by_key(|range| range.end.column - range.start.column)
14437                            .expect("prefixes is non-empty");
14438
14439                        if prefix_range.is_empty() {
14440                            all_selection_lines_are_comments = false;
14441                        }
14442
14443                        selection_edit_ranges.push(prefix_range);
14444                    }
14445
14446                    if all_selection_lines_are_comments {
14447                        edits.extend(
14448                            selection_edit_ranges
14449                                .iter()
14450                                .cloned()
14451                                .map(|range| (range, empty_str.clone())),
14452                        );
14453                    } else {
14454                        let min_column = selection_edit_ranges
14455                            .iter()
14456                            .map(|range| range.start.column)
14457                            .min()
14458                            .unwrap_or(0);
14459                        edits.extend(selection_edit_ranges.iter().map(|range| {
14460                            let position = Point::new(range.start.row, min_column);
14461                            (position..position, first_prefix.clone())
14462                        }));
14463                    }
14464                } else if let Some(BlockCommentConfig {
14465                    start: full_comment_prefix,
14466                    end: comment_suffix,
14467                    ..
14468                }) = language.block_comment()
14469                {
14470                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14471                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14472                    let prefix_range = comment_prefix_range(
14473                        snapshot.deref(),
14474                        start_row,
14475                        comment_prefix,
14476                        comment_prefix_whitespace,
14477                        ignore_indent,
14478                    );
14479                    let suffix_range = comment_suffix_range(
14480                        snapshot.deref(),
14481                        end_row,
14482                        comment_suffix.trim_start_matches(' '),
14483                        comment_suffix.starts_with(' '),
14484                    );
14485
14486                    if prefix_range.is_empty() || suffix_range.is_empty() {
14487                        edits.push((
14488                            prefix_range.start..prefix_range.start,
14489                            full_comment_prefix.clone(),
14490                        ));
14491                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14492                        suffixes_inserted.push((end_row, comment_suffix.len()));
14493                    } else {
14494                        edits.push((prefix_range, empty_str.clone()));
14495                        edits.push((suffix_range, empty_str.clone()));
14496                    }
14497                } else {
14498                    continue;
14499                }
14500            }
14501
14502            drop(snapshot);
14503            this.buffer.update(cx, |buffer, cx| {
14504                buffer.edit(edits, None, cx);
14505            });
14506
14507            // Adjust selections so that they end before any comment suffixes that
14508            // were inserted.
14509            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14510            let mut selections = this.selections.all::<Point>(cx);
14511            let snapshot = this.buffer.read(cx).read(cx);
14512            for selection in &mut selections {
14513                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14514                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14515                        Ordering::Less => {
14516                            suffixes_inserted.next();
14517                            continue;
14518                        }
14519                        Ordering::Greater => break,
14520                        Ordering::Equal => {
14521                            if selection.end.column == snapshot.line_len(row) {
14522                                if selection.is_empty() {
14523                                    selection.start.column -= suffix_len as u32;
14524                                }
14525                                selection.end.column -= suffix_len as u32;
14526                            }
14527                            break;
14528                        }
14529                    }
14530                }
14531            }
14532
14533            drop(snapshot);
14534            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14535
14536            let selections = this.selections.all::<Point>(cx);
14537            let selections_on_single_row = selections.windows(2).all(|selections| {
14538                selections[0].start.row == selections[1].start.row
14539                    && selections[0].end.row == selections[1].end.row
14540                    && selections[0].start.row == selections[0].end.row
14541            });
14542            let selections_selecting = selections
14543                .iter()
14544                .any(|selection| selection.start != selection.end);
14545            let advance_downwards = action.advance_downwards
14546                && selections_on_single_row
14547                && !selections_selecting
14548                && !matches!(this.mode, EditorMode::SingleLine);
14549
14550            if advance_downwards {
14551                let snapshot = this.buffer.read(cx).snapshot(cx);
14552
14553                this.change_selections(Default::default(), window, cx, |s| {
14554                    s.move_cursors_with(|display_snapshot, display_point, _| {
14555                        let mut point = display_point.to_point(display_snapshot);
14556                        point.row += 1;
14557                        point = snapshot.clip_point(point, Bias::Left);
14558                        let display_point = point.to_display_point(display_snapshot);
14559                        let goal = SelectionGoal::HorizontalPosition(
14560                            display_snapshot
14561                                .x_for_display_point(display_point, text_layout_details)
14562                                .into(),
14563                        );
14564                        (display_point, goal)
14565                    })
14566                });
14567            }
14568        });
14569    }
14570
14571    pub fn select_enclosing_symbol(
14572        &mut self,
14573        _: &SelectEnclosingSymbol,
14574        window: &mut Window,
14575        cx: &mut Context<Self>,
14576    ) {
14577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14578
14579        let buffer = self.buffer.read(cx).snapshot(cx);
14580        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14581
14582        fn update_selection(
14583            selection: &Selection<usize>,
14584            buffer_snap: &MultiBufferSnapshot,
14585        ) -> Option<Selection<usize>> {
14586            let cursor = selection.head();
14587            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14588            for symbol in symbols.iter().rev() {
14589                let start = symbol.range.start.to_offset(buffer_snap);
14590                let end = symbol.range.end.to_offset(buffer_snap);
14591                let new_range = start..end;
14592                if start < selection.start || end > selection.end {
14593                    return Some(Selection {
14594                        id: selection.id,
14595                        start: new_range.start,
14596                        end: new_range.end,
14597                        goal: SelectionGoal::None,
14598                        reversed: selection.reversed,
14599                    });
14600                }
14601            }
14602            None
14603        }
14604
14605        let mut selected_larger_symbol = false;
14606        let new_selections = old_selections
14607            .iter()
14608            .map(|selection| match update_selection(selection, &buffer) {
14609                Some(new_selection) => {
14610                    if new_selection.range() != selection.range() {
14611                        selected_larger_symbol = true;
14612                    }
14613                    new_selection
14614                }
14615                None => selection.clone(),
14616            })
14617            .collect::<Vec<_>>();
14618
14619        if selected_larger_symbol {
14620            self.change_selections(Default::default(), window, cx, |s| {
14621                s.select(new_selections);
14622            });
14623        }
14624    }
14625
14626    pub fn select_larger_syntax_node(
14627        &mut self,
14628        _: &SelectLargerSyntaxNode,
14629        window: &mut Window,
14630        cx: &mut Context<Self>,
14631    ) {
14632        let Some(visible_row_count) = self.visible_row_count() else {
14633            return;
14634        };
14635        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14636        if old_selections.is_empty() {
14637            return;
14638        }
14639
14640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14641
14642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14643        let buffer = self.buffer.read(cx).snapshot(cx);
14644
14645        let mut selected_larger_node = false;
14646        let mut new_selections = old_selections
14647            .iter()
14648            .map(|selection| {
14649                let old_range = selection.start..selection.end;
14650
14651                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14652                    // manually select word at selection
14653                    if ["string_content", "inline"].contains(&node.kind()) {
14654                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14655                        // ignore if word is already selected
14656                        if !word_range.is_empty() && old_range != word_range {
14657                            let (last_word_range, _) =
14658                                buffer.surrounding_word(old_range.end, false);
14659                            // only select word if start and end point belongs to same word
14660                            if word_range == last_word_range {
14661                                selected_larger_node = true;
14662                                return Selection {
14663                                    id: selection.id,
14664                                    start: word_range.start,
14665                                    end: word_range.end,
14666                                    goal: SelectionGoal::None,
14667                                    reversed: selection.reversed,
14668                                };
14669                            }
14670                        }
14671                    }
14672                }
14673
14674                let mut new_range = old_range.clone();
14675                while let Some((_node, containing_range)) =
14676                    buffer.syntax_ancestor(new_range.clone())
14677                {
14678                    new_range = match containing_range {
14679                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14680                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14681                    };
14682                    if !display_map.intersects_fold(new_range.start)
14683                        && !display_map.intersects_fold(new_range.end)
14684                    {
14685                        break;
14686                    }
14687                }
14688
14689                selected_larger_node |= new_range != old_range;
14690                Selection {
14691                    id: selection.id,
14692                    start: new_range.start,
14693                    end: new_range.end,
14694                    goal: SelectionGoal::None,
14695                    reversed: selection.reversed,
14696                }
14697            })
14698            .collect::<Vec<_>>();
14699
14700        if !selected_larger_node {
14701            return; // don't put this call in the history
14702        }
14703
14704        // scroll based on transformation done to the last selection created by the user
14705        let (last_old, last_new) = old_selections
14706            .last()
14707            .zip(new_selections.last().cloned())
14708            .expect("old_selections isn't empty");
14709
14710        // revert selection
14711        let is_selection_reversed = {
14712            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14713            new_selections.last_mut().expect("checked above").reversed =
14714                should_newest_selection_be_reversed;
14715            should_newest_selection_be_reversed
14716        };
14717
14718        if selected_larger_node {
14719            self.select_syntax_node_history.disable_clearing = true;
14720            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14721                s.select(new_selections.clone());
14722            });
14723            self.select_syntax_node_history.disable_clearing = false;
14724        }
14725
14726        let start_row = last_new.start.to_display_point(&display_map).row().0;
14727        let end_row = last_new.end.to_display_point(&display_map).row().0;
14728        let selection_height = end_row - start_row + 1;
14729        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14730
14731        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14732        let scroll_behavior = if fits_on_the_screen {
14733            self.request_autoscroll(Autoscroll::fit(), cx);
14734            SelectSyntaxNodeScrollBehavior::FitSelection
14735        } else if is_selection_reversed {
14736            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14737            SelectSyntaxNodeScrollBehavior::CursorTop
14738        } else {
14739            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14740            SelectSyntaxNodeScrollBehavior::CursorBottom
14741        };
14742
14743        self.select_syntax_node_history.push((
14744            old_selections,
14745            scroll_behavior,
14746            is_selection_reversed,
14747        ));
14748    }
14749
14750    pub fn select_smaller_syntax_node(
14751        &mut self,
14752        _: &SelectSmallerSyntaxNode,
14753        window: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) {
14756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14757
14758        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14759            self.select_syntax_node_history.pop()
14760        {
14761            if let Some(selection) = selections.last_mut() {
14762                selection.reversed = is_selection_reversed;
14763            }
14764
14765            self.select_syntax_node_history.disable_clearing = true;
14766            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14767                s.select(selections.to_vec());
14768            });
14769            self.select_syntax_node_history.disable_clearing = false;
14770
14771            match scroll_behavior {
14772                SelectSyntaxNodeScrollBehavior::CursorTop => {
14773                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14774                }
14775                SelectSyntaxNodeScrollBehavior::FitSelection => {
14776                    self.request_autoscroll(Autoscroll::fit(), cx);
14777                }
14778                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14779                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14780                }
14781            }
14782        }
14783    }
14784
14785    pub fn unwrap_syntax_node(
14786        &mut self,
14787        _: &UnwrapSyntaxNode,
14788        window: &mut Window,
14789        cx: &mut Context<Self>,
14790    ) {
14791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14792
14793        let buffer = self.buffer.read(cx).snapshot(cx);
14794        let selections = self
14795            .selections
14796            .all::<usize>(cx)
14797            .into_iter()
14798            // subtracting the offset requires sorting
14799            .sorted_by_key(|i| i.start);
14800
14801        let full_edits = selections
14802            .into_iter()
14803            .filter_map(|selection| {
14804                // Only requires two branches once if-let-chains stabilize (#53667)
14805                let child = if !selection.is_empty() {
14806                    selection.range()
14807                } else if let Some((_, ancestor_range)) =
14808                    buffer.syntax_ancestor(selection.start..selection.end)
14809                {
14810                    match ancestor_range {
14811                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14812                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14813                    }
14814                } else {
14815                    selection.range()
14816                };
14817
14818                let mut parent = child.clone();
14819                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14820                    parent = match ancestor_range {
14821                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14822                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14823                    };
14824                    if parent.start < child.start || parent.end > child.end {
14825                        break;
14826                    }
14827                }
14828
14829                if parent == child {
14830                    return None;
14831                }
14832                let text = buffer.text_for_range(child).collect::<String>();
14833                Some((selection.id, parent, text))
14834            })
14835            .collect::<Vec<_>>();
14836
14837        self.transact(window, cx, |this, window, cx| {
14838            this.buffer.update(cx, |buffer, cx| {
14839                buffer.edit(
14840                    full_edits
14841                        .iter()
14842                        .map(|(_, p, t)| (p.clone(), t.clone()))
14843                        .collect::<Vec<_>>(),
14844                    None,
14845                    cx,
14846                );
14847            });
14848            this.change_selections(Default::default(), window, cx, |s| {
14849                let mut offset = 0;
14850                let mut selections = vec![];
14851                for (id, parent, text) in full_edits {
14852                    let start = parent.start - offset;
14853                    offset += parent.len() - text.len();
14854                    selections.push(Selection {
14855                        id,
14856                        start,
14857                        end: start + text.len(),
14858                        reversed: false,
14859                        goal: Default::default(),
14860                    });
14861                }
14862                s.select(selections);
14863            });
14864        });
14865    }
14866
14867    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14868        if !EditorSettings::get_global(cx).gutter.runnables {
14869            self.clear_tasks();
14870            return Task::ready(());
14871        }
14872        let project = self.project().map(Entity::downgrade);
14873        let task_sources = self.lsp_task_sources(cx);
14874        let multi_buffer = self.buffer.downgrade();
14875        cx.spawn_in(window, async move |editor, cx| {
14876            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14877            let Some(project) = project.and_then(|p| p.upgrade()) else {
14878                return;
14879            };
14880            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14881                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14882            }) else {
14883                return;
14884            };
14885
14886            let hide_runnables = project
14887                .update(cx, |project, _| project.is_via_collab())
14888                .unwrap_or(true);
14889            if hide_runnables {
14890                return;
14891            }
14892            let new_rows =
14893                cx.background_spawn({
14894                    let snapshot = display_snapshot.clone();
14895                    async move {
14896                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14897                    }
14898                })
14899                    .await;
14900            let Ok(lsp_tasks) =
14901                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14902            else {
14903                return;
14904            };
14905            let lsp_tasks = lsp_tasks.await;
14906
14907            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14908                lsp_tasks
14909                    .into_iter()
14910                    .flat_map(|(kind, tasks)| {
14911                        tasks.into_iter().filter_map(move |(location, task)| {
14912                            Some((kind.clone(), location?, task))
14913                        })
14914                    })
14915                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14916                        let buffer = location.target.buffer;
14917                        let buffer_snapshot = buffer.read(cx).snapshot();
14918                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14919                            |(excerpt_id, snapshot, _)| {
14920                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14921                                    display_snapshot
14922                                        .buffer_snapshot
14923                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14924                                } else {
14925                                    None
14926                                }
14927                            },
14928                        );
14929                        if let Some(offset) = offset {
14930                            let task_buffer_range =
14931                                location.target.range.to_point(&buffer_snapshot);
14932                            let context_buffer_range =
14933                                task_buffer_range.to_offset(&buffer_snapshot);
14934                            let context_range = BufferOffset(context_buffer_range.start)
14935                                ..BufferOffset(context_buffer_range.end);
14936
14937                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14938                                .or_insert_with(|| RunnableTasks {
14939                                    templates: Vec::new(),
14940                                    offset,
14941                                    column: task_buffer_range.start.column,
14942                                    extra_variables: HashMap::default(),
14943                                    context_range,
14944                                })
14945                                .templates
14946                                .push((kind, task.original_task().clone()));
14947                        }
14948
14949                        acc
14950                    })
14951            }) else {
14952                return;
14953            };
14954
14955            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14956                buffer.language_settings(cx).tasks.prefer_lsp
14957            }) else {
14958                return;
14959            };
14960
14961            let rows = Self::runnable_rows(
14962                project,
14963                display_snapshot,
14964                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14965                new_rows,
14966                cx.clone(),
14967            )
14968            .await;
14969            editor
14970                .update(cx, |editor, _| {
14971                    editor.clear_tasks();
14972                    for (key, mut value) in rows {
14973                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14974                            value.templates.extend(lsp_tasks.templates);
14975                        }
14976
14977                        editor.insert_tasks(key, value);
14978                    }
14979                    for (key, value) in lsp_tasks_by_rows {
14980                        editor.insert_tasks(key, value);
14981                    }
14982                })
14983                .ok();
14984        })
14985    }
14986    fn fetch_runnable_ranges(
14987        snapshot: &DisplaySnapshot,
14988        range: Range<Anchor>,
14989    ) -> Vec<language::RunnableRange> {
14990        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14991    }
14992
14993    fn runnable_rows(
14994        project: Entity<Project>,
14995        snapshot: DisplaySnapshot,
14996        prefer_lsp: bool,
14997        runnable_ranges: Vec<RunnableRange>,
14998        cx: AsyncWindowContext,
14999    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15000        cx.spawn(async move |cx| {
15001            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15002            for mut runnable in runnable_ranges {
15003                let Some(tasks) = cx
15004                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15005                    .ok()
15006                else {
15007                    continue;
15008                };
15009                let mut tasks = tasks.await;
15010
15011                if prefer_lsp {
15012                    tasks.retain(|(task_kind, _)| {
15013                        !matches!(task_kind, TaskSourceKind::Language { .. })
15014                    });
15015                }
15016                if tasks.is_empty() {
15017                    continue;
15018                }
15019
15020                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15021                let Some(row) = snapshot
15022                    .buffer_snapshot
15023                    .buffer_line_for_row(MultiBufferRow(point.row))
15024                    .map(|(_, range)| range.start.row)
15025                else {
15026                    continue;
15027                };
15028
15029                let context_range =
15030                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15031                runnable_rows.push((
15032                    (runnable.buffer_id, row),
15033                    RunnableTasks {
15034                        templates: tasks,
15035                        offset: snapshot
15036                            .buffer_snapshot
15037                            .anchor_before(runnable.run_range.start),
15038                        context_range,
15039                        column: point.column,
15040                        extra_variables: runnable.extra_captures,
15041                    },
15042                ));
15043            }
15044            runnable_rows
15045        })
15046    }
15047
15048    fn templates_with_tags(
15049        project: &Entity<Project>,
15050        runnable: &mut Runnable,
15051        cx: &mut App,
15052    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15053        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15054            let (worktree_id, file) = project
15055                .buffer_for_id(runnable.buffer, cx)
15056                .and_then(|buffer| buffer.read(cx).file())
15057                .map(|file| (file.worktree_id(cx), file.clone()))
15058                .unzip();
15059
15060            (
15061                project.task_store().read(cx).task_inventory().cloned(),
15062                worktree_id,
15063                file,
15064            )
15065        });
15066
15067        let tags = mem::take(&mut runnable.tags);
15068        let language = runnable.language.clone();
15069        cx.spawn(async move |cx| {
15070            let mut templates_with_tags = Vec::new();
15071            if let Some(inventory) = inventory {
15072                for RunnableTag(tag) in tags {
15073                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15074                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15075                    }) else {
15076                        return templates_with_tags;
15077                    };
15078                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15079                        move |(_, template)| {
15080                            template.tags.iter().any(|source_tag| source_tag == &tag)
15081                        },
15082                    ));
15083                }
15084            }
15085            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15086
15087            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15088                // Strongest source wins; if we have worktree tag binding, prefer that to
15089                // global and language bindings;
15090                // if we have a global binding, prefer that to language binding.
15091                let first_mismatch = templates_with_tags
15092                    .iter()
15093                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15094                if let Some(index) = first_mismatch {
15095                    templates_with_tags.truncate(index);
15096                }
15097            }
15098
15099            templates_with_tags
15100        })
15101    }
15102
15103    pub fn move_to_enclosing_bracket(
15104        &mut self,
15105        _: &MoveToEnclosingBracket,
15106        window: &mut Window,
15107        cx: &mut Context<Self>,
15108    ) {
15109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15110        self.change_selections(Default::default(), window, cx, |s| {
15111            s.move_offsets_with(|snapshot, selection| {
15112                let Some(enclosing_bracket_ranges) =
15113                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15114                else {
15115                    return;
15116                };
15117
15118                let mut best_length = usize::MAX;
15119                let mut best_inside = false;
15120                let mut best_in_bracket_range = false;
15121                let mut best_destination = None;
15122                for (open, close) in enclosing_bracket_ranges {
15123                    let close = close.to_inclusive();
15124                    let length = close.end() - open.start;
15125                    let inside = selection.start >= open.end && selection.end <= *close.start();
15126                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15127                        || close.contains(&selection.head());
15128
15129                    // If best is next to a bracket and current isn't, skip
15130                    if !in_bracket_range && best_in_bracket_range {
15131                        continue;
15132                    }
15133
15134                    // Prefer smaller lengths unless best is inside and current isn't
15135                    if length > best_length && (best_inside || !inside) {
15136                        continue;
15137                    }
15138
15139                    best_length = length;
15140                    best_inside = inside;
15141                    best_in_bracket_range = in_bracket_range;
15142                    best_destination = Some(
15143                        if close.contains(&selection.start) && close.contains(&selection.end) {
15144                            if inside { open.end } else { open.start }
15145                        } else if inside {
15146                            *close.start()
15147                        } else {
15148                            *close.end()
15149                        },
15150                    );
15151                }
15152
15153                if let Some(destination) = best_destination {
15154                    selection.collapse_to(destination, SelectionGoal::None);
15155                }
15156            })
15157        });
15158    }
15159
15160    pub fn undo_selection(
15161        &mut self,
15162        _: &UndoSelection,
15163        window: &mut Window,
15164        cx: &mut Context<Self>,
15165    ) {
15166        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15167        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15168            self.selection_history.mode = SelectionHistoryMode::Undoing;
15169            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15170                this.end_selection(window, cx);
15171                this.change_selections(
15172                    SelectionEffects::scroll(Autoscroll::newest()),
15173                    window,
15174                    cx,
15175                    |s| s.select_anchors(entry.selections.to_vec()),
15176                );
15177            });
15178            self.selection_history.mode = SelectionHistoryMode::Normal;
15179
15180            self.select_next_state = entry.select_next_state;
15181            self.select_prev_state = entry.select_prev_state;
15182            self.add_selections_state = entry.add_selections_state;
15183        }
15184    }
15185
15186    pub fn redo_selection(
15187        &mut self,
15188        _: &RedoSelection,
15189        window: &mut Window,
15190        cx: &mut Context<Self>,
15191    ) {
15192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15193        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15194            self.selection_history.mode = SelectionHistoryMode::Redoing;
15195            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15196                this.end_selection(window, cx);
15197                this.change_selections(
15198                    SelectionEffects::scroll(Autoscroll::newest()),
15199                    window,
15200                    cx,
15201                    |s| s.select_anchors(entry.selections.to_vec()),
15202                );
15203            });
15204            self.selection_history.mode = SelectionHistoryMode::Normal;
15205
15206            self.select_next_state = entry.select_next_state;
15207            self.select_prev_state = entry.select_prev_state;
15208            self.add_selections_state = entry.add_selections_state;
15209        }
15210    }
15211
15212    pub fn expand_excerpts(
15213        &mut self,
15214        action: &ExpandExcerpts,
15215        _: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) {
15218        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15219    }
15220
15221    pub fn expand_excerpts_down(
15222        &mut self,
15223        action: &ExpandExcerptsDown,
15224        _: &mut Window,
15225        cx: &mut Context<Self>,
15226    ) {
15227        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15228    }
15229
15230    pub fn expand_excerpts_up(
15231        &mut self,
15232        action: &ExpandExcerptsUp,
15233        _: &mut Window,
15234        cx: &mut Context<Self>,
15235    ) {
15236        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15237    }
15238
15239    pub fn expand_excerpts_for_direction(
15240        &mut self,
15241        lines: u32,
15242        direction: ExpandExcerptDirection,
15243
15244        cx: &mut Context<Self>,
15245    ) {
15246        let selections = self.selections.disjoint_anchors();
15247
15248        let lines = if lines == 0 {
15249            EditorSettings::get_global(cx).expand_excerpt_lines
15250        } else {
15251            lines
15252        };
15253
15254        self.buffer.update(cx, |buffer, cx| {
15255            let snapshot = buffer.snapshot(cx);
15256            let mut excerpt_ids = selections
15257                .iter()
15258                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15259                .collect::<Vec<_>>();
15260            excerpt_ids.sort();
15261            excerpt_ids.dedup();
15262            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15263        })
15264    }
15265
15266    pub fn expand_excerpt(
15267        &mut self,
15268        excerpt: ExcerptId,
15269        direction: ExpandExcerptDirection,
15270        window: &mut Window,
15271        cx: &mut Context<Self>,
15272    ) {
15273        let current_scroll_position = self.scroll_position(cx);
15274        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15275        let mut should_scroll_up = false;
15276
15277        if direction == ExpandExcerptDirection::Down {
15278            let multi_buffer = self.buffer.read(cx);
15279            let snapshot = multi_buffer.snapshot(cx);
15280            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15281                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15282                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15283            {
15284                let buffer_snapshot = buffer.read(cx).snapshot();
15285                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15286                let last_row = buffer_snapshot.max_point().row;
15287                let lines_below = last_row.saturating_sub(excerpt_end_row);
15288                should_scroll_up = lines_below >= lines_to_expand;
15289            }
15290        }
15291
15292        self.buffer.update(cx, |buffer, cx| {
15293            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15294        });
15295
15296        if should_scroll_up {
15297            let new_scroll_position =
15298                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15299            self.set_scroll_position(new_scroll_position, window, cx);
15300        }
15301    }
15302
15303    pub fn go_to_singleton_buffer_point(
15304        &mut self,
15305        point: Point,
15306        window: &mut Window,
15307        cx: &mut Context<Self>,
15308    ) {
15309        self.go_to_singleton_buffer_range(point..point, window, cx);
15310    }
15311
15312    pub fn go_to_singleton_buffer_range(
15313        &mut self,
15314        range: Range<Point>,
15315        window: &mut Window,
15316        cx: &mut Context<Self>,
15317    ) {
15318        let multibuffer = self.buffer().read(cx);
15319        let Some(buffer) = multibuffer.as_singleton() else {
15320            return;
15321        };
15322        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15323            return;
15324        };
15325        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15326            return;
15327        };
15328        self.change_selections(
15329            SelectionEffects::default().nav_history(true),
15330            window,
15331            cx,
15332            |s| s.select_anchor_ranges([start..end]),
15333        );
15334    }
15335
15336    pub fn go_to_diagnostic(
15337        &mut self,
15338        action: &GoToDiagnostic,
15339        window: &mut Window,
15340        cx: &mut Context<Self>,
15341    ) {
15342        if !self.diagnostics_enabled() {
15343            return;
15344        }
15345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15346        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15347    }
15348
15349    pub fn go_to_prev_diagnostic(
15350        &mut self,
15351        action: &GoToPreviousDiagnostic,
15352        window: &mut Window,
15353        cx: &mut Context<Self>,
15354    ) {
15355        if !self.diagnostics_enabled() {
15356            return;
15357        }
15358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15359        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15360    }
15361
15362    pub fn go_to_diagnostic_impl(
15363        &mut self,
15364        direction: Direction,
15365        severity: GoToDiagnosticSeverityFilter,
15366        window: &mut Window,
15367        cx: &mut Context<Self>,
15368    ) {
15369        let buffer = self.buffer.read(cx).snapshot(cx);
15370        let selection = self.selections.newest::<usize>(cx);
15371
15372        let mut active_group_id = None;
15373        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15374            && active_group.active_range.start.to_offset(&buffer) == selection.start
15375        {
15376            active_group_id = Some(active_group.group_id);
15377        }
15378
15379        fn filtered(
15380            snapshot: EditorSnapshot,
15381            severity: GoToDiagnosticSeverityFilter,
15382            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15383        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15384            diagnostics
15385                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15386                .filter(|entry| entry.range.start != entry.range.end)
15387                .filter(|entry| !entry.diagnostic.is_unnecessary)
15388                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15389        }
15390
15391        let snapshot = self.snapshot(window, cx);
15392        let before = filtered(
15393            snapshot.clone(),
15394            severity,
15395            buffer
15396                .diagnostics_in_range(0..selection.start)
15397                .filter(|entry| entry.range.start <= selection.start),
15398        );
15399        let after = filtered(
15400            snapshot,
15401            severity,
15402            buffer
15403                .diagnostics_in_range(selection.start..buffer.len())
15404                .filter(|entry| entry.range.start >= selection.start),
15405        );
15406
15407        let mut found: Option<DiagnosticEntry<usize>> = None;
15408        if direction == Direction::Prev {
15409            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15410            {
15411                for diagnostic in prev_diagnostics.into_iter().rev() {
15412                    if diagnostic.range.start != selection.start
15413                        || active_group_id
15414                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15415                    {
15416                        found = Some(diagnostic);
15417                        break 'outer;
15418                    }
15419                }
15420            }
15421        } else {
15422            for diagnostic in after.chain(before) {
15423                if diagnostic.range.start != selection.start
15424                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15425                {
15426                    found = Some(diagnostic);
15427                    break;
15428                }
15429            }
15430        }
15431        let Some(next_diagnostic) = found else {
15432            return;
15433        };
15434
15435        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15436            return;
15437        };
15438        self.change_selections(Default::default(), window, cx, |s| {
15439            s.select_ranges(vec![
15440                next_diagnostic.range.start..next_diagnostic.range.start,
15441            ])
15442        });
15443        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15444        self.refresh_edit_prediction(false, true, window, cx);
15445    }
15446
15447    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15449        let snapshot = self.snapshot(window, cx);
15450        let selection = self.selections.newest::<Point>(cx);
15451        self.go_to_hunk_before_or_after_position(
15452            &snapshot,
15453            selection.head(),
15454            Direction::Next,
15455            window,
15456            cx,
15457        );
15458    }
15459
15460    pub fn go_to_hunk_before_or_after_position(
15461        &mut self,
15462        snapshot: &EditorSnapshot,
15463        position: Point,
15464        direction: Direction,
15465        window: &mut Window,
15466        cx: &mut Context<Editor>,
15467    ) {
15468        let row = if direction == Direction::Next {
15469            self.hunk_after_position(snapshot, position)
15470                .map(|hunk| hunk.row_range.start)
15471        } else {
15472            self.hunk_before_position(snapshot, position)
15473        };
15474
15475        if let Some(row) = row {
15476            let destination = Point::new(row.0, 0);
15477            let autoscroll = Autoscroll::center();
15478
15479            self.unfold_ranges(&[destination..destination], false, false, cx);
15480            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15481                s.select_ranges([destination..destination]);
15482            });
15483        }
15484    }
15485
15486    fn hunk_after_position(
15487        &mut self,
15488        snapshot: &EditorSnapshot,
15489        position: Point,
15490    ) -> Option<MultiBufferDiffHunk> {
15491        snapshot
15492            .buffer_snapshot
15493            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15494            .find(|hunk| hunk.row_range.start.0 > position.row)
15495            .or_else(|| {
15496                snapshot
15497                    .buffer_snapshot
15498                    .diff_hunks_in_range(Point::zero()..position)
15499                    .find(|hunk| hunk.row_range.end.0 < position.row)
15500            })
15501    }
15502
15503    fn go_to_prev_hunk(
15504        &mut self,
15505        _: &GoToPreviousHunk,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15510        let snapshot = self.snapshot(window, cx);
15511        let selection = self.selections.newest::<Point>(cx);
15512        self.go_to_hunk_before_or_after_position(
15513            &snapshot,
15514            selection.head(),
15515            Direction::Prev,
15516            window,
15517            cx,
15518        );
15519    }
15520
15521    fn hunk_before_position(
15522        &mut self,
15523        snapshot: &EditorSnapshot,
15524        position: Point,
15525    ) -> Option<MultiBufferRow> {
15526        snapshot
15527            .buffer_snapshot
15528            .diff_hunk_before(position)
15529            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15530    }
15531
15532    fn go_to_next_change(
15533        &mut self,
15534        _: &GoToNextChange,
15535        window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) {
15538        if let Some(selections) = self
15539            .change_list
15540            .next_change(1, Direction::Next)
15541            .map(|s| s.to_vec())
15542        {
15543            self.change_selections(Default::default(), window, cx, |s| {
15544                let map = s.display_map();
15545                s.select_display_ranges(selections.iter().map(|a| {
15546                    let point = a.to_display_point(&map);
15547                    point..point
15548                }))
15549            })
15550        }
15551    }
15552
15553    fn go_to_previous_change(
15554        &mut self,
15555        _: &GoToPreviousChange,
15556        window: &mut Window,
15557        cx: &mut Context<Self>,
15558    ) {
15559        if let Some(selections) = self
15560            .change_list
15561            .next_change(1, Direction::Prev)
15562            .map(|s| s.to_vec())
15563        {
15564            self.change_selections(Default::default(), window, cx, |s| {
15565                let map = s.display_map();
15566                s.select_display_ranges(selections.iter().map(|a| {
15567                    let point = a.to_display_point(&map);
15568                    point..point
15569                }))
15570            })
15571        }
15572    }
15573
15574    fn go_to_line<T: 'static>(
15575        &mut self,
15576        position: Anchor,
15577        highlight_color: Option<Hsla>,
15578        window: &mut Window,
15579        cx: &mut Context<Self>,
15580    ) {
15581        let snapshot = self.snapshot(window, cx).display_snapshot;
15582        let position = position.to_point(&snapshot.buffer_snapshot);
15583        let start = snapshot
15584            .buffer_snapshot
15585            .clip_point(Point::new(position.row, 0), Bias::Left);
15586        let end = start + Point::new(1, 0);
15587        let start = snapshot.buffer_snapshot.anchor_before(start);
15588        let end = snapshot.buffer_snapshot.anchor_before(end);
15589
15590        self.highlight_rows::<T>(
15591            start..end,
15592            highlight_color
15593                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15594            Default::default(),
15595            cx,
15596        );
15597
15598        if self.buffer.read(cx).is_singleton() {
15599            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15600        }
15601    }
15602
15603    pub fn go_to_definition(
15604        &mut self,
15605        _: &GoToDefinition,
15606        window: &mut Window,
15607        cx: &mut Context<Self>,
15608    ) -> Task<Result<Navigated>> {
15609        let definition =
15610            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15611        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15612        cx.spawn_in(window, async move |editor, cx| {
15613            if definition.await? == Navigated::Yes {
15614                return Ok(Navigated::Yes);
15615            }
15616            match fallback_strategy {
15617                GoToDefinitionFallback::None => Ok(Navigated::No),
15618                GoToDefinitionFallback::FindAllReferences => {
15619                    match editor.update_in(cx, |editor, window, cx| {
15620                        editor.find_all_references(&FindAllReferences, window, cx)
15621                    })? {
15622                        Some(references) => references.await,
15623                        None => Ok(Navigated::No),
15624                    }
15625                }
15626            }
15627        })
15628    }
15629
15630    pub fn go_to_declaration(
15631        &mut self,
15632        _: &GoToDeclaration,
15633        window: &mut Window,
15634        cx: &mut Context<Self>,
15635    ) -> Task<Result<Navigated>> {
15636        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15637    }
15638
15639    pub fn go_to_declaration_split(
15640        &mut self,
15641        _: &GoToDeclaration,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) -> Task<Result<Navigated>> {
15645        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15646    }
15647
15648    pub fn go_to_implementation(
15649        &mut self,
15650        _: &GoToImplementation,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) -> Task<Result<Navigated>> {
15654        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15655    }
15656
15657    pub fn go_to_implementation_split(
15658        &mut self,
15659        _: &GoToImplementationSplit,
15660        window: &mut Window,
15661        cx: &mut Context<Self>,
15662    ) -> Task<Result<Navigated>> {
15663        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15664    }
15665
15666    pub fn go_to_type_definition(
15667        &mut self,
15668        _: &GoToTypeDefinition,
15669        window: &mut Window,
15670        cx: &mut Context<Self>,
15671    ) -> Task<Result<Navigated>> {
15672        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15673    }
15674
15675    pub fn go_to_definition_split(
15676        &mut self,
15677        _: &GoToDefinitionSplit,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) -> Task<Result<Navigated>> {
15681        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15682    }
15683
15684    pub fn go_to_type_definition_split(
15685        &mut self,
15686        _: &GoToTypeDefinitionSplit,
15687        window: &mut Window,
15688        cx: &mut Context<Self>,
15689    ) -> Task<Result<Navigated>> {
15690        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15691    }
15692
15693    fn go_to_definition_of_kind(
15694        &mut self,
15695        kind: GotoDefinitionKind,
15696        split: bool,
15697        window: &mut Window,
15698        cx: &mut Context<Self>,
15699    ) -> Task<Result<Navigated>> {
15700        let Some(provider) = self.semantics_provider.clone() else {
15701            return Task::ready(Ok(Navigated::No));
15702        };
15703        let head = self.selections.newest::<usize>(cx).head();
15704        let buffer = self.buffer.read(cx);
15705        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15706            return Task::ready(Ok(Navigated::No));
15707        };
15708        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15709            return Task::ready(Ok(Navigated::No));
15710        };
15711
15712        cx.spawn_in(window, async move |editor, cx| {
15713            let definitions = definitions.await?;
15714            let navigated = editor
15715                .update_in(cx, |editor, window, cx| {
15716                    editor.navigate_to_hover_links(
15717                        Some(kind),
15718                        definitions
15719                            .into_iter()
15720                            .filter(|location| {
15721                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15722                            })
15723                            .map(HoverLink::Text)
15724                            .collect::<Vec<_>>(),
15725                        split,
15726                        window,
15727                        cx,
15728                    )
15729                })?
15730                .await?;
15731            anyhow::Ok(navigated)
15732        })
15733    }
15734
15735    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15736        let selection = self.selections.newest_anchor();
15737        let head = selection.head();
15738        let tail = selection.tail();
15739
15740        let Some((buffer, start_position)) =
15741            self.buffer.read(cx).text_anchor_for_position(head, cx)
15742        else {
15743            return;
15744        };
15745
15746        let end_position = if head != tail {
15747            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15748                return;
15749            };
15750            Some(pos)
15751        } else {
15752            None
15753        };
15754
15755        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15756            let url = if let Some(end_pos) = end_position {
15757                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15758            } else {
15759                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15760            };
15761
15762            if let Some(url) = url {
15763                editor.update(cx, |_, cx| {
15764                    cx.open_url(&url);
15765                })
15766            } else {
15767                Ok(())
15768            }
15769        });
15770
15771        url_finder.detach();
15772    }
15773
15774    pub fn open_selected_filename(
15775        &mut self,
15776        _: &OpenSelectedFilename,
15777        window: &mut Window,
15778        cx: &mut Context<Self>,
15779    ) {
15780        let Some(workspace) = self.workspace() else {
15781            return;
15782        };
15783
15784        let position = self.selections.newest_anchor().head();
15785
15786        let Some((buffer, buffer_position)) =
15787            self.buffer.read(cx).text_anchor_for_position(position, cx)
15788        else {
15789            return;
15790        };
15791
15792        let project = self.project.clone();
15793
15794        cx.spawn_in(window, async move |_, cx| {
15795            let result = find_file(&buffer, project, buffer_position, cx).await;
15796
15797            if let Some((_, path)) = result {
15798                workspace
15799                    .update_in(cx, |workspace, window, cx| {
15800                        workspace.open_resolved_path(path, window, cx)
15801                    })?
15802                    .await?;
15803            }
15804            anyhow::Ok(())
15805        })
15806        .detach();
15807    }
15808
15809    pub(crate) fn navigate_to_hover_links(
15810        &mut self,
15811        kind: Option<GotoDefinitionKind>,
15812        definitions: Vec<HoverLink>,
15813        split: bool,
15814        window: &mut Window,
15815        cx: &mut Context<Editor>,
15816    ) -> Task<Result<Navigated>> {
15817        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15818        let mut first_url_or_file = None;
15819        let definitions: Vec<_> = definitions
15820            .into_iter()
15821            .filter_map(|def| match def {
15822                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15823                HoverLink::InlayHint(lsp_location, server_id) => {
15824                    let computation =
15825                        self.compute_target_location(lsp_location, server_id, window, cx);
15826                    Some(cx.background_spawn(computation))
15827                }
15828                HoverLink::Url(url) => {
15829                    first_url_or_file = Some(Either::Left(url));
15830                    None
15831                }
15832                HoverLink::File(path) => {
15833                    first_url_or_file = Some(Either::Right(path));
15834                    None
15835                }
15836            })
15837            .collect();
15838
15839        let workspace = self.workspace();
15840
15841        cx.spawn_in(window, async move |editor, acx| {
15842            let mut locations: Vec<Location> = future::join_all(definitions)
15843                .await
15844                .into_iter()
15845                .filter_map(|location| location.transpose())
15846                .collect::<Result<_>>()
15847                .context("location tasks")?;
15848
15849            if locations.len() > 1 {
15850                let Some(workspace) = workspace else {
15851                    return Ok(Navigated::No);
15852                };
15853
15854                let tab_kind = match kind {
15855                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15856                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15857                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15858                    Some(GotoDefinitionKind::Type) => "Types",
15859                };
15860                let title = editor
15861                    .update_in(acx, |_, _, cx| {
15862                        let target = locations
15863                            .iter()
15864                            .map(|location| {
15865                                location
15866                                    .buffer
15867                                    .read(cx)
15868                                    .text_for_range(location.range.clone())
15869                                    .collect::<String>()
15870                            })
15871                            .filter(|text| !text.contains('\n'))
15872                            .unique()
15873                            .take(3)
15874                            .join(", ");
15875                        if target.is_empty() {
15876                            tab_kind.to_owned()
15877                        } else {
15878                            format!("{tab_kind} for {target}")
15879                        }
15880                    })
15881                    .context("buffer title")?;
15882
15883                let opened = workspace
15884                    .update_in(acx, |workspace, window, cx| {
15885                        Self::open_locations_in_multibuffer(
15886                            workspace,
15887                            locations,
15888                            title,
15889                            split,
15890                            MultibufferSelectionMode::First,
15891                            window,
15892                            cx,
15893                        )
15894                    })
15895                    .is_ok();
15896
15897                anyhow::Ok(Navigated::from_bool(opened))
15898            } else if locations.is_empty() {
15899                // If there is one definition, just open it directly
15900                match first_url_or_file {
15901                    Some(Either::Left(url)) => {
15902                        acx.update(|_, cx| cx.open_url(&url))?;
15903                        Ok(Navigated::Yes)
15904                    }
15905                    Some(Either::Right(path)) => {
15906                        let Some(workspace) = workspace else {
15907                            return Ok(Navigated::No);
15908                        };
15909
15910                        workspace
15911                            .update_in(acx, |workspace, window, cx| {
15912                                workspace.open_resolved_path(path, window, cx)
15913                            })?
15914                            .await?;
15915                        Ok(Navigated::Yes)
15916                    }
15917                    None => Ok(Navigated::No),
15918                }
15919            } else {
15920                let Some(workspace) = workspace else {
15921                    return Ok(Navigated::No);
15922                };
15923
15924                let target = locations.pop().unwrap();
15925                editor.update_in(acx, |editor, window, cx| {
15926                    let pane = workspace.read(cx).active_pane().clone();
15927
15928                    let range = target.range.to_point(target.buffer.read(cx));
15929                    let range = editor.range_for_match(&range);
15930                    let range = collapse_multiline_range(range);
15931
15932                    if !split
15933                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15934                    {
15935                        editor.go_to_singleton_buffer_range(range, window, cx);
15936                    } else {
15937                        window.defer(cx, move |window, cx| {
15938                            let target_editor: Entity<Self> =
15939                                workspace.update(cx, |workspace, cx| {
15940                                    let pane = if split {
15941                                        workspace.adjacent_pane(window, cx)
15942                                    } else {
15943                                        workspace.active_pane().clone()
15944                                    };
15945
15946                                    workspace.open_project_item(
15947                                        pane,
15948                                        target.buffer.clone(),
15949                                        true,
15950                                        true,
15951                                        window,
15952                                        cx,
15953                                    )
15954                                });
15955                            target_editor.update(cx, |target_editor, cx| {
15956                                // When selecting a definition in a different buffer, disable the nav history
15957                                // to avoid creating a history entry at the previous cursor location.
15958                                pane.update(cx, |pane, _| pane.disable_history());
15959                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15960                                pane.update(cx, |pane, _| pane.enable_history());
15961                            });
15962                        });
15963                    }
15964                    Navigated::Yes
15965                })
15966            }
15967        })
15968    }
15969
15970    fn compute_target_location(
15971        &self,
15972        lsp_location: lsp::Location,
15973        server_id: LanguageServerId,
15974        window: &mut Window,
15975        cx: &mut Context<Self>,
15976    ) -> Task<anyhow::Result<Option<Location>>> {
15977        let Some(project) = self.project.clone() else {
15978            return Task::ready(Ok(None));
15979        };
15980
15981        cx.spawn_in(window, async move |editor, cx| {
15982            let location_task = editor.update(cx, |_, cx| {
15983                project.update(cx, |project, cx| {
15984                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
15985                })
15986            })?;
15987            let location = Some({
15988                let target_buffer_handle = location_task.await.context("open local buffer")?;
15989                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15990                    let target_start = target_buffer
15991                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15992                    let target_end = target_buffer
15993                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15994                    target_buffer.anchor_after(target_start)
15995                        ..target_buffer.anchor_before(target_end)
15996                })?;
15997                Location {
15998                    buffer: target_buffer_handle,
15999                    range,
16000                }
16001            });
16002            Ok(location)
16003        })
16004    }
16005
16006    pub fn find_all_references(
16007        &mut self,
16008        _: &FindAllReferences,
16009        window: &mut Window,
16010        cx: &mut Context<Self>,
16011    ) -> Option<Task<Result<Navigated>>> {
16012        let selection = self.selections.newest::<usize>(cx);
16013        let multi_buffer = self.buffer.read(cx);
16014        let head = selection.head();
16015
16016        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16017        let head_anchor = multi_buffer_snapshot.anchor_at(
16018            head,
16019            if head < selection.tail() {
16020                Bias::Right
16021            } else {
16022                Bias::Left
16023            },
16024        );
16025
16026        match self
16027            .find_all_references_task_sources
16028            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16029        {
16030            Ok(_) => {
16031                log::info!(
16032                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16033                );
16034                return None;
16035            }
16036            Err(i) => {
16037                self.find_all_references_task_sources.insert(i, head_anchor);
16038            }
16039        }
16040
16041        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16042        let workspace = self.workspace()?;
16043        let project = workspace.read(cx).project().clone();
16044        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16045        Some(cx.spawn_in(window, async move |editor, cx| {
16046            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16047                if let Ok(i) = editor
16048                    .find_all_references_task_sources
16049                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16050                {
16051                    editor.find_all_references_task_sources.remove(i);
16052                }
16053            });
16054
16055            let locations = references.await?;
16056            if locations.is_empty() {
16057                return anyhow::Ok(Navigated::No);
16058            }
16059
16060            workspace.update_in(cx, |workspace, window, cx| {
16061                let target = locations
16062                    .iter()
16063                    .map(|location| {
16064                        location
16065                            .buffer
16066                            .read(cx)
16067                            .text_for_range(location.range.clone())
16068                            .collect::<String>()
16069                    })
16070                    .filter(|text| !text.contains('\n'))
16071                    .unique()
16072                    .take(3)
16073                    .join(", ");
16074                let title = if target.is_empty() {
16075                    "References".to_owned()
16076                } else {
16077                    format!("References to {target}")
16078                };
16079                Self::open_locations_in_multibuffer(
16080                    workspace,
16081                    locations,
16082                    title,
16083                    false,
16084                    MultibufferSelectionMode::First,
16085                    window,
16086                    cx,
16087                );
16088                Navigated::Yes
16089            })
16090        }))
16091    }
16092
16093    /// Opens a multibuffer with the given project locations in it
16094    pub fn open_locations_in_multibuffer(
16095        workspace: &mut Workspace,
16096        mut locations: Vec<Location>,
16097        title: String,
16098        split: bool,
16099        multibuffer_selection_mode: MultibufferSelectionMode,
16100        window: &mut Window,
16101        cx: &mut Context<Workspace>,
16102    ) {
16103        if locations.is_empty() {
16104            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16105            return;
16106        }
16107
16108        // If there are multiple definitions, open them in a multibuffer
16109        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16110        let mut locations = locations.into_iter().peekable();
16111        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16112        let capability = workspace.project().read(cx).capability();
16113
16114        let excerpt_buffer = cx.new(|cx| {
16115            let mut multibuffer = MultiBuffer::new(capability);
16116            while let Some(location) = locations.next() {
16117                let buffer = location.buffer.read(cx);
16118                let mut ranges_for_buffer = Vec::new();
16119                let range = location.range.to_point(buffer);
16120                ranges_for_buffer.push(range.clone());
16121
16122                while let Some(next_location) = locations.peek() {
16123                    if next_location.buffer == location.buffer {
16124                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16125                        locations.next();
16126                    } else {
16127                        break;
16128                    }
16129                }
16130
16131                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16132                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16133                    PathKey::for_buffer(&location.buffer, cx),
16134                    location.buffer.clone(),
16135                    ranges_for_buffer,
16136                    DEFAULT_MULTIBUFFER_CONTEXT,
16137                    cx,
16138                );
16139                ranges.extend(new_ranges)
16140            }
16141
16142            multibuffer.with_title(title)
16143        });
16144
16145        let editor = cx.new(|cx| {
16146            Editor::for_multibuffer(
16147                excerpt_buffer,
16148                Some(workspace.project().clone()),
16149                window,
16150                cx,
16151            )
16152        });
16153        editor.update(cx, |editor, cx| {
16154            match multibuffer_selection_mode {
16155                MultibufferSelectionMode::First => {
16156                    if let Some(first_range) = ranges.first() {
16157                        editor.change_selections(
16158                            SelectionEffects::no_scroll(),
16159                            window,
16160                            cx,
16161                            |selections| {
16162                                selections.clear_disjoint();
16163                                selections
16164                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16165                            },
16166                        );
16167                    }
16168                    editor.highlight_background::<Self>(
16169                        &ranges,
16170                        |theme| theme.colors().editor_highlighted_line_background,
16171                        cx,
16172                    );
16173                }
16174                MultibufferSelectionMode::All => {
16175                    editor.change_selections(
16176                        SelectionEffects::no_scroll(),
16177                        window,
16178                        cx,
16179                        |selections| {
16180                            selections.clear_disjoint();
16181                            selections.select_anchor_ranges(ranges);
16182                        },
16183                    );
16184                }
16185            }
16186            editor.register_buffers_with_language_servers(cx);
16187        });
16188
16189        let item = Box::new(editor);
16190        let item_id = item.item_id();
16191
16192        if split {
16193            workspace.split_item(SplitDirection::Right, item, window, cx);
16194        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16195            let (preview_item_id, preview_item_idx) =
16196                workspace.active_pane().read_with(cx, |pane, _| {
16197                    (pane.preview_item_id(), pane.preview_item_idx())
16198                });
16199
16200            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16201
16202            if let Some(preview_item_id) = preview_item_id {
16203                workspace.active_pane().update(cx, |pane, cx| {
16204                    pane.remove_item(preview_item_id, false, false, window, cx);
16205                });
16206            }
16207        } else {
16208            workspace.add_item_to_active_pane(item, None, true, window, cx);
16209        }
16210        workspace.active_pane().update(cx, |pane, cx| {
16211            pane.set_preview_item_id(Some(item_id), cx);
16212        });
16213    }
16214
16215    pub fn rename(
16216        &mut self,
16217        _: &Rename,
16218        window: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) -> Option<Task<Result<()>>> {
16221        use language::ToOffset as _;
16222
16223        let provider = self.semantics_provider.clone()?;
16224        let selection = self.selections.newest_anchor().clone();
16225        let (cursor_buffer, cursor_buffer_position) = self
16226            .buffer
16227            .read(cx)
16228            .text_anchor_for_position(selection.head(), cx)?;
16229        let (tail_buffer, cursor_buffer_position_end) = self
16230            .buffer
16231            .read(cx)
16232            .text_anchor_for_position(selection.tail(), cx)?;
16233        if tail_buffer != cursor_buffer {
16234            return None;
16235        }
16236
16237        let snapshot = cursor_buffer.read(cx).snapshot();
16238        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16239        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16240        let prepare_rename = provider
16241            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16242            .unwrap_or_else(|| Task::ready(Ok(None)));
16243        drop(snapshot);
16244
16245        Some(cx.spawn_in(window, async move |this, cx| {
16246            let rename_range = if let Some(range) = prepare_rename.await? {
16247                Some(range)
16248            } else {
16249                this.update(cx, |this, cx| {
16250                    let buffer = this.buffer.read(cx).snapshot(cx);
16251                    let mut buffer_highlights = this
16252                        .document_highlights_for_position(selection.head(), &buffer)
16253                        .filter(|highlight| {
16254                            highlight.start.excerpt_id == selection.head().excerpt_id
16255                                && highlight.end.excerpt_id == selection.head().excerpt_id
16256                        });
16257                    buffer_highlights
16258                        .next()
16259                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16260                })?
16261            };
16262            if let Some(rename_range) = rename_range {
16263                this.update_in(cx, |this, window, cx| {
16264                    let snapshot = cursor_buffer.read(cx).snapshot();
16265                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16266                    let cursor_offset_in_rename_range =
16267                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16268                    let cursor_offset_in_rename_range_end =
16269                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16270
16271                    this.take_rename(false, window, cx);
16272                    let buffer = this.buffer.read(cx).read(cx);
16273                    let cursor_offset = selection.head().to_offset(&buffer);
16274                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16275                    let rename_end = rename_start + rename_buffer_range.len();
16276                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16277                    let mut old_highlight_id = None;
16278                    let old_name: Arc<str> = buffer
16279                        .chunks(rename_start..rename_end, true)
16280                        .map(|chunk| {
16281                            if old_highlight_id.is_none() {
16282                                old_highlight_id = chunk.syntax_highlight_id;
16283                            }
16284                            chunk.text
16285                        })
16286                        .collect::<String>()
16287                        .into();
16288
16289                    drop(buffer);
16290
16291                    // Position the selection in the rename editor so that it matches the current selection.
16292                    this.show_local_selections = false;
16293                    let rename_editor = cx.new(|cx| {
16294                        let mut editor = Editor::single_line(window, cx);
16295                        editor.buffer.update(cx, |buffer, cx| {
16296                            buffer.edit([(0..0, old_name.clone())], None, cx)
16297                        });
16298                        let rename_selection_range = match cursor_offset_in_rename_range
16299                            .cmp(&cursor_offset_in_rename_range_end)
16300                        {
16301                            Ordering::Equal => {
16302                                editor.select_all(&SelectAll, window, cx);
16303                                return editor;
16304                            }
16305                            Ordering::Less => {
16306                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16307                            }
16308                            Ordering::Greater => {
16309                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16310                            }
16311                        };
16312                        if rename_selection_range.end > old_name.len() {
16313                            editor.select_all(&SelectAll, window, cx);
16314                        } else {
16315                            editor.change_selections(Default::default(), window, cx, |s| {
16316                                s.select_ranges([rename_selection_range]);
16317                            });
16318                        }
16319                        editor
16320                    });
16321                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16322                        if e == &EditorEvent::Focused {
16323                            cx.emit(EditorEvent::FocusedIn)
16324                        }
16325                    })
16326                    .detach();
16327
16328                    let write_highlights =
16329                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16330                    let read_highlights =
16331                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16332                    let ranges = write_highlights
16333                        .iter()
16334                        .flat_map(|(_, ranges)| ranges.iter())
16335                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16336                        .cloned()
16337                        .collect();
16338
16339                    this.highlight_text::<Rename>(
16340                        ranges,
16341                        HighlightStyle {
16342                            fade_out: Some(0.6),
16343                            ..Default::default()
16344                        },
16345                        cx,
16346                    );
16347                    let rename_focus_handle = rename_editor.focus_handle(cx);
16348                    window.focus(&rename_focus_handle);
16349                    let block_id = this.insert_blocks(
16350                        [BlockProperties {
16351                            style: BlockStyle::Flex,
16352                            placement: BlockPlacement::Below(range.start),
16353                            height: Some(1),
16354                            render: Arc::new({
16355                                let rename_editor = rename_editor.clone();
16356                                move |cx: &mut BlockContext| {
16357                                    let mut text_style = cx.editor_style.text.clone();
16358                                    if let Some(highlight_style) = old_highlight_id
16359                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16360                                    {
16361                                        text_style = text_style.highlight(highlight_style);
16362                                    }
16363                                    div()
16364                                        .block_mouse_except_scroll()
16365                                        .pl(cx.anchor_x)
16366                                        .child(EditorElement::new(
16367                                            &rename_editor,
16368                                            EditorStyle {
16369                                                background: cx.theme().system().transparent,
16370                                                local_player: cx.editor_style.local_player,
16371                                                text: text_style,
16372                                                scrollbar_width: cx.editor_style.scrollbar_width,
16373                                                syntax: cx.editor_style.syntax.clone(),
16374                                                status: cx.editor_style.status.clone(),
16375                                                inlay_hints_style: HighlightStyle {
16376                                                    font_weight: Some(FontWeight::BOLD),
16377                                                    ..make_inlay_hints_style(cx.app)
16378                                                },
16379                                                edit_prediction_styles: make_suggestion_styles(
16380                                                    cx.app,
16381                                                ),
16382                                                ..EditorStyle::default()
16383                                            },
16384                                        ))
16385                                        .into_any_element()
16386                                }
16387                            }),
16388                            priority: 0,
16389                        }],
16390                        Some(Autoscroll::fit()),
16391                        cx,
16392                    )[0];
16393                    this.pending_rename = Some(RenameState {
16394                        range,
16395                        old_name,
16396                        editor: rename_editor,
16397                        block_id,
16398                    });
16399                })?;
16400            }
16401
16402            Ok(())
16403        }))
16404    }
16405
16406    pub fn confirm_rename(
16407        &mut self,
16408        _: &ConfirmRename,
16409        window: &mut Window,
16410        cx: &mut Context<Self>,
16411    ) -> Option<Task<Result<()>>> {
16412        let rename = self.take_rename(false, window, cx)?;
16413        let workspace = self.workspace()?.downgrade();
16414        let (buffer, start) = self
16415            .buffer
16416            .read(cx)
16417            .text_anchor_for_position(rename.range.start, cx)?;
16418        let (end_buffer, _) = self
16419            .buffer
16420            .read(cx)
16421            .text_anchor_for_position(rename.range.end, cx)?;
16422        if buffer != end_buffer {
16423            return None;
16424        }
16425
16426        let old_name = rename.old_name;
16427        let new_name = rename.editor.read(cx).text(cx);
16428
16429        let rename = self.semantics_provider.as_ref()?.perform_rename(
16430            &buffer,
16431            start,
16432            new_name.clone(),
16433            cx,
16434        )?;
16435
16436        Some(cx.spawn_in(window, async move |editor, cx| {
16437            let project_transaction = rename.await?;
16438            Self::open_project_transaction(
16439                &editor,
16440                workspace,
16441                project_transaction,
16442                format!("Rename: {}{}", old_name, new_name),
16443                cx,
16444            )
16445            .await?;
16446
16447            editor.update(cx, |editor, cx| {
16448                editor.refresh_document_highlights(cx);
16449            })?;
16450            Ok(())
16451        }))
16452    }
16453
16454    fn take_rename(
16455        &mut self,
16456        moving_cursor: bool,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) -> Option<RenameState> {
16460        let rename = self.pending_rename.take()?;
16461        if rename.editor.focus_handle(cx).is_focused(window) {
16462            window.focus(&self.focus_handle);
16463        }
16464
16465        self.remove_blocks(
16466            [rename.block_id].into_iter().collect(),
16467            Some(Autoscroll::fit()),
16468            cx,
16469        );
16470        self.clear_highlights::<Rename>(cx);
16471        self.show_local_selections = true;
16472
16473        if moving_cursor {
16474            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16475                editor.selections.newest::<usize>(cx).head()
16476            });
16477
16478            // Update the selection to match the position of the selection inside
16479            // the rename editor.
16480            let snapshot = self.buffer.read(cx).read(cx);
16481            let rename_range = rename.range.to_offset(&snapshot);
16482            let cursor_in_editor = snapshot
16483                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16484                .min(rename_range.end);
16485            drop(snapshot);
16486
16487            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16488                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16489            });
16490        } else {
16491            self.refresh_document_highlights(cx);
16492        }
16493
16494        Some(rename)
16495    }
16496
16497    pub fn pending_rename(&self) -> Option<&RenameState> {
16498        self.pending_rename.as_ref()
16499    }
16500
16501    fn format(
16502        &mut self,
16503        _: &Format,
16504        window: &mut Window,
16505        cx: &mut Context<Self>,
16506    ) -> Option<Task<Result<()>>> {
16507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16508
16509        let project = match &self.project {
16510            Some(project) => project.clone(),
16511            None => return None,
16512        };
16513
16514        Some(self.perform_format(
16515            project,
16516            FormatTrigger::Manual,
16517            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16518            window,
16519            cx,
16520        ))
16521    }
16522
16523    fn format_selections(
16524        &mut self,
16525        _: &FormatSelections,
16526        window: &mut Window,
16527        cx: &mut Context<Self>,
16528    ) -> Option<Task<Result<()>>> {
16529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16530
16531        let project = match &self.project {
16532            Some(project) => project.clone(),
16533            None => return None,
16534        };
16535
16536        let ranges = self
16537            .selections
16538            .all_adjusted(cx)
16539            .into_iter()
16540            .map(|selection| selection.range())
16541            .collect_vec();
16542
16543        Some(self.perform_format(
16544            project,
16545            FormatTrigger::Manual,
16546            FormatTarget::Ranges(ranges),
16547            window,
16548            cx,
16549        ))
16550    }
16551
16552    fn perform_format(
16553        &mut self,
16554        project: Entity<Project>,
16555        trigger: FormatTrigger,
16556        target: FormatTarget,
16557        window: &mut Window,
16558        cx: &mut Context<Self>,
16559    ) -> Task<Result<()>> {
16560        let buffer = self.buffer.clone();
16561        let (buffers, target) = match target {
16562            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16563            FormatTarget::Ranges(selection_ranges) => {
16564                let multi_buffer = buffer.read(cx);
16565                let snapshot = multi_buffer.read(cx);
16566                let mut buffers = HashSet::default();
16567                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16568                    BTreeMap::new();
16569                for selection_range in selection_ranges {
16570                    for (buffer, buffer_range, _) in
16571                        snapshot.range_to_buffer_ranges(selection_range)
16572                    {
16573                        let buffer_id = buffer.remote_id();
16574                        let start = buffer.anchor_before(buffer_range.start);
16575                        let end = buffer.anchor_after(buffer_range.end);
16576                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16577                        buffer_id_to_ranges
16578                            .entry(buffer_id)
16579                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16580                            .or_insert_with(|| vec![start..end]);
16581                    }
16582                }
16583                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16584            }
16585        };
16586
16587        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16588        let selections_prev = transaction_id_prev
16589            .and_then(|transaction_id_prev| {
16590                // default to selections as they were after the last edit, if we have them,
16591                // instead of how they are now.
16592                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16593                // will take you back to where you made the last edit, instead of staying where you scrolled
16594                self.selection_history
16595                    .transaction(transaction_id_prev)
16596                    .map(|t| t.0.clone())
16597            })
16598            .unwrap_or_else(|| self.selections.disjoint_anchors());
16599
16600        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16601        let format = project.update(cx, |project, cx| {
16602            project.format(buffers, target, true, trigger, cx)
16603        });
16604
16605        cx.spawn_in(window, async move |editor, cx| {
16606            let transaction = futures::select_biased! {
16607                transaction = format.log_err().fuse() => transaction,
16608                () = timeout => {
16609                    log::warn!("timed out waiting for formatting");
16610                    None
16611                }
16612            };
16613
16614            buffer
16615                .update(cx, |buffer, cx| {
16616                    if let Some(transaction) = transaction
16617                        && !buffer.is_singleton()
16618                    {
16619                        buffer.push_transaction(&transaction.0, cx);
16620                    }
16621                    cx.notify();
16622                })
16623                .ok();
16624
16625            if let Some(transaction_id_now) =
16626                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16627            {
16628                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16629                if has_new_transaction {
16630                    _ = editor.update(cx, |editor, _| {
16631                        editor
16632                            .selection_history
16633                            .insert_transaction(transaction_id_now, selections_prev);
16634                    });
16635                }
16636            }
16637
16638            Ok(())
16639        })
16640    }
16641
16642    fn organize_imports(
16643        &mut self,
16644        _: &OrganizeImports,
16645        window: &mut Window,
16646        cx: &mut Context<Self>,
16647    ) -> Option<Task<Result<()>>> {
16648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16649        let project = match &self.project {
16650            Some(project) => project.clone(),
16651            None => return None,
16652        };
16653        Some(self.perform_code_action_kind(
16654            project,
16655            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16656            window,
16657            cx,
16658        ))
16659    }
16660
16661    fn perform_code_action_kind(
16662        &mut self,
16663        project: Entity<Project>,
16664        kind: CodeActionKind,
16665        window: &mut Window,
16666        cx: &mut Context<Self>,
16667    ) -> Task<Result<()>> {
16668        let buffer = self.buffer.clone();
16669        let buffers = buffer.read(cx).all_buffers();
16670        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16671        let apply_action = project.update(cx, |project, cx| {
16672            project.apply_code_action_kind(buffers, kind, true, cx)
16673        });
16674        cx.spawn_in(window, async move |_, cx| {
16675            let transaction = futures::select_biased! {
16676                () = timeout => {
16677                    log::warn!("timed out waiting for executing code action");
16678                    None
16679                }
16680                transaction = apply_action.log_err().fuse() => transaction,
16681            };
16682            buffer
16683                .update(cx, |buffer, cx| {
16684                    // check if we need this
16685                    if let Some(transaction) = transaction
16686                        && !buffer.is_singleton()
16687                    {
16688                        buffer.push_transaction(&transaction.0, cx);
16689                    }
16690                    cx.notify();
16691                })
16692                .ok();
16693            Ok(())
16694        })
16695    }
16696
16697    pub fn restart_language_server(
16698        &mut self,
16699        _: &RestartLanguageServer,
16700        _: &mut Window,
16701        cx: &mut Context<Self>,
16702    ) {
16703        if let Some(project) = self.project.clone() {
16704            self.buffer.update(cx, |multi_buffer, cx| {
16705                project.update(cx, |project, cx| {
16706                    project.restart_language_servers_for_buffers(
16707                        multi_buffer.all_buffers().into_iter().collect(),
16708                        HashSet::default(),
16709                        cx,
16710                    );
16711                });
16712            })
16713        }
16714    }
16715
16716    pub fn stop_language_server(
16717        &mut self,
16718        _: &StopLanguageServer,
16719        _: &mut Window,
16720        cx: &mut Context<Self>,
16721    ) {
16722        if let Some(project) = self.project.clone() {
16723            self.buffer.update(cx, |multi_buffer, cx| {
16724                project.update(cx, |project, cx| {
16725                    project.stop_language_servers_for_buffers(
16726                        multi_buffer.all_buffers().into_iter().collect(),
16727                        HashSet::default(),
16728                        cx,
16729                    );
16730                    cx.emit(project::Event::RefreshInlayHints);
16731                });
16732            });
16733        }
16734    }
16735
16736    fn cancel_language_server_work(
16737        workspace: &mut Workspace,
16738        _: &actions::CancelLanguageServerWork,
16739        _: &mut Window,
16740        cx: &mut Context<Workspace>,
16741    ) {
16742        let project = workspace.project();
16743        let buffers = workspace
16744            .active_item(cx)
16745            .and_then(|item| item.act_as::<Editor>(cx))
16746            .map_or(HashSet::default(), |editor| {
16747                editor.read(cx).buffer.read(cx).all_buffers()
16748            });
16749        project.update(cx, |project, cx| {
16750            project.cancel_language_server_work_for_buffers(buffers, cx);
16751        });
16752    }
16753
16754    fn show_character_palette(
16755        &mut self,
16756        _: &ShowCharacterPalette,
16757        window: &mut Window,
16758        _: &mut Context<Self>,
16759    ) {
16760        window.show_character_palette();
16761    }
16762
16763    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16764        if !self.diagnostics_enabled() {
16765            return;
16766        }
16767
16768        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16769            let buffer = self.buffer.read(cx).snapshot(cx);
16770            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16771            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16772            let is_valid = buffer
16773                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16774                .any(|entry| {
16775                    entry.diagnostic.is_primary
16776                        && !entry.range.is_empty()
16777                        && entry.range.start == primary_range_start
16778                        && entry.diagnostic.message == active_diagnostics.active_message
16779                });
16780
16781            if !is_valid {
16782                self.dismiss_diagnostics(cx);
16783            }
16784        }
16785    }
16786
16787    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16788        match &self.active_diagnostics {
16789            ActiveDiagnostic::Group(group) => Some(group),
16790            _ => None,
16791        }
16792    }
16793
16794    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16795        if !self.diagnostics_enabled() {
16796            return;
16797        }
16798        self.dismiss_diagnostics(cx);
16799        self.active_diagnostics = ActiveDiagnostic::All;
16800    }
16801
16802    fn activate_diagnostics(
16803        &mut self,
16804        buffer_id: BufferId,
16805        diagnostic: DiagnosticEntry<usize>,
16806        window: &mut Window,
16807        cx: &mut Context<Self>,
16808    ) {
16809        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16810            return;
16811        }
16812        self.dismiss_diagnostics(cx);
16813        let snapshot = self.snapshot(window, cx);
16814        let buffer = self.buffer.read(cx).snapshot(cx);
16815        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16816            return;
16817        };
16818
16819        let diagnostic_group = buffer
16820            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16821            .collect::<Vec<_>>();
16822
16823        let blocks =
16824            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16825
16826        let blocks = self.display_map.update(cx, |display_map, cx| {
16827            display_map.insert_blocks(blocks, cx).into_iter().collect()
16828        });
16829        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16830            active_range: buffer.anchor_before(diagnostic.range.start)
16831                ..buffer.anchor_after(diagnostic.range.end),
16832            active_message: diagnostic.diagnostic.message.clone(),
16833            group_id: diagnostic.diagnostic.group_id,
16834            blocks,
16835        });
16836        cx.notify();
16837    }
16838
16839    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16840        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16841            return;
16842        };
16843
16844        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16845        if let ActiveDiagnostic::Group(group) = prev {
16846            self.display_map.update(cx, |display_map, cx| {
16847                display_map.remove_blocks(group.blocks, cx);
16848            });
16849            cx.notify();
16850        }
16851    }
16852
16853    /// Disable inline diagnostics rendering for this editor.
16854    pub fn disable_inline_diagnostics(&mut self) {
16855        self.inline_diagnostics_enabled = false;
16856        self.inline_diagnostics_update = Task::ready(());
16857        self.inline_diagnostics.clear();
16858    }
16859
16860    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16861        self.diagnostics_enabled = false;
16862        self.dismiss_diagnostics(cx);
16863        self.inline_diagnostics_update = Task::ready(());
16864        self.inline_diagnostics.clear();
16865    }
16866
16867    pub fn diagnostics_enabled(&self) -> bool {
16868        self.diagnostics_enabled && self.mode.is_full()
16869    }
16870
16871    pub fn inline_diagnostics_enabled(&self) -> bool {
16872        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16873    }
16874
16875    pub fn show_inline_diagnostics(&self) -> bool {
16876        self.show_inline_diagnostics
16877    }
16878
16879    pub fn toggle_inline_diagnostics(
16880        &mut self,
16881        _: &ToggleInlineDiagnostics,
16882        window: &mut Window,
16883        cx: &mut Context<Editor>,
16884    ) {
16885        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16886        self.refresh_inline_diagnostics(false, window, cx);
16887    }
16888
16889    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16890        self.diagnostics_max_severity = severity;
16891        self.display_map.update(cx, |display_map, _| {
16892            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16893        });
16894    }
16895
16896    pub fn toggle_diagnostics(
16897        &mut self,
16898        _: &ToggleDiagnostics,
16899        window: &mut Window,
16900        cx: &mut Context<Editor>,
16901    ) {
16902        if !self.diagnostics_enabled() {
16903            return;
16904        }
16905
16906        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16907            EditorSettings::get_global(cx)
16908                .diagnostics_max_severity
16909                .filter(|severity| severity != &DiagnosticSeverity::Off)
16910                .unwrap_or(DiagnosticSeverity::Hint)
16911        } else {
16912            DiagnosticSeverity::Off
16913        };
16914        self.set_max_diagnostics_severity(new_severity, cx);
16915        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16916            self.active_diagnostics = ActiveDiagnostic::None;
16917            self.inline_diagnostics_update = Task::ready(());
16918            self.inline_diagnostics.clear();
16919        } else {
16920            self.refresh_inline_diagnostics(false, window, cx);
16921        }
16922
16923        cx.notify();
16924    }
16925
16926    pub fn toggle_minimap(
16927        &mut self,
16928        _: &ToggleMinimap,
16929        window: &mut Window,
16930        cx: &mut Context<Editor>,
16931    ) {
16932        if self.supports_minimap(cx) {
16933            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16934        }
16935    }
16936
16937    fn refresh_inline_diagnostics(
16938        &mut self,
16939        debounce: bool,
16940        window: &mut Window,
16941        cx: &mut Context<Self>,
16942    ) {
16943        let max_severity = ProjectSettings::get_global(cx)
16944            .diagnostics
16945            .inline
16946            .max_severity
16947            .unwrap_or(self.diagnostics_max_severity);
16948
16949        if !self.inline_diagnostics_enabled()
16950            || !self.show_inline_diagnostics
16951            || max_severity == DiagnosticSeverity::Off
16952        {
16953            self.inline_diagnostics_update = Task::ready(());
16954            self.inline_diagnostics.clear();
16955            return;
16956        }
16957
16958        let debounce_ms = ProjectSettings::get_global(cx)
16959            .diagnostics
16960            .inline
16961            .update_debounce_ms;
16962        let debounce = if debounce && debounce_ms > 0 {
16963            Some(Duration::from_millis(debounce_ms))
16964        } else {
16965            None
16966        };
16967        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16968            if let Some(debounce) = debounce {
16969                cx.background_executor().timer(debounce).await;
16970            }
16971            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16972                editor
16973                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16974                    .ok()
16975            }) else {
16976                return;
16977            };
16978
16979            let new_inline_diagnostics = cx
16980                .background_spawn(async move {
16981                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16982                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16983                        let message = diagnostic_entry
16984                            .diagnostic
16985                            .message
16986                            .split_once('\n')
16987                            .map(|(line, _)| line)
16988                            .map(SharedString::new)
16989                            .unwrap_or_else(|| {
16990                                SharedString::from(diagnostic_entry.diagnostic.message)
16991                            });
16992                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16993                        let (Ok(i) | Err(i)) = inline_diagnostics
16994                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16995                        inline_diagnostics.insert(
16996                            i,
16997                            (
16998                                start_anchor,
16999                                InlineDiagnostic {
17000                                    message,
17001                                    group_id: diagnostic_entry.diagnostic.group_id,
17002                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17003                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17004                                    severity: diagnostic_entry.diagnostic.severity,
17005                                },
17006                            ),
17007                        );
17008                    }
17009                    inline_diagnostics
17010                })
17011                .await;
17012
17013            editor
17014                .update(cx, |editor, cx| {
17015                    editor.inline_diagnostics = new_inline_diagnostics;
17016                    cx.notify();
17017                })
17018                .ok();
17019        });
17020    }
17021
17022    fn pull_diagnostics(
17023        &mut self,
17024        buffer_id: Option<BufferId>,
17025        window: &Window,
17026        cx: &mut Context<Self>,
17027    ) -> Option<()> {
17028        if !self.mode().is_full() {
17029            return None;
17030        }
17031        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17032            .diagnostics
17033            .lsp_pull_diagnostics;
17034        if !pull_diagnostics_settings.enabled {
17035            return None;
17036        }
17037        let project = self.project()?.downgrade();
17038        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17039        let mut buffers = self.buffer.read(cx).all_buffers();
17040        if let Some(buffer_id) = buffer_id {
17041            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17042        }
17043
17044        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17045            cx.background_executor().timer(debounce).await;
17046
17047            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17048                buffers
17049                    .into_iter()
17050                    .filter_map(|buffer| {
17051                        project
17052                            .update(cx, |project, cx| {
17053                                project.lsp_store().update(cx, |lsp_store, cx| {
17054                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17055                                })
17056                            })
17057                            .ok()
17058                    })
17059                    .collect::<FuturesUnordered<_>>()
17060            }) else {
17061                return;
17062            };
17063
17064            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17065                match pull_task {
17066                    Ok(()) => {
17067                        if editor
17068                            .update_in(cx, |editor, window, cx| {
17069                                editor.update_diagnostics_state(window, cx);
17070                            })
17071                            .is_err()
17072                        {
17073                            return;
17074                        }
17075                    }
17076                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17077                }
17078            }
17079        });
17080
17081        Some(())
17082    }
17083
17084    pub fn set_selections_from_remote(
17085        &mut self,
17086        selections: Vec<Selection<Anchor>>,
17087        pending_selection: Option<Selection<Anchor>>,
17088        window: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) {
17091        let old_cursor_position = self.selections.newest_anchor().head();
17092        self.selections.change_with(cx, |s| {
17093            s.select_anchors(selections);
17094            if let Some(pending_selection) = pending_selection {
17095                s.set_pending(pending_selection, SelectMode::Character);
17096            } else {
17097                s.clear_pending();
17098            }
17099        });
17100        self.selections_did_change(
17101            false,
17102            &old_cursor_position,
17103            SelectionEffects::default(),
17104            window,
17105            cx,
17106        );
17107    }
17108
17109    pub fn transact(
17110        &mut self,
17111        window: &mut Window,
17112        cx: &mut Context<Self>,
17113        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17114    ) -> Option<TransactionId> {
17115        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17116            this.start_transaction_at(Instant::now(), window, cx);
17117            update(this, window, cx);
17118            this.end_transaction_at(Instant::now(), cx)
17119        })
17120    }
17121
17122    pub fn start_transaction_at(
17123        &mut self,
17124        now: Instant,
17125        window: &mut Window,
17126        cx: &mut Context<Self>,
17127    ) -> Option<TransactionId> {
17128        self.end_selection(window, cx);
17129        if let Some(tx_id) = self
17130            .buffer
17131            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17132        {
17133            self.selection_history
17134                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17135            cx.emit(EditorEvent::TransactionBegun {
17136                transaction_id: tx_id,
17137            });
17138            Some(tx_id)
17139        } else {
17140            None
17141        }
17142    }
17143
17144    pub fn end_transaction_at(
17145        &mut self,
17146        now: Instant,
17147        cx: &mut Context<Self>,
17148    ) -> Option<TransactionId> {
17149        if let Some(transaction_id) = self
17150            .buffer
17151            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17152        {
17153            if let Some((_, end_selections)) =
17154                self.selection_history.transaction_mut(transaction_id)
17155            {
17156                *end_selections = Some(self.selections.disjoint_anchors());
17157            } else {
17158                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17159            }
17160
17161            cx.emit(EditorEvent::Edited { transaction_id });
17162            Some(transaction_id)
17163        } else {
17164            None
17165        }
17166    }
17167
17168    pub fn modify_transaction_selection_history(
17169        &mut self,
17170        transaction_id: TransactionId,
17171        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17172    ) -> bool {
17173        self.selection_history
17174            .transaction_mut(transaction_id)
17175            .map(modify)
17176            .is_some()
17177    }
17178
17179    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17180        if self.selection_mark_mode {
17181            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17182                s.move_with(|_, sel| {
17183                    sel.collapse_to(sel.head(), SelectionGoal::None);
17184                });
17185            })
17186        }
17187        self.selection_mark_mode = true;
17188        cx.notify();
17189    }
17190
17191    pub fn swap_selection_ends(
17192        &mut self,
17193        _: &actions::SwapSelectionEnds,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) {
17197        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17198            s.move_with(|_, sel| {
17199                if sel.start != sel.end {
17200                    sel.reversed = !sel.reversed
17201                }
17202            });
17203        });
17204        self.request_autoscroll(Autoscroll::newest(), cx);
17205        cx.notify();
17206    }
17207
17208    pub fn toggle_focus(
17209        workspace: &mut Workspace,
17210        _: &actions::ToggleFocus,
17211        window: &mut Window,
17212        cx: &mut Context<Workspace>,
17213    ) {
17214        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17215            return;
17216        };
17217        workspace.activate_item(&item, true, true, window, cx);
17218    }
17219
17220    pub fn toggle_fold(
17221        &mut self,
17222        _: &actions::ToggleFold,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        if self.is_singleton(cx) {
17227            let selection = self.selections.newest::<Point>(cx);
17228
17229            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17230            let range = if selection.is_empty() {
17231                let point = selection.head().to_display_point(&display_map);
17232                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17233                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17234                    .to_point(&display_map);
17235                start..end
17236            } else {
17237                selection.range()
17238            };
17239            if display_map.folds_in_range(range).next().is_some() {
17240                self.unfold_lines(&Default::default(), window, cx)
17241            } else {
17242                self.fold(&Default::default(), window, cx)
17243            }
17244        } else {
17245            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17246            let buffer_ids: HashSet<_> = self
17247                .selections
17248                .disjoint_anchor_ranges()
17249                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17250                .collect();
17251
17252            let should_unfold = buffer_ids
17253                .iter()
17254                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17255
17256            for buffer_id in buffer_ids {
17257                if should_unfold {
17258                    self.unfold_buffer(buffer_id, cx);
17259                } else {
17260                    self.fold_buffer(buffer_id, cx);
17261                }
17262            }
17263        }
17264    }
17265
17266    pub fn toggle_fold_recursive(
17267        &mut self,
17268        _: &actions::ToggleFoldRecursive,
17269        window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) {
17272        let selection = self.selections.newest::<Point>(cx);
17273
17274        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17275        let range = if selection.is_empty() {
17276            let point = selection.head().to_display_point(&display_map);
17277            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17278            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17279                .to_point(&display_map);
17280            start..end
17281        } else {
17282            selection.range()
17283        };
17284        if display_map.folds_in_range(range).next().is_some() {
17285            self.unfold_recursive(&Default::default(), window, cx)
17286        } else {
17287            self.fold_recursive(&Default::default(), window, cx)
17288        }
17289    }
17290
17291    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17292        if self.is_singleton(cx) {
17293            let mut to_fold = Vec::new();
17294            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17295            let selections = self.selections.all_adjusted(cx);
17296
17297            for selection in selections {
17298                let range = selection.range().sorted();
17299                let buffer_start_row = range.start.row;
17300
17301                if range.start.row != range.end.row {
17302                    let mut found = false;
17303                    let mut row = range.start.row;
17304                    while row <= range.end.row {
17305                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17306                        {
17307                            found = true;
17308                            row = crease.range().end.row + 1;
17309                            to_fold.push(crease);
17310                        } else {
17311                            row += 1
17312                        }
17313                    }
17314                    if found {
17315                        continue;
17316                    }
17317                }
17318
17319                for row in (0..=range.start.row).rev() {
17320                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17321                        && crease.range().end.row >= buffer_start_row
17322                    {
17323                        to_fold.push(crease);
17324                        if row <= range.start.row {
17325                            break;
17326                        }
17327                    }
17328                }
17329            }
17330
17331            self.fold_creases(to_fold, true, window, cx);
17332        } else {
17333            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17334            let buffer_ids = self
17335                .selections
17336                .disjoint_anchor_ranges()
17337                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17338                .collect::<HashSet<_>>();
17339            for buffer_id in buffer_ids {
17340                self.fold_buffer(buffer_id, cx);
17341            }
17342        }
17343    }
17344
17345    pub fn toggle_fold_all(
17346        &mut self,
17347        _: &actions::ToggleFoldAll,
17348        window: &mut Window,
17349        cx: &mut Context<Self>,
17350    ) {
17351        if self.buffer.read(cx).is_singleton() {
17352            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17353            let has_folds = display_map
17354                .folds_in_range(0..display_map.buffer_snapshot.len())
17355                .next()
17356                .is_some();
17357
17358            if has_folds {
17359                self.unfold_all(&actions::UnfoldAll, window, cx);
17360            } else {
17361                self.fold_all(&actions::FoldAll, window, cx);
17362            }
17363        } else {
17364            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17365            let should_unfold = buffer_ids
17366                .iter()
17367                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17368
17369            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17370                editor
17371                    .update_in(cx, |editor, _, cx| {
17372                        for buffer_id in buffer_ids {
17373                            if should_unfold {
17374                                editor.unfold_buffer(buffer_id, cx);
17375                            } else {
17376                                editor.fold_buffer(buffer_id, cx);
17377                            }
17378                        }
17379                    })
17380                    .ok();
17381            });
17382        }
17383    }
17384
17385    fn fold_at_level(
17386        &mut self,
17387        fold_at: &FoldAtLevel,
17388        window: &mut Window,
17389        cx: &mut Context<Self>,
17390    ) {
17391        if !self.buffer.read(cx).is_singleton() {
17392            return;
17393        }
17394
17395        let fold_at_level = fold_at.0;
17396        let snapshot = self.buffer.read(cx).snapshot(cx);
17397        let mut to_fold = Vec::new();
17398        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17399
17400        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17401            while start_row < end_row {
17402                match self
17403                    .snapshot(window, cx)
17404                    .crease_for_buffer_row(MultiBufferRow(start_row))
17405                {
17406                    Some(crease) => {
17407                        let nested_start_row = crease.range().start.row + 1;
17408                        let nested_end_row = crease.range().end.row;
17409
17410                        if current_level < fold_at_level {
17411                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17412                        } else if current_level == fold_at_level {
17413                            to_fold.push(crease);
17414                        }
17415
17416                        start_row = nested_end_row + 1;
17417                    }
17418                    None => start_row += 1,
17419                }
17420            }
17421        }
17422
17423        self.fold_creases(to_fold, true, window, cx);
17424    }
17425
17426    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17427        if self.buffer.read(cx).is_singleton() {
17428            let mut fold_ranges = Vec::new();
17429            let snapshot = self.buffer.read(cx).snapshot(cx);
17430
17431            for row in 0..snapshot.max_row().0 {
17432                if let Some(foldable_range) = self
17433                    .snapshot(window, cx)
17434                    .crease_for_buffer_row(MultiBufferRow(row))
17435                {
17436                    fold_ranges.push(foldable_range);
17437                }
17438            }
17439
17440            self.fold_creases(fold_ranges, true, window, cx);
17441        } else {
17442            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17443                editor
17444                    .update_in(cx, |editor, _, cx| {
17445                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17446                            editor.fold_buffer(buffer_id, cx);
17447                        }
17448                    })
17449                    .ok();
17450            });
17451        }
17452    }
17453
17454    pub fn fold_function_bodies(
17455        &mut self,
17456        _: &actions::FoldFunctionBodies,
17457        window: &mut Window,
17458        cx: &mut Context<Self>,
17459    ) {
17460        let snapshot = self.buffer.read(cx).snapshot(cx);
17461
17462        let ranges = snapshot
17463            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17464            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17465            .collect::<Vec<_>>();
17466
17467        let creases = ranges
17468            .into_iter()
17469            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17470            .collect();
17471
17472        self.fold_creases(creases, true, window, cx);
17473    }
17474
17475    pub fn fold_recursive(
17476        &mut self,
17477        _: &actions::FoldRecursive,
17478        window: &mut Window,
17479        cx: &mut Context<Self>,
17480    ) {
17481        let mut to_fold = Vec::new();
17482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17483        let selections = self.selections.all_adjusted(cx);
17484
17485        for selection in selections {
17486            let range = selection.range().sorted();
17487            let buffer_start_row = range.start.row;
17488
17489            if range.start.row != range.end.row {
17490                let mut found = false;
17491                for row in range.start.row..=range.end.row {
17492                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17493                        found = true;
17494                        to_fold.push(crease);
17495                    }
17496                }
17497                if found {
17498                    continue;
17499                }
17500            }
17501
17502            for row in (0..=range.start.row).rev() {
17503                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17504                    if crease.range().end.row >= buffer_start_row {
17505                        to_fold.push(crease);
17506                    } else {
17507                        break;
17508                    }
17509                }
17510            }
17511        }
17512
17513        self.fold_creases(to_fold, true, window, cx);
17514    }
17515
17516    pub fn fold_at(
17517        &mut self,
17518        buffer_row: MultiBufferRow,
17519        window: &mut Window,
17520        cx: &mut Context<Self>,
17521    ) {
17522        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17523
17524        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17525            let autoscroll = self
17526                .selections
17527                .all::<Point>(cx)
17528                .iter()
17529                .any(|selection| crease.range().overlaps(&selection.range()));
17530
17531            self.fold_creases(vec![crease], autoscroll, window, cx);
17532        }
17533    }
17534
17535    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17536        if self.is_singleton(cx) {
17537            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17538            let buffer = &display_map.buffer_snapshot;
17539            let selections = self.selections.all::<Point>(cx);
17540            let ranges = selections
17541                .iter()
17542                .map(|s| {
17543                    let range = s.display_range(&display_map).sorted();
17544                    let mut start = range.start.to_point(&display_map);
17545                    let mut end = range.end.to_point(&display_map);
17546                    start.column = 0;
17547                    end.column = buffer.line_len(MultiBufferRow(end.row));
17548                    start..end
17549                })
17550                .collect::<Vec<_>>();
17551
17552            self.unfold_ranges(&ranges, true, true, cx);
17553        } else {
17554            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17555            let buffer_ids = self
17556                .selections
17557                .disjoint_anchor_ranges()
17558                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17559                .collect::<HashSet<_>>();
17560            for buffer_id in buffer_ids {
17561                self.unfold_buffer(buffer_id, cx);
17562            }
17563        }
17564    }
17565
17566    pub fn unfold_recursive(
17567        &mut self,
17568        _: &UnfoldRecursive,
17569        _window: &mut Window,
17570        cx: &mut Context<Self>,
17571    ) {
17572        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17573        let selections = self.selections.all::<Point>(cx);
17574        let ranges = selections
17575            .iter()
17576            .map(|s| {
17577                let mut range = s.display_range(&display_map).sorted();
17578                *range.start.column_mut() = 0;
17579                *range.end.column_mut() = display_map.line_len(range.end.row());
17580                let start = range.start.to_point(&display_map);
17581                let end = range.end.to_point(&display_map);
17582                start..end
17583            })
17584            .collect::<Vec<_>>();
17585
17586        self.unfold_ranges(&ranges, true, true, cx);
17587    }
17588
17589    pub fn unfold_at(
17590        &mut self,
17591        buffer_row: MultiBufferRow,
17592        _window: &mut Window,
17593        cx: &mut Context<Self>,
17594    ) {
17595        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17596
17597        let intersection_range = Point::new(buffer_row.0, 0)
17598            ..Point::new(
17599                buffer_row.0,
17600                display_map.buffer_snapshot.line_len(buffer_row),
17601            );
17602
17603        let autoscroll = self
17604            .selections
17605            .all::<Point>(cx)
17606            .iter()
17607            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17608
17609        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17610    }
17611
17612    pub fn unfold_all(
17613        &mut self,
17614        _: &actions::UnfoldAll,
17615        _window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        if self.buffer.read(cx).is_singleton() {
17619            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17620            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17621        } else {
17622            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17623                editor
17624                    .update(cx, |editor, cx| {
17625                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17626                            editor.unfold_buffer(buffer_id, cx);
17627                        }
17628                    })
17629                    .ok();
17630            });
17631        }
17632    }
17633
17634    pub fn fold_selected_ranges(
17635        &mut self,
17636        _: &FoldSelectedRanges,
17637        window: &mut Window,
17638        cx: &mut Context<Self>,
17639    ) {
17640        let selections = self.selections.all_adjusted(cx);
17641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17642        let ranges = selections
17643            .into_iter()
17644            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17645            .collect::<Vec<_>>();
17646        self.fold_creases(ranges, true, window, cx);
17647    }
17648
17649    pub fn fold_ranges<T: ToOffset + Clone>(
17650        &mut self,
17651        ranges: Vec<Range<T>>,
17652        auto_scroll: bool,
17653        window: &mut Window,
17654        cx: &mut Context<Self>,
17655    ) {
17656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17657        let ranges = ranges
17658            .into_iter()
17659            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17660            .collect::<Vec<_>>();
17661        self.fold_creases(ranges, auto_scroll, window, cx);
17662    }
17663
17664    pub fn fold_creases<T: ToOffset + Clone>(
17665        &mut self,
17666        creases: Vec<Crease<T>>,
17667        auto_scroll: bool,
17668        _window: &mut Window,
17669        cx: &mut Context<Self>,
17670    ) {
17671        if creases.is_empty() {
17672            return;
17673        }
17674
17675        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17676
17677        if auto_scroll {
17678            self.request_autoscroll(Autoscroll::fit(), cx);
17679        }
17680
17681        cx.notify();
17682
17683        self.scrollbar_marker_state.dirty = true;
17684        self.folds_did_change(cx);
17685    }
17686
17687    /// Removes any folds whose ranges intersect any of the given ranges.
17688    pub fn unfold_ranges<T: ToOffset + Clone>(
17689        &mut self,
17690        ranges: &[Range<T>],
17691        inclusive: bool,
17692        auto_scroll: bool,
17693        cx: &mut Context<Self>,
17694    ) {
17695        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17696            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17697        });
17698        self.folds_did_change(cx);
17699    }
17700
17701    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17702        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17703            return;
17704        }
17705        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17706        self.display_map.update(cx, |display_map, cx| {
17707            display_map.fold_buffers([buffer_id], cx)
17708        });
17709        cx.emit(EditorEvent::BufferFoldToggled {
17710            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17711            folded: true,
17712        });
17713        cx.notify();
17714    }
17715
17716    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17717        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17718            return;
17719        }
17720        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17721        self.display_map.update(cx, |display_map, cx| {
17722            display_map.unfold_buffers([buffer_id], cx);
17723        });
17724        cx.emit(EditorEvent::BufferFoldToggled {
17725            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17726            folded: false,
17727        });
17728        cx.notify();
17729    }
17730
17731    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17732        self.display_map.read(cx).is_buffer_folded(buffer)
17733    }
17734
17735    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17736        self.display_map.read(cx).folded_buffers()
17737    }
17738
17739    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17740        self.display_map.update(cx, |display_map, cx| {
17741            display_map.disable_header_for_buffer(buffer_id, cx);
17742        });
17743        cx.notify();
17744    }
17745
17746    /// Removes any folds with the given ranges.
17747    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17748        &mut self,
17749        ranges: &[Range<T>],
17750        type_id: TypeId,
17751        auto_scroll: bool,
17752        cx: &mut Context<Self>,
17753    ) {
17754        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17755            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17756        });
17757        self.folds_did_change(cx);
17758    }
17759
17760    fn remove_folds_with<T: ToOffset + Clone>(
17761        &mut self,
17762        ranges: &[Range<T>],
17763        auto_scroll: bool,
17764        cx: &mut Context<Self>,
17765        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17766    ) {
17767        if ranges.is_empty() {
17768            return;
17769        }
17770
17771        let mut buffers_affected = HashSet::default();
17772        let multi_buffer = self.buffer().read(cx);
17773        for range in ranges {
17774            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17775                buffers_affected.insert(buffer.read(cx).remote_id());
17776            };
17777        }
17778
17779        self.display_map.update(cx, update);
17780
17781        if auto_scroll {
17782            self.request_autoscroll(Autoscroll::fit(), cx);
17783        }
17784
17785        cx.notify();
17786        self.scrollbar_marker_state.dirty = true;
17787        self.active_indent_guides_state.dirty = true;
17788    }
17789
17790    pub fn update_renderer_widths(
17791        &mut self,
17792        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17793        cx: &mut Context<Self>,
17794    ) -> bool {
17795        self.display_map
17796            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17797    }
17798
17799    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17800        self.display_map.read(cx).fold_placeholder.clone()
17801    }
17802
17803    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17804        self.buffer.update(cx, |buffer, cx| {
17805            buffer.set_all_diff_hunks_expanded(cx);
17806        });
17807    }
17808
17809    pub fn expand_all_diff_hunks(
17810        &mut self,
17811        _: &ExpandAllDiffHunks,
17812        _window: &mut Window,
17813        cx: &mut Context<Self>,
17814    ) {
17815        self.buffer.update(cx, |buffer, cx| {
17816            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17817        });
17818    }
17819
17820    pub fn toggle_selected_diff_hunks(
17821        &mut self,
17822        _: &ToggleSelectedDiffHunks,
17823        _window: &mut Window,
17824        cx: &mut Context<Self>,
17825    ) {
17826        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17827        self.toggle_diff_hunks_in_ranges(ranges, cx);
17828    }
17829
17830    pub fn diff_hunks_in_ranges<'a>(
17831        &'a self,
17832        ranges: &'a [Range<Anchor>],
17833        buffer: &'a MultiBufferSnapshot,
17834    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17835        ranges.iter().flat_map(move |range| {
17836            let end_excerpt_id = range.end.excerpt_id;
17837            let range = range.to_point(buffer);
17838            let mut peek_end = range.end;
17839            if range.end.row < buffer.max_row().0 {
17840                peek_end = Point::new(range.end.row + 1, 0);
17841            }
17842            buffer
17843                .diff_hunks_in_range(range.start..peek_end)
17844                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17845        })
17846    }
17847
17848    pub fn has_stageable_diff_hunks_in_ranges(
17849        &self,
17850        ranges: &[Range<Anchor>],
17851        snapshot: &MultiBufferSnapshot,
17852    ) -> bool {
17853        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17854        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17855    }
17856
17857    pub fn toggle_staged_selected_diff_hunks(
17858        &mut self,
17859        _: &::git::ToggleStaged,
17860        _: &mut Window,
17861        cx: &mut Context<Self>,
17862    ) {
17863        let snapshot = self.buffer.read(cx).snapshot(cx);
17864        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17865        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17866        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17867    }
17868
17869    pub fn set_render_diff_hunk_controls(
17870        &mut self,
17871        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17872        cx: &mut Context<Self>,
17873    ) {
17874        self.render_diff_hunk_controls = render_diff_hunk_controls;
17875        cx.notify();
17876    }
17877
17878    pub fn stage_and_next(
17879        &mut self,
17880        _: &::git::StageAndNext,
17881        window: &mut Window,
17882        cx: &mut Context<Self>,
17883    ) {
17884        self.do_stage_or_unstage_and_next(true, window, cx);
17885    }
17886
17887    pub fn unstage_and_next(
17888        &mut self,
17889        _: &::git::UnstageAndNext,
17890        window: &mut Window,
17891        cx: &mut Context<Self>,
17892    ) {
17893        self.do_stage_or_unstage_and_next(false, window, cx);
17894    }
17895
17896    pub fn stage_or_unstage_diff_hunks(
17897        &mut self,
17898        stage: bool,
17899        ranges: Vec<Range<Anchor>>,
17900        cx: &mut Context<Self>,
17901    ) {
17902        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17903        cx.spawn(async move |this, cx| {
17904            task.await?;
17905            this.update(cx, |this, cx| {
17906                let snapshot = this.buffer.read(cx).snapshot(cx);
17907                let chunk_by = this
17908                    .diff_hunks_in_ranges(&ranges, &snapshot)
17909                    .chunk_by(|hunk| hunk.buffer_id);
17910                for (buffer_id, hunks) in &chunk_by {
17911                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17912                }
17913            })
17914        })
17915        .detach_and_log_err(cx);
17916    }
17917
17918    fn save_buffers_for_ranges_if_needed(
17919        &mut self,
17920        ranges: &[Range<Anchor>],
17921        cx: &mut Context<Editor>,
17922    ) -> Task<Result<()>> {
17923        let multibuffer = self.buffer.read(cx);
17924        let snapshot = multibuffer.read(cx);
17925        let buffer_ids: HashSet<_> = ranges
17926            .iter()
17927            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17928            .collect();
17929        drop(snapshot);
17930
17931        let mut buffers = HashSet::default();
17932        for buffer_id in buffer_ids {
17933            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17934                let buffer = buffer_entity.read(cx);
17935                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17936                {
17937                    buffers.insert(buffer_entity);
17938                }
17939            }
17940        }
17941
17942        if let Some(project) = &self.project {
17943            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17944        } else {
17945            Task::ready(Ok(()))
17946        }
17947    }
17948
17949    fn do_stage_or_unstage_and_next(
17950        &mut self,
17951        stage: bool,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17956
17957        if ranges.iter().any(|range| range.start != range.end) {
17958            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17959            return;
17960        }
17961
17962        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17963        let snapshot = self.snapshot(window, cx);
17964        let position = self.selections.newest::<Point>(cx).head();
17965        let mut row = snapshot
17966            .buffer_snapshot
17967            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17968            .find(|hunk| hunk.row_range.start.0 > position.row)
17969            .map(|hunk| hunk.row_range.start);
17970
17971        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17972        // Outside of the project diff editor, wrap around to the beginning.
17973        if !all_diff_hunks_expanded {
17974            row = row.or_else(|| {
17975                snapshot
17976                    .buffer_snapshot
17977                    .diff_hunks_in_range(Point::zero()..position)
17978                    .find(|hunk| hunk.row_range.end.0 < position.row)
17979                    .map(|hunk| hunk.row_range.start)
17980            });
17981        }
17982
17983        if let Some(row) = row {
17984            let destination = Point::new(row.0, 0);
17985            let autoscroll = Autoscroll::center();
17986
17987            self.unfold_ranges(&[destination..destination], false, false, cx);
17988            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17989                s.select_ranges([destination..destination]);
17990            });
17991        }
17992    }
17993
17994    fn do_stage_or_unstage(
17995        &self,
17996        stage: bool,
17997        buffer_id: BufferId,
17998        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17999        cx: &mut App,
18000    ) -> Option<()> {
18001        let project = self.project()?;
18002        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18003        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18004        let buffer_snapshot = buffer.read(cx).snapshot();
18005        let file_exists = buffer_snapshot
18006            .file()
18007            .is_some_and(|file| file.disk_state().exists());
18008        diff.update(cx, |diff, cx| {
18009            diff.stage_or_unstage_hunks(
18010                stage,
18011                &hunks
18012                    .map(|hunk| buffer_diff::DiffHunk {
18013                        buffer_range: hunk.buffer_range,
18014                        diff_base_byte_range: hunk.diff_base_byte_range,
18015                        secondary_status: hunk.secondary_status,
18016                        range: Point::zero()..Point::zero(), // unused
18017                    })
18018                    .collect::<Vec<_>>(),
18019                &buffer_snapshot,
18020                file_exists,
18021                cx,
18022            )
18023        });
18024        None
18025    }
18026
18027    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18028        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18029        self.buffer
18030            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18031    }
18032
18033    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18034        self.buffer.update(cx, |buffer, cx| {
18035            let ranges = vec![Anchor::min()..Anchor::max()];
18036            if !buffer.all_diff_hunks_expanded()
18037                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18038            {
18039                buffer.collapse_diff_hunks(ranges, cx);
18040                true
18041            } else {
18042                false
18043            }
18044        })
18045    }
18046
18047    fn toggle_diff_hunks_in_ranges(
18048        &mut self,
18049        ranges: Vec<Range<Anchor>>,
18050        cx: &mut Context<Editor>,
18051    ) {
18052        self.buffer.update(cx, |buffer, cx| {
18053            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18054            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18055        })
18056    }
18057
18058    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18059        self.buffer.update(cx, |buffer, cx| {
18060            let snapshot = buffer.snapshot(cx);
18061            let excerpt_id = range.end.excerpt_id;
18062            let point_range = range.to_point(&snapshot);
18063            let expand = !buffer.single_hunk_is_expanded(range, cx);
18064            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18065        })
18066    }
18067
18068    pub(crate) fn apply_all_diff_hunks(
18069        &mut self,
18070        _: &ApplyAllDiffHunks,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18075
18076        let buffers = self.buffer.read(cx).all_buffers();
18077        for branch_buffer in buffers {
18078            branch_buffer.update(cx, |branch_buffer, cx| {
18079                branch_buffer.merge_into_base(Vec::new(), cx);
18080            });
18081        }
18082
18083        if let Some(project) = self.project.clone() {
18084            self.save(
18085                SaveOptions {
18086                    format: true,
18087                    autosave: false,
18088                },
18089                project,
18090                window,
18091                cx,
18092            )
18093            .detach_and_log_err(cx);
18094        }
18095    }
18096
18097    pub(crate) fn apply_selected_diff_hunks(
18098        &mut self,
18099        _: &ApplyDiffHunk,
18100        window: &mut Window,
18101        cx: &mut Context<Self>,
18102    ) {
18103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18104        let snapshot = self.snapshot(window, cx);
18105        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18106        let mut ranges_by_buffer = HashMap::default();
18107        self.transact(window, cx, |editor, _window, cx| {
18108            for hunk in hunks {
18109                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18110                    ranges_by_buffer
18111                        .entry(buffer.clone())
18112                        .or_insert_with(Vec::new)
18113                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18114                }
18115            }
18116
18117            for (buffer, ranges) in ranges_by_buffer {
18118                buffer.update(cx, |buffer, cx| {
18119                    buffer.merge_into_base(ranges, cx);
18120                });
18121            }
18122        });
18123
18124        if let Some(project) = self.project.clone() {
18125            self.save(
18126                SaveOptions {
18127                    format: true,
18128                    autosave: false,
18129                },
18130                project,
18131                window,
18132                cx,
18133            )
18134            .detach_and_log_err(cx);
18135        }
18136    }
18137
18138    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18139        if hovered != self.gutter_hovered {
18140            self.gutter_hovered = hovered;
18141            cx.notify();
18142        }
18143    }
18144
18145    pub fn insert_blocks(
18146        &mut self,
18147        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18148        autoscroll: Option<Autoscroll>,
18149        cx: &mut Context<Self>,
18150    ) -> Vec<CustomBlockId> {
18151        let blocks = self
18152            .display_map
18153            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18154        if let Some(autoscroll) = autoscroll {
18155            self.request_autoscroll(autoscroll, cx);
18156        }
18157        cx.notify();
18158        blocks
18159    }
18160
18161    pub fn resize_blocks(
18162        &mut self,
18163        heights: HashMap<CustomBlockId, u32>,
18164        autoscroll: Option<Autoscroll>,
18165        cx: &mut Context<Self>,
18166    ) {
18167        self.display_map
18168            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18169        if let Some(autoscroll) = autoscroll {
18170            self.request_autoscroll(autoscroll, cx);
18171        }
18172        cx.notify();
18173    }
18174
18175    pub fn replace_blocks(
18176        &mut self,
18177        renderers: HashMap<CustomBlockId, RenderBlock>,
18178        autoscroll: Option<Autoscroll>,
18179        cx: &mut Context<Self>,
18180    ) {
18181        self.display_map
18182            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18183        if let Some(autoscroll) = autoscroll {
18184            self.request_autoscroll(autoscroll, cx);
18185        }
18186        cx.notify();
18187    }
18188
18189    pub fn remove_blocks(
18190        &mut self,
18191        block_ids: HashSet<CustomBlockId>,
18192        autoscroll: Option<Autoscroll>,
18193        cx: &mut Context<Self>,
18194    ) {
18195        self.display_map.update(cx, |display_map, cx| {
18196            display_map.remove_blocks(block_ids, cx)
18197        });
18198        if let Some(autoscroll) = autoscroll {
18199            self.request_autoscroll(autoscroll, cx);
18200        }
18201        cx.notify();
18202    }
18203
18204    pub fn row_for_block(
18205        &self,
18206        block_id: CustomBlockId,
18207        cx: &mut Context<Self>,
18208    ) -> Option<DisplayRow> {
18209        self.display_map
18210            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18211    }
18212
18213    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18214        self.focused_block = Some(focused_block);
18215    }
18216
18217    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18218        self.focused_block.take()
18219    }
18220
18221    pub fn insert_creases(
18222        &mut self,
18223        creases: impl IntoIterator<Item = Crease<Anchor>>,
18224        cx: &mut Context<Self>,
18225    ) -> Vec<CreaseId> {
18226        self.display_map
18227            .update(cx, |map, cx| map.insert_creases(creases, cx))
18228    }
18229
18230    pub fn remove_creases(
18231        &mut self,
18232        ids: impl IntoIterator<Item = CreaseId>,
18233        cx: &mut Context<Self>,
18234    ) -> Vec<(CreaseId, Range<Anchor>)> {
18235        self.display_map
18236            .update(cx, |map, cx| map.remove_creases(ids, cx))
18237    }
18238
18239    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18240        self.display_map
18241            .update(cx, |map, cx| map.snapshot(cx))
18242            .longest_row()
18243    }
18244
18245    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18246        self.display_map
18247            .update(cx, |map, cx| map.snapshot(cx))
18248            .max_point()
18249    }
18250
18251    pub fn text(&self, cx: &App) -> String {
18252        self.buffer.read(cx).read(cx).text()
18253    }
18254
18255    pub fn is_empty(&self, cx: &App) -> bool {
18256        self.buffer.read(cx).read(cx).is_empty()
18257    }
18258
18259    pub fn text_option(&self, cx: &App) -> Option<String> {
18260        let text = self.text(cx);
18261        let text = text.trim();
18262
18263        if text.is_empty() {
18264            return None;
18265        }
18266
18267        Some(text.to_string())
18268    }
18269
18270    pub fn set_text(
18271        &mut self,
18272        text: impl Into<Arc<str>>,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) {
18276        self.transact(window, cx, |this, _, cx| {
18277            this.buffer
18278                .read(cx)
18279                .as_singleton()
18280                .expect("you can only call set_text on editors for singleton buffers")
18281                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18282        });
18283    }
18284
18285    pub fn display_text(&self, cx: &mut App) -> String {
18286        self.display_map
18287            .update(cx, |map, cx| map.snapshot(cx))
18288            .text()
18289    }
18290
18291    fn create_minimap(
18292        &self,
18293        minimap_settings: MinimapSettings,
18294        window: &mut Window,
18295        cx: &mut Context<Self>,
18296    ) -> Option<Entity<Self>> {
18297        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18298            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18299    }
18300
18301    fn initialize_new_minimap(
18302        &self,
18303        minimap_settings: MinimapSettings,
18304        window: &mut Window,
18305        cx: &mut Context<Self>,
18306    ) -> Entity<Self> {
18307        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18308
18309        let mut minimap = Editor::new_internal(
18310            EditorMode::Minimap {
18311                parent: cx.weak_entity(),
18312            },
18313            self.buffer.clone(),
18314            None,
18315            Some(self.display_map.clone()),
18316            window,
18317            cx,
18318        );
18319        minimap.scroll_manager.clone_state(&self.scroll_manager);
18320        minimap.set_text_style_refinement(TextStyleRefinement {
18321            font_size: Some(MINIMAP_FONT_SIZE),
18322            font_weight: Some(MINIMAP_FONT_WEIGHT),
18323            ..Default::default()
18324        });
18325        minimap.update_minimap_configuration(minimap_settings, cx);
18326        cx.new(|_| minimap)
18327    }
18328
18329    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18330        let current_line_highlight = minimap_settings
18331            .current_line_highlight
18332            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18333        self.set_current_line_highlight(Some(current_line_highlight));
18334    }
18335
18336    pub fn minimap(&self) -> Option<&Entity<Self>> {
18337        self.minimap
18338            .as_ref()
18339            .filter(|_| self.minimap_visibility.visible())
18340    }
18341
18342    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18343        let mut wrap_guides = smallvec![];
18344
18345        if self.show_wrap_guides == Some(false) {
18346            return wrap_guides;
18347        }
18348
18349        let settings = self.buffer.read(cx).language_settings(cx);
18350        if settings.show_wrap_guides {
18351            match self.soft_wrap_mode(cx) {
18352                SoftWrap::Column(soft_wrap) => {
18353                    wrap_guides.push((soft_wrap as usize, true));
18354                }
18355                SoftWrap::Bounded(soft_wrap) => {
18356                    wrap_guides.push((soft_wrap as usize, true));
18357                }
18358                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18359            }
18360            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18361        }
18362
18363        wrap_guides
18364    }
18365
18366    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18367        let settings = self.buffer.read(cx).language_settings(cx);
18368        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18369        match mode {
18370            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18371                SoftWrap::None
18372            }
18373            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18374            language_settings::SoftWrap::PreferredLineLength => {
18375                SoftWrap::Column(settings.preferred_line_length)
18376            }
18377            language_settings::SoftWrap::Bounded => {
18378                SoftWrap::Bounded(settings.preferred_line_length)
18379            }
18380        }
18381    }
18382
18383    pub fn set_soft_wrap_mode(
18384        &mut self,
18385        mode: language_settings::SoftWrap,
18386
18387        cx: &mut Context<Self>,
18388    ) {
18389        self.soft_wrap_mode_override = Some(mode);
18390        cx.notify();
18391    }
18392
18393    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18394        self.hard_wrap = hard_wrap;
18395        cx.notify();
18396    }
18397
18398    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18399        self.text_style_refinement = Some(style);
18400    }
18401
18402    /// called by the Element so we know what style we were most recently rendered with.
18403    pub(crate) fn set_style(
18404        &mut self,
18405        style: EditorStyle,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408    ) {
18409        // We intentionally do not inform the display map about the minimap style
18410        // so that wrapping is not recalculated and stays consistent for the editor
18411        // and its linked minimap.
18412        if !self.mode.is_minimap() {
18413            let rem_size = window.rem_size();
18414            self.display_map.update(cx, |map, cx| {
18415                map.set_font(
18416                    style.text.font(),
18417                    style.text.font_size.to_pixels(rem_size),
18418                    cx,
18419                )
18420            });
18421        }
18422        self.style = Some(style);
18423    }
18424
18425    pub fn style(&self) -> Option<&EditorStyle> {
18426        self.style.as_ref()
18427    }
18428
18429    // Called by the element. This method is not designed to be called outside of the editor
18430    // element's layout code because it does not notify when rewrapping is computed synchronously.
18431    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18432        self.display_map
18433            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18434    }
18435
18436    pub fn set_soft_wrap(&mut self) {
18437        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18438    }
18439
18440    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18441        if self.soft_wrap_mode_override.is_some() {
18442            self.soft_wrap_mode_override.take();
18443        } else {
18444            let soft_wrap = match self.soft_wrap_mode(cx) {
18445                SoftWrap::GitDiff => return,
18446                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18447                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18448                    language_settings::SoftWrap::None
18449                }
18450            };
18451            self.soft_wrap_mode_override = Some(soft_wrap);
18452        }
18453        cx.notify();
18454    }
18455
18456    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18457        let Some(workspace) = self.workspace() else {
18458            return;
18459        };
18460        let fs = workspace.read(cx).app_state().fs.clone();
18461        let current_show = TabBarSettings::get_global(cx).show;
18462        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18463            setting.show = Some(!current_show);
18464        });
18465    }
18466
18467    pub fn toggle_indent_guides(
18468        &mut self,
18469        _: &ToggleIndentGuides,
18470        _: &mut Window,
18471        cx: &mut Context<Self>,
18472    ) {
18473        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18474            self.buffer
18475                .read(cx)
18476                .language_settings(cx)
18477                .indent_guides
18478                .enabled
18479        });
18480        self.show_indent_guides = Some(!currently_enabled);
18481        cx.notify();
18482    }
18483
18484    fn should_show_indent_guides(&self) -> Option<bool> {
18485        self.show_indent_guides
18486    }
18487
18488    pub fn toggle_line_numbers(
18489        &mut self,
18490        _: &ToggleLineNumbers,
18491        _: &mut Window,
18492        cx: &mut Context<Self>,
18493    ) {
18494        let mut editor_settings = EditorSettings::get_global(cx).clone();
18495        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18496        EditorSettings::override_global(editor_settings, cx);
18497    }
18498
18499    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18500        if let Some(show_line_numbers) = self.show_line_numbers {
18501            return show_line_numbers;
18502        }
18503        EditorSettings::get_global(cx).gutter.line_numbers
18504    }
18505
18506    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18507        self.use_relative_line_numbers
18508            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18509    }
18510
18511    pub fn toggle_relative_line_numbers(
18512        &mut self,
18513        _: &ToggleRelativeLineNumbers,
18514        _: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        let is_relative = self.should_use_relative_line_numbers(cx);
18518        self.set_relative_line_number(Some(!is_relative), cx)
18519    }
18520
18521    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18522        self.use_relative_line_numbers = is_relative;
18523        cx.notify();
18524    }
18525
18526    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18527        self.show_gutter = show_gutter;
18528        cx.notify();
18529    }
18530
18531    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18532        self.show_scrollbars = ScrollbarAxes {
18533            horizontal: show,
18534            vertical: show,
18535        };
18536        cx.notify();
18537    }
18538
18539    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18540        self.show_scrollbars.vertical = show;
18541        cx.notify();
18542    }
18543
18544    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18545        self.show_scrollbars.horizontal = show;
18546        cx.notify();
18547    }
18548
18549    pub fn set_minimap_visibility(
18550        &mut self,
18551        minimap_visibility: MinimapVisibility,
18552        window: &mut Window,
18553        cx: &mut Context<Self>,
18554    ) {
18555        if self.minimap_visibility != minimap_visibility {
18556            if minimap_visibility.visible() && self.minimap.is_none() {
18557                let minimap_settings = EditorSettings::get_global(cx).minimap;
18558                self.minimap =
18559                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18560            }
18561            self.minimap_visibility = minimap_visibility;
18562            cx.notify();
18563        }
18564    }
18565
18566    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18567        self.set_show_scrollbars(false, cx);
18568        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18569    }
18570
18571    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18572        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18573    }
18574
18575    /// Normally the text in full mode and auto height editors is padded on the
18576    /// left side by roughly half a character width for improved hit testing.
18577    ///
18578    /// Use this method to disable this for cases where this is not wanted (e.g.
18579    /// if you want to align the editor text with some other text above or below)
18580    /// or if you want to add this padding to single-line editors.
18581    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18582        self.offset_content = offset_content;
18583        cx.notify();
18584    }
18585
18586    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18587        self.show_line_numbers = Some(show_line_numbers);
18588        cx.notify();
18589    }
18590
18591    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18592        self.disable_expand_excerpt_buttons = true;
18593        cx.notify();
18594    }
18595
18596    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18597        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18598        cx.notify();
18599    }
18600
18601    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18602        self.show_code_actions = Some(show_code_actions);
18603        cx.notify();
18604    }
18605
18606    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18607        self.show_runnables = Some(show_runnables);
18608        cx.notify();
18609    }
18610
18611    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18612        self.show_breakpoints = Some(show_breakpoints);
18613        cx.notify();
18614    }
18615
18616    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18617        if self.display_map.read(cx).masked != masked {
18618            self.display_map.update(cx, |map, _| map.masked = masked);
18619        }
18620        cx.notify()
18621    }
18622
18623    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18624        self.show_wrap_guides = Some(show_wrap_guides);
18625        cx.notify();
18626    }
18627
18628    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18629        self.show_indent_guides = Some(show_indent_guides);
18630        cx.notify();
18631    }
18632
18633    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18634        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18635            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18636                && let Some(dir) = file.abs_path(cx).parent()
18637            {
18638                return Some(dir.to_owned());
18639            }
18640
18641            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18642                return Some(project_path.path.to_path_buf());
18643            }
18644        }
18645
18646        None
18647    }
18648
18649    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18650        self.active_excerpt(cx)?
18651            .1
18652            .read(cx)
18653            .file()
18654            .and_then(|f| f.as_local())
18655    }
18656
18657    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18658        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18659            let buffer = buffer.read(cx);
18660            if let Some(project_path) = buffer.project_path(cx) {
18661                let project = self.project()?.read(cx);
18662                project.absolute_path(&project_path, cx)
18663            } else {
18664                buffer
18665                    .file()
18666                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18667            }
18668        })
18669    }
18670
18671    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18672        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18673            let project_path = buffer.read(cx).project_path(cx)?;
18674            let project = self.project()?.read(cx);
18675            let entry = project.entry_for_path(&project_path, cx)?;
18676            let path = entry.path.to_path_buf();
18677            Some(path)
18678        })
18679    }
18680
18681    pub fn reveal_in_finder(
18682        &mut self,
18683        _: &RevealInFileManager,
18684        _window: &mut Window,
18685        cx: &mut Context<Self>,
18686    ) {
18687        if let Some(target) = self.target_file(cx) {
18688            cx.reveal_path(&target.abs_path(cx));
18689        }
18690    }
18691
18692    pub fn copy_path(
18693        &mut self,
18694        _: &zed_actions::workspace::CopyPath,
18695        _window: &mut Window,
18696        cx: &mut Context<Self>,
18697    ) {
18698        if let Some(path) = self.target_file_abs_path(cx)
18699            && let Some(path) = path.to_str()
18700        {
18701            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18702        }
18703    }
18704
18705    pub fn copy_relative_path(
18706        &mut self,
18707        _: &zed_actions::workspace::CopyRelativePath,
18708        _window: &mut Window,
18709        cx: &mut Context<Self>,
18710    ) {
18711        if let Some(path) = self.target_file_path(cx)
18712            && let Some(path) = path.to_str()
18713        {
18714            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18715        }
18716    }
18717
18718    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18719        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18720            buffer.read(cx).project_path(cx)
18721        } else {
18722            None
18723        }
18724    }
18725
18726    // Returns true if the editor handled a go-to-line request
18727    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18728        maybe!({
18729            let breakpoint_store = self.breakpoint_store.as_ref()?;
18730
18731            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18732            else {
18733                self.clear_row_highlights::<ActiveDebugLine>();
18734                return None;
18735            };
18736
18737            let position = active_stack_frame.position;
18738            let buffer_id = position.buffer_id?;
18739            let snapshot = self
18740                .project
18741                .as_ref()?
18742                .read(cx)
18743                .buffer_for_id(buffer_id, cx)?
18744                .read(cx)
18745                .snapshot();
18746
18747            let mut handled = false;
18748            for (id, ExcerptRange { context, .. }) in
18749                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18750            {
18751                if context.start.cmp(&position, &snapshot).is_ge()
18752                    || context.end.cmp(&position, &snapshot).is_lt()
18753                {
18754                    continue;
18755                }
18756                let snapshot = self.buffer.read(cx).snapshot(cx);
18757                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18758
18759                handled = true;
18760                self.clear_row_highlights::<ActiveDebugLine>();
18761
18762                self.go_to_line::<ActiveDebugLine>(
18763                    multibuffer_anchor,
18764                    Some(cx.theme().colors().editor_debugger_active_line_background),
18765                    window,
18766                    cx,
18767                );
18768
18769                cx.notify();
18770            }
18771
18772            handled.then_some(())
18773        })
18774        .is_some()
18775    }
18776
18777    pub fn copy_file_name_without_extension(
18778        &mut self,
18779        _: &CopyFileNameWithoutExtension,
18780        _: &mut Window,
18781        cx: &mut Context<Self>,
18782    ) {
18783        if let Some(file) = self.target_file(cx)
18784            && let Some(file_stem) = file.path().file_stem()
18785            && let Some(name) = file_stem.to_str()
18786        {
18787            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18788        }
18789    }
18790
18791    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18792        if let Some(file) = self.target_file(cx)
18793            && let Some(file_name) = file.path().file_name()
18794            && let Some(name) = file_name.to_str()
18795        {
18796            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18797        }
18798    }
18799
18800    pub fn toggle_git_blame(
18801        &mut self,
18802        _: &::git::Blame,
18803        window: &mut Window,
18804        cx: &mut Context<Self>,
18805    ) {
18806        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18807
18808        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18809            self.start_git_blame(true, window, cx);
18810        }
18811
18812        cx.notify();
18813    }
18814
18815    pub fn toggle_git_blame_inline(
18816        &mut self,
18817        _: &ToggleGitBlameInline,
18818        window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.toggle_git_blame_inline_internal(true, window, cx);
18822        cx.notify();
18823    }
18824
18825    pub fn open_git_blame_commit(
18826        &mut self,
18827        _: &OpenGitBlameCommit,
18828        window: &mut Window,
18829        cx: &mut Context<Self>,
18830    ) {
18831        self.open_git_blame_commit_internal(window, cx);
18832    }
18833
18834    fn open_git_blame_commit_internal(
18835        &mut self,
18836        window: &mut Window,
18837        cx: &mut Context<Self>,
18838    ) -> Option<()> {
18839        let blame = self.blame.as_ref()?;
18840        let snapshot = self.snapshot(window, cx);
18841        let cursor = self.selections.newest::<Point>(cx).head();
18842        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18843        let blame_entry = blame
18844            .update(cx, |blame, cx| {
18845                blame
18846                    .blame_for_rows(
18847                        &[RowInfo {
18848                            buffer_id: Some(buffer.remote_id()),
18849                            buffer_row: Some(point.row),
18850                            ..Default::default()
18851                        }],
18852                        cx,
18853                    )
18854                    .next()
18855            })
18856            .flatten()?;
18857        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18858        let repo = blame.read(cx).repository(cx)?;
18859        let workspace = self.workspace()?.downgrade();
18860        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18861        None
18862    }
18863
18864    pub fn git_blame_inline_enabled(&self) -> bool {
18865        self.git_blame_inline_enabled
18866    }
18867
18868    pub fn toggle_selection_menu(
18869        &mut self,
18870        _: &ToggleSelectionMenu,
18871        _: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        self.show_selection_menu = self
18875            .show_selection_menu
18876            .map(|show_selections_menu| !show_selections_menu)
18877            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18878
18879        cx.notify();
18880    }
18881
18882    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18883        self.show_selection_menu
18884            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18885    }
18886
18887    fn start_git_blame(
18888        &mut self,
18889        user_triggered: bool,
18890        window: &mut Window,
18891        cx: &mut Context<Self>,
18892    ) {
18893        if let Some(project) = self.project() {
18894            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18895                return;
18896            };
18897
18898            if buffer.read(cx).file().is_none() {
18899                return;
18900            }
18901
18902            let focused = self.focus_handle(cx).contains_focused(window, cx);
18903
18904            let project = project.clone();
18905            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18906            self.blame_subscription =
18907                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18908            self.blame = Some(blame);
18909        }
18910    }
18911
18912    fn toggle_git_blame_inline_internal(
18913        &mut self,
18914        user_triggered: bool,
18915        window: &mut Window,
18916        cx: &mut Context<Self>,
18917    ) {
18918        if self.git_blame_inline_enabled {
18919            self.git_blame_inline_enabled = false;
18920            self.show_git_blame_inline = false;
18921            self.show_git_blame_inline_delay_task.take();
18922        } else {
18923            self.git_blame_inline_enabled = true;
18924            self.start_git_blame_inline(user_triggered, window, cx);
18925        }
18926
18927        cx.notify();
18928    }
18929
18930    fn start_git_blame_inline(
18931        &mut self,
18932        user_triggered: bool,
18933        window: &mut Window,
18934        cx: &mut Context<Self>,
18935    ) {
18936        self.start_git_blame(user_triggered, window, cx);
18937
18938        if ProjectSettings::get_global(cx)
18939            .git
18940            .inline_blame_delay()
18941            .is_some()
18942        {
18943            self.start_inline_blame_timer(window, cx);
18944        } else {
18945            self.show_git_blame_inline = true
18946        }
18947    }
18948
18949    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18950        self.blame.as_ref()
18951    }
18952
18953    pub fn show_git_blame_gutter(&self) -> bool {
18954        self.show_git_blame_gutter
18955    }
18956
18957    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18958        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18959    }
18960
18961    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18962        self.show_git_blame_inline
18963            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18964            && !self.newest_selection_head_on_empty_line(cx)
18965            && self.has_blame_entries(cx)
18966    }
18967
18968    fn has_blame_entries(&self, cx: &App) -> bool {
18969        self.blame()
18970            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18971    }
18972
18973    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18974        let cursor_anchor = self.selections.newest_anchor().head();
18975
18976        let snapshot = self.buffer.read(cx).snapshot(cx);
18977        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18978
18979        snapshot.line_len(buffer_row) == 0
18980    }
18981
18982    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18983        let buffer_and_selection = maybe!({
18984            let selection = self.selections.newest::<Point>(cx);
18985            let selection_range = selection.range();
18986
18987            let multi_buffer = self.buffer().read(cx);
18988            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18989            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18990
18991            let (buffer, range, _) = if selection.reversed {
18992                buffer_ranges.first()
18993            } else {
18994                buffer_ranges.last()
18995            }?;
18996
18997            let selection = text::ToPoint::to_point(&range.start, buffer).row
18998                ..text::ToPoint::to_point(&range.end, buffer).row;
18999            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19000        });
19001
19002        let Some((buffer, selection)) = buffer_and_selection else {
19003            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19004        };
19005
19006        let Some(project) = self.project() else {
19007            return Task::ready(Err(anyhow!("editor does not have project")));
19008        };
19009
19010        project.update(cx, |project, cx| {
19011            project.get_permalink_to_line(&buffer, selection, cx)
19012        })
19013    }
19014
19015    pub fn copy_permalink_to_line(
19016        &mut self,
19017        _: &CopyPermalinkToLine,
19018        window: &mut Window,
19019        cx: &mut Context<Self>,
19020    ) {
19021        let permalink_task = self.get_permalink_to_line(cx);
19022        let workspace = self.workspace();
19023
19024        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19025            Ok(permalink) => {
19026                cx.update(|_, cx| {
19027                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19028                })
19029                .ok();
19030            }
19031            Err(err) => {
19032                let message = format!("Failed to copy permalink: {err}");
19033
19034                anyhow::Result::<()>::Err(err).log_err();
19035
19036                if let Some(workspace) = workspace {
19037                    workspace
19038                        .update_in(cx, |workspace, _, cx| {
19039                            struct CopyPermalinkToLine;
19040
19041                            workspace.show_toast(
19042                                Toast::new(
19043                                    NotificationId::unique::<CopyPermalinkToLine>(),
19044                                    message,
19045                                ),
19046                                cx,
19047                            )
19048                        })
19049                        .ok();
19050                }
19051            }
19052        })
19053        .detach();
19054    }
19055
19056    pub fn copy_file_location(
19057        &mut self,
19058        _: &CopyFileLocation,
19059        _: &mut Window,
19060        cx: &mut Context<Self>,
19061    ) {
19062        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19063        if let Some(file) = self.target_file(cx)
19064            && let Some(path) = file.path().to_str()
19065        {
19066            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19067        }
19068    }
19069
19070    pub fn open_permalink_to_line(
19071        &mut self,
19072        _: &OpenPermalinkToLine,
19073        window: &mut Window,
19074        cx: &mut Context<Self>,
19075    ) {
19076        let permalink_task = self.get_permalink_to_line(cx);
19077        let workspace = self.workspace();
19078
19079        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19080            Ok(permalink) => {
19081                cx.update(|_, cx| {
19082                    cx.open_url(permalink.as_ref());
19083                })
19084                .ok();
19085            }
19086            Err(err) => {
19087                let message = format!("Failed to open permalink: {err}");
19088
19089                anyhow::Result::<()>::Err(err).log_err();
19090
19091                if let Some(workspace) = workspace {
19092                    workspace
19093                        .update(cx, |workspace, cx| {
19094                            struct OpenPermalinkToLine;
19095
19096                            workspace.show_toast(
19097                                Toast::new(
19098                                    NotificationId::unique::<OpenPermalinkToLine>(),
19099                                    message,
19100                                ),
19101                                cx,
19102                            )
19103                        })
19104                        .ok();
19105                }
19106            }
19107        })
19108        .detach();
19109    }
19110
19111    pub fn insert_uuid_v4(
19112        &mut self,
19113        _: &InsertUuidV4,
19114        window: &mut Window,
19115        cx: &mut Context<Self>,
19116    ) {
19117        self.insert_uuid(UuidVersion::V4, window, cx);
19118    }
19119
19120    pub fn insert_uuid_v7(
19121        &mut self,
19122        _: &InsertUuidV7,
19123        window: &mut Window,
19124        cx: &mut Context<Self>,
19125    ) {
19126        self.insert_uuid(UuidVersion::V7, window, cx);
19127    }
19128
19129    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19130        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19131        self.transact(window, cx, |this, window, cx| {
19132            let edits = this
19133                .selections
19134                .all::<Point>(cx)
19135                .into_iter()
19136                .map(|selection| {
19137                    let uuid = match version {
19138                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19139                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19140                    };
19141
19142                    (selection.range(), uuid.to_string())
19143                });
19144            this.edit(edits, cx);
19145            this.refresh_edit_prediction(true, false, window, cx);
19146        });
19147    }
19148
19149    pub fn open_selections_in_multibuffer(
19150        &mut self,
19151        _: &OpenSelectionsInMultibuffer,
19152        window: &mut Window,
19153        cx: &mut Context<Self>,
19154    ) {
19155        let multibuffer = self.buffer.read(cx);
19156
19157        let Some(buffer) = multibuffer.as_singleton() else {
19158            return;
19159        };
19160
19161        let Some(workspace) = self.workspace() else {
19162            return;
19163        };
19164
19165        let title = multibuffer.title(cx).to_string();
19166
19167        let locations = self
19168            .selections
19169            .all_anchors(cx)
19170            .iter()
19171            .map(|selection| Location {
19172                buffer: buffer.clone(),
19173                range: selection.start.text_anchor..selection.end.text_anchor,
19174            })
19175            .collect::<Vec<_>>();
19176
19177        cx.spawn_in(window, async move |_, cx| {
19178            workspace.update_in(cx, |workspace, window, cx| {
19179                Self::open_locations_in_multibuffer(
19180                    workspace,
19181                    locations,
19182                    format!("Selections for '{title}'"),
19183                    false,
19184                    MultibufferSelectionMode::All,
19185                    window,
19186                    cx,
19187                );
19188            })
19189        })
19190        .detach();
19191    }
19192
19193    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19194    /// last highlight added will be used.
19195    ///
19196    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19197    pub fn highlight_rows<T: 'static>(
19198        &mut self,
19199        range: Range<Anchor>,
19200        color: Hsla,
19201        options: RowHighlightOptions,
19202        cx: &mut Context<Self>,
19203    ) {
19204        let snapshot = self.buffer().read(cx).snapshot(cx);
19205        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19206        let ix = row_highlights.binary_search_by(|highlight| {
19207            Ordering::Equal
19208                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19209                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19210        });
19211
19212        if let Err(mut ix) = ix {
19213            let index = post_inc(&mut self.highlight_order);
19214
19215            // If this range intersects with the preceding highlight, then merge it with
19216            // the preceding highlight. Otherwise insert a new highlight.
19217            let mut merged = false;
19218            if ix > 0 {
19219                let prev_highlight = &mut row_highlights[ix - 1];
19220                if prev_highlight
19221                    .range
19222                    .end
19223                    .cmp(&range.start, &snapshot)
19224                    .is_ge()
19225                {
19226                    ix -= 1;
19227                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19228                        prev_highlight.range.end = range.end;
19229                    }
19230                    merged = true;
19231                    prev_highlight.index = index;
19232                    prev_highlight.color = color;
19233                    prev_highlight.options = options;
19234                }
19235            }
19236
19237            if !merged {
19238                row_highlights.insert(
19239                    ix,
19240                    RowHighlight {
19241                        range,
19242                        index,
19243                        color,
19244                        options,
19245                        type_id: TypeId::of::<T>(),
19246                    },
19247                );
19248            }
19249
19250            // If any of the following highlights intersect with this one, merge them.
19251            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19252                let highlight = &row_highlights[ix];
19253                if next_highlight
19254                    .range
19255                    .start
19256                    .cmp(&highlight.range.end, &snapshot)
19257                    .is_le()
19258                {
19259                    if next_highlight
19260                        .range
19261                        .end
19262                        .cmp(&highlight.range.end, &snapshot)
19263                        .is_gt()
19264                    {
19265                        row_highlights[ix].range.end = next_highlight.range.end;
19266                    }
19267                    row_highlights.remove(ix + 1);
19268                } else {
19269                    break;
19270                }
19271            }
19272        }
19273    }
19274
19275    /// Remove any highlighted row ranges of the given type that intersect the
19276    /// given ranges.
19277    pub fn remove_highlighted_rows<T: 'static>(
19278        &mut self,
19279        ranges_to_remove: Vec<Range<Anchor>>,
19280        cx: &mut Context<Self>,
19281    ) {
19282        let snapshot = self.buffer().read(cx).snapshot(cx);
19283        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19284        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19285        row_highlights.retain(|highlight| {
19286            while let Some(range_to_remove) = ranges_to_remove.peek() {
19287                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19288                    Ordering::Less | Ordering::Equal => {
19289                        ranges_to_remove.next();
19290                    }
19291                    Ordering::Greater => {
19292                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19293                            Ordering::Less | Ordering::Equal => {
19294                                return false;
19295                            }
19296                            Ordering::Greater => break,
19297                        }
19298                    }
19299                }
19300            }
19301
19302            true
19303        })
19304    }
19305
19306    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19307    pub fn clear_row_highlights<T: 'static>(&mut self) {
19308        self.highlighted_rows.remove(&TypeId::of::<T>());
19309    }
19310
19311    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19312    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19313        self.highlighted_rows
19314            .get(&TypeId::of::<T>())
19315            .map_or(&[] as &[_], |vec| vec.as_slice())
19316            .iter()
19317            .map(|highlight| (highlight.range.clone(), highlight.color))
19318    }
19319
19320    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19321    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19322    /// Allows to ignore certain kinds of highlights.
19323    pub fn highlighted_display_rows(
19324        &self,
19325        window: &mut Window,
19326        cx: &mut App,
19327    ) -> BTreeMap<DisplayRow, LineHighlight> {
19328        let snapshot = self.snapshot(window, cx);
19329        let mut used_highlight_orders = HashMap::default();
19330        self.highlighted_rows
19331            .iter()
19332            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19333            .fold(
19334                BTreeMap::<DisplayRow, LineHighlight>::new(),
19335                |mut unique_rows, highlight| {
19336                    let start = highlight.range.start.to_display_point(&snapshot);
19337                    let end = highlight.range.end.to_display_point(&snapshot);
19338                    let start_row = start.row().0;
19339                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19340                        && end.column() == 0
19341                    {
19342                        end.row().0.saturating_sub(1)
19343                    } else {
19344                        end.row().0
19345                    };
19346                    for row in start_row..=end_row {
19347                        let used_index =
19348                            used_highlight_orders.entry(row).or_insert(highlight.index);
19349                        if highlight.index >= *used_index {
19350                            *used_index = highlight.index;
19351                            unique_rows.insert(
19352                                DisplayRow(row),
19353                                LineHighlight {
19354                                    include_gutter: highlight.options.include_gutter,
19355                                    border: None,
19356                                    background: highlight.color.into(),
19357                                    type_id: Some(highlight.type_id),
19358                                },
19359                            );
19360                        }
19361                    }
19362                    unique_rows
19363                },
19364            )
19365    }
19366
19367    pub fn highlighted_display_row_for_autoscroll(
19368        &self,
19369        snapshot: &DisplaySnapshot,
19370    ) -> Option<DisplayRow> {
19371        self.highlighted_rows
19372            .values()
19373            .flat_map(|highlighted_rows| highlighted_rows.iter())
19374            .filter_map(|highlight| {
19375                if highlight.options.autoscroll {
19376                    Some(highlight.range.start.to_display_point(snapshot).row())
19377                } else {
19378                    None
19379                }
19380            })
19381            .min()
19382    }
19383
19384    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19385        self.highlight_background::<SearchWithinRange>(
19386            ranges,
19387            |colors| colors.colors().editor_document_highlight_read_background,
19388            cx,
19389        )
19390    }
19391
19392    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19393        self.breadcrumb_header = Some(new_header);
19394    }
19395
19396    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19397        self.clear_background_highlights::<SearchWithinRange>(cx);
19398    }
19399
19400    pub fn highlight_background<T: 'static>(
19401        &mut self,
19402        ranges: &[Range<Anchor>],
19403        color_fetcher: fn(&Theme) -> Hsla,
19404        cx: &mut Context<Self>,
19405    ) {
19406        self.background_highlights.insert(
19407            HighlightKey::Type(TypeId::of::<T>()),
19408            (color_fetcher, Arc::from(ranges)),
19409        );
19410        self.scrollbar_marker_state.dirty = true;
19411        cx.notify();
19412    }
19413
19414    pub fn highlight_background_key<T: 'static>(
19415        &mut self,
19416        key: usize,
19417        ranges: &[Range<Anchor>],
19418        color_fetcher: fn(&Theme) -> Hsla,
19419        cx: &mut Context<Self>,
19420    ) {
19421        self.background_highlights.insert(
19422            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19423            (color_fetcher, Arc::from(ranges)),
19424        );
19425        self.scrollbar_marker_state.dirty = true;
19426        cx.notify();
19427    }
19428
19429    pub fn clear_background_highlights<T: 'static>(
19430        &mut self,
19431        cx: &mut Context<Self>,
19432    ) -> Option<BackgroundHighlight> {
19433        let text_highlights = self
19434            .background_highlights
19435            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19436        if !text_highlights.1.is_empty() {
19437            self.scrollbar_marker_state.dirty = true;
19438            cx.notify();
19439        }
19440        Some(text_highlights)
19441    }
19442
19443    pub fn highlight_gutter<T: 'static>(
19444        &mut self,
19445        ranges: impl Into<Vec<Range<Anchor>>>,
19446        color_fetcher: fn(&App) -> Hsla,
19447        cx: &mut Context<Self>,
19448    ) {
19449        self.gutter_highlights
19450            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19451        cx.notify();
19452    }
19453
19454    pub fn clear_gutter_highlights<T: 'static>(
19455        &mut self,
19456        cx: &mut Context<Self>,
19457    ) -> Option<GutterHighlight> {
19458        cx.notify();
19459        self.gutter_highlights.remove(&TypeId::of::<T>())
19460    }
19461
19462    pub fn insert_gutter_highlight<T: 'static>(
19463        &mut self,
19464        range: Range<Anchor>,
19465        color_fetcher: fn(&App) -> Hsla,
19466        cx: &mut Context<Self>,
19467    ) {
19468        let snapshot = self.buffer().read(cx).snapshot(cx);
19469        let mut highlights = self
19470            .gutter_highlights
19471            .remove(&TypeId::of::<T>())
19472            .map(|(_, highlights)| highlights)
19473            .unwrap_or_default();
19474        let ix = highlights.binary_search_by(|highlight| {
19475            Ordering::Equal
19476                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19477                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19478        });
19479        if let Err(ix) = ix {
19480            highlights.insert(ix, range);
19481        }
19482        self.gutter_highlights
19483            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19484    }
19485
19486    pub fn remove_gutter_highlights<T: 'static>(
19487        &mut self,
19488        ranges_to_remove: Vec<Range<Anchor>>,
19489        cx: &mut Context<Self>,
19490    ) {
19491        let snapshot = self.buffer().read(cx).snapshot(cx);
19492        let Some((color_fetcher, mut gutter_highlights)) =
19493            self.gutter_highlights.remove(&TypeId::of::<T>())
19494        else {
19495            return;
19496        };
19497        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19498        gutter_highlights.retain(|highlight| {
19499            while let Some(range_to_remove) = ranges_to_remove.peek() {
19500                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19501                    Ordering::Less | Ordering::Equal => {
19502                        ranges_to_remove.next();
19503                    }
19504                    Ordering::Greater => {
19505                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19506                            Ordering::Less | Ordering::Equal => {
19507                                return false;
19508                            }
19509                            Ordering::Greater => break,
19510                        }
19511                    }
19512                }
19513            }
19514
19515            true
19516        });
19517        self.gutter_highlights
19518            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19519    }
19520
19521    #[cfg(feature = "test-support")]
19522    pub fn all_text_highlights(
19523        &self,
19524        window: &mut Window,
19525        cx: &mut Context<Self>,
19526    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19527        let snapshot = self.snapshot(window, cx);
19528        self.display_map.update(cx, |display_map, _| {
19529            display_map
19530                .all_text_highlights()
19531                .map(|highlight| {
19532                    let (style, ranges) = highlight.as_ref();
19533                    (
19534                        *style,
19535                        ranges
19536                            .iter()
19537                            .map(|range| range.clone().to_display_points(&snapshot))
19538                            .collect(),
19539                    )
19540                })
19541                .collect()
19542        })
19543    }
19544
19545    #[cfg(feature = "test-support")]
19546    pub fn all_text_background_highlights(
19547        &self,
19548        window: &mut Window,
19549        cx: &mut Context<Self>,
19550    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19551        let snapshot = self.snapshot(window, cx);
19552        let buffer = &snapshot.buffer_snapshot;
19553        let start = buffer.anchor_before(0);
19554        let end = buffer.anchor_after(buffer.len());
19555        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19556    }
19557
19558    #[cfg(feature = "test-support")]
19559    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19560        let snapshot = self.buffer().read(cx).snapshot(cx);
19561
19562        let highlights = self
19563            .background_highlights
19564            .get(&HighlightKey::Type(TypeId::of::<
19565                items::BufferSearchHighlights,
19566            >()));
19567
19568        if let Some((_color, ranges)) = highlights {
19569            ranges
19570                .iter()
19571                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19572                .collect_vec()
19573        } else {
19574            vec![]
19575        }
19576    }
19577
19578    fn document_highlights_for_position<'a>(
19579        &'a self,
19580        position: Anchor,
19581        buffer: &'a MultiBufferSnapshot,
19582    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19583        let read_highlights = self
19584            .background_highlights
19585            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19586            .map(|h| &h.1);
19587        let write_highlights = self
19588            .background_highlights
19589            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19590            .map(|h| &h.1);
19591        let left_position = position.bias_left(buffer);
19592        let right_position = position.bias_right(buffer);
19593        read_highlights
19594            .into_iter()
19595            .chain(write_highlights)
19596            .flat_map(move |ranges| {
19597                let start_ix = match ranges.binary_search_by(|probe| {
19598                    let cmp = probe.end.cmp(&left_position, buffer);
19599                    if cmp.is_ge() {
19600                        Ordering::Greater
19601                    } else {
19602                        Ordering::Less
19603                    }
19604                }) {
19605                    Ok(i) | Err(i) => i,
19606                };
19607
19608                ranges[start_ix..]
19609                    .iter()
19610                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19611            })
19612    }
19613
19614    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19615        self.background_highlights
19616            .get(&HighlightKey::Type(TypeId::of::<T>()))
19617            .is_some_and(|(_, highlights)| !highlights.is_empty())
19618    }
19619
19620    pub fn background_highlights_in_range(
19621        &self,
19622        search_range: Range<Anchor>,
19623        display_snapshot: &DisplaySnapshot,
19624        theme: &Theme,
19625    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19626        let mut results = Vec::new();
19627        for (color_fetcher, ranges) in self.background_highlights.values() {
19628            let color = color_fetcher(theme);
19629            let start_ix = match ranges.binary_search_by(|probe| {
19630                let cmp = probe
19631                    .end
19632                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19633                if cmp.is_gt() {
19634                    Ordering::Greater
19635                } else {
19636                    Ordering::Less
19637                }
19638            }) {
19639                Ok(i) | Err(i) => i,
19640            };
19641            for range in &ranges[start_ix..] {
19642                if range
19643                    .start
19644                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19645                    .is_ge()
19646                {
19647                    break;
19648                }
19649
19650                let start = range.start.to_display_point(display_snapshot);
19651                let end = range.end.to_display_point(display_snapshot);
19652                results.push((start..end, color))
19653            }
19654        }
19655        results
19656    }
19657
19658    pub fn background_highlight_row_ranges<T: 'static>(
19659        &self,
19660        search_range: Range<Anchor>,
19661        display_snapshot: &DisplaySnapshot,
19662        count: usize,
19663    ) -> Vec<RangeInclusive<DisplayPoint>> {
19664        let mut results = Vec::new();
19665        let Some((_, ranges)) = self
19666            .background_highlights
19667            .get(&HighlightKey::Type(TypeId::of::<T>()))
19668        else {
19669            return vec![];
19670        };
19671
19672        let start_ix = match ranges.binary_search_by(|probe| {
19673            let cmp = probe
19674                .end
19675                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19676            if cmp.is_gt() {
19677                Ordering::Greater
19678            } else {
19679                Ordering::Less
19680            }
19681        }) {
19682            Ok(i) | Err(i) => i,
19683        };
19684        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19685            if let (Some(start_display), Some(end_display)) = (start, end) {
19686                results.push(
19687                    start_display.to_display_point(display_snapshot)
19688                        ..=end_display.to_display_point(display_snapshot),
19689                );
19690            }
19691        };
19692        let mut start_row: Option<Point> = None;
19693        let mut end_row: Option<Point> = None;
19694        if ranges.len() > count {
19695            return Vec::new();
19696        }
19697        for range in &ranges[start_ix..] {
19698            if range
19699                .start
19700                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19701                .is_ge()
19702            {
19703                break;
19704            }
19705            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19706            if let Some(current_row) = &end_row
19707                && end.row == current_row.row
19708            {
19709                continue;
19710            }
19711            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19712            if start_row.is_none() {
19713                assert_eq!(end_row, None);
19714                start_row = Some(start);
19715                end_row = Some(end);
19716                continue;
19717            }
19718            if let Some(current_end) = end_row.as_mut() {
19719                if start.row > current_end.row + 1 {
19720                    push_region(start_row, end_row);
19721                    start_row = Some(start);
19722                    end_row = Some(end);
19723                } else {
19724                    // Merge two hunks.
19725                    *current_end = end;
19726                }
19727            } else {
19728                unreachable!();
19729            }
19730        }
19731        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19732        push_region(start_row, end_row);
19733        results
19734    }
19735
19736    pub fn gutter_highlights_in_range(
19737        &self,
19738        search_range: Range<Anchor>,
19739        display_snapshot: &DisplaySnapshot,
19740        cx: &App,
19741    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19742        let mut results = Vec::new();
19743        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19744            let color = color_fetcher(cx);
19745            let start_ix = match ranges.binary_search_by(|probe| {
19746                let cmp = probe
19747                    .end
19748                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19749                if cmp.is_gt() {
19750                    Ordering::Greater
19751                } else {
19752                    Ordering::Less
19753                }
19754            }) {
19755                Ok(i) | Err(i) => i,
19756            };
19757            for range in &ranges[start_ix..] {
19758                if range
19759                    .start
19760                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19761                    .is_ge()
19762                {
19763                    break;
19764                }
19765
19766                let start = range.start.to_display_point(display_snapshot);
19767                let end = range.end.to_display_point(display_snapshot);
19768                results.push((start..end, color))
19769            }
19770        }
19771        results
19772    }
19773
19774    /// Get the text ranges corresponding to the redaction query
19775    pub fn redacted_ranges(
19776        &self,
19777        search_range: Range<Anchor>,
19778        display_snapshot: &DisplaySnapshot,
19779        cx: &App,
19780    ) -> Vec<Range<DisplayPoint>> {
19781        display_snapshot
19782            .buffer_snapshot
19783            .redacted_ranges(search_range, |file| {
19784                if let Some(file) = file {
19785                    file.is_private()
19786                        && EditorSettings::get(
19787                            Some(SettingsLocation {
19788                                worktree_id: file.worktree_id(cx),
19789                                path: file.path().as_ref(),
19790                            }),
19791                            cx,
19792                        )
19793                        .redact_private_values
19794                } else {
19795                    false
19796                }
19797            })
19798            .map(|range| {
19799                range.start.to_display_point(display_snapshot)
19800                    ..range.end.to_display_point(display_snapshot)
19801            })
19802            .collect()
19803    }
19804
19805    pub fn highlight_text_key<T: 'static>(
19806        &mut self,
19807        key: usize,
19808        ranges: Vec<Range<Anchor>>,
19809        style: HighlightStyle,
19810        cx: &mut Context<Self>,
19811    ) {
19812        self.display_map.update(cx, |map, _| {
19813            map.highlight_text(
19814                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19815                ranges,
19816                style,
19817            );
19818        });
19819        cx.notify();
19820    }
19821
19822    pub fn highlight_text<T: 'static>(
19823        &mut self,
19824        ranges: Vec<Range<Anchor>>,
19825        style: HighlightStyle,
19826        cx: &mut Context<Self>,
19827    ) {
19828        self.display_map.update(cx, |map, _| {
19829            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19830        });
19831        cx.notify();
19832    }
19833
19834    pub(crate) fn highlight_inlays<T: 'static>(
19835        &mut self,
19836        highlights: Vec<InlayHighlight>,
19837        style: HighlightStyle,
19838        cx: &mut Context<Self>,
19839    ) {
19840        self.display_map.update(cx, |map, _| {
19841            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19842        });
19843        cx.notify();
19844    }
19845
19846    pub fn text_highlights<'a, T: 'static>(
19847        &'a self,
19848        cx: &'a App,
19849    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19850        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19851    }
19852
19853    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19854        let cleared = self
19855            .display_map
19856            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19857        if cleared {
19858            cx.notify();
19859        }
19860    }
19861
19862    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19863        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19864            && self.focus_handle.is_focused(window)
19865    }
19866
19867    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19868        self.show_cursor_when_unfocused = is_enabled;
19869        cx.notify();
19870    }
19871
19872    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19873        cx.notify();
19874    }
19875
19876    fn on_debug_session_event(
19877        &mut self,
19878        _session: Entity<Session>,
19879        event: &SessionEvent,
19880        cx: &mut Context<Self>,
19881    ) {
19882        if let SessionEvent::InvalidateInlineValue = event {
19883            self.refresh_inline_values(cx);
19884        }
19885    }
19886
19887    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19888        let Some(project) = self.project.clone() else {
19889            return;
19890        };
19891
19892        if !self.inline_value_cache.enabled {
19893            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19894            self.splice_inlays(&inlays, Vec::new(), cx);
19895            return;
19896        }
19897
19898        let current_execution_position = self
19899            .highlighted_rows
19900            .get(&TypeId::of::<ActiveDebugLine>())
19901            .and_then(|lines| lines.last().map(|line| line.range.end));
19902
19903        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19904            let inline_values = editor
19905                .update(cx, |editor, cx| {
19906                    let Some(current_execution_position) = current_execution_position else {
19907                        return Some(Task::ready(Ok(Vec::new())));
19908                    };
19909
19910                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19911                        let snapshot = buffer.snapshot(cx);
19912
19913                        let excerpt = snapshot.excerpt_containing(
19914                            current_execution_position..current_execution_position,
19915                        )?;
19916
19917                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19918                    })?;
19919
19920                    let range =
19921                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19922
19923                    project.inline_values(buffer, range, cx)
19924                })
19925                .ok()
19926                .flatten()?
19927                .await
19928                .context("refreshing debugger inlays")
19929                .log_err()?;
19930
19931            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19932
19933            for (buffer_id, inline_value) in inline_values
19934                .into_iter()
19935                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19936            {
19937                buffer_inline_values
19938                    .entry(buffer_id)
19939                    .or_default()
19940                    .push(inline_value);
19941            }
19942
19943            editor
19944                .update(cx, |editor, cx| {
19945                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19946                    let mut new_inlays = Vec::default();
19947
19948                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19949                        let buffer_id = buffer_snapshot.remote_id();
19950                        buffer_inline_values
19951                            .get(&buffer_id)
19952                            .into_iter()
19953                            .flatten()
19954                            .for_each(|hint| {
19955                                let inlay = Inlay::debugger(
19956                                    post_inc(&mut editor.next_inlay_id),
19957                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19958                                    hint.text(),
19959                                );
19960                                if !inlay.text.chars().contains(&'\n') {
19961                                    new_inlays.push(inlay);
19962                                }
19963                            });
19964                    }
19965
19966                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19967                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19968
19969                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19970                })
19971                .ok()?;
19972            Some(())
19973        });
19974    }
19975
19976    fn on_buffer_event(
19977        &mut self,
19978        multibuffer: &Entity<MultiBuffer>,
19979        event: &multi_buffer::Event,
19980        window: &mut Window,
19981        cx: &mut Context<Self>,
19982    ) {
19983        match event {
19984            multi_buffer::Event::Edited {
19985                singleton_buffer_edited,
19986                edited_buffer,
19987            } => {
19988                self.scrollbar_marker_state.dirty = true;
19989                self.active_indent_guides_state.dirty = true;
19990                self.refresh_active_diagnostics(cx);
19991                self.refresh_code_actions(window, cx);
19992                self.refresh_selected_text_highlights(true, window, cx);
19993                self.refresh_single_line_folds(window, cx);
19994                refresh_matching_bracket_highlights(self, window, cx);
19995                if self.has_active_edit_prediction() {
19996                    self.update_visible_edit_prediction(window, cx);
19997                }
19998                if let Some(project) = self.project.as_ref()
19999                    && let Some(edited_buffer) = edited_buffer
20000                {
20001                    project.update(cx, |project, cx| {
20002                        self.registered_buffers
20003                            .entry(edited_buffer.read(cx).remote_id())
20004                            .or_insert_with(|| {
20005                                project.register_buffer_with_language_servers(edited_buffer, cx)
20006                            });
20007                    });
20008                }
20009                cx.emit(EditorEvent::BufferEdited);
20010                cx.emit(SearchEvent::MatchesInvalidated);
20011
20012                if let Some(buffer) = edited_buffer {
20013                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20014                }
20015
20016                if *singleton_buffer_edited {
20017                    if let Some(buffer) = edited_buffer
20018                        && buffer.read(cx).file().is_none()
20019                    {
20020                        cx.emit(EditorEvent::TitleChanged);
20021                    }
20022                    if let Some(project) = &self.project {
20023                        #[allow(clippy::mutable_key_type)]
20024                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20025                            multibuffer
20026                                .all_buffers()
20027                                .into_iter()
20028                                .filter_map(|buffer| {
20029                                    buffer.update(cx, |buffer, cx| {
20030                                        let language = buffer.language()?;
20031                                        let should_discard = project.update(cx, |project, cx| {
20032                                            project.is_local()
20033                                                && !project.has_language_servers_for(buffer, cx)
20034                                        });
20035                                        should_discard.not().then_some(language.clone())
20036                                    })
20037                                })
20038                                .collect::<HashSet<_>>()
20039                        });
20040                        if !languages_affected.is_empty() {
20041                            self.refresh_inlay_hints(
20042                                InlayHintRefreshReason::BufferEdited(languages_affected),
20043                                cx,
20044                            );
20045                        }
20046                    }
20047                }
20048
20049                let Some(project) = &self.project else { return };
20050                let (telemetry, is_via_ssh) = {
20051                    let project = project.read(cx);
20052                    let telemetry = project.client().telemetry().clone();
20053                    let is_via_ssh = project.is_via_ssh();
20054                    (telemetry, is_via_ssh)
20055                };
20056                refresh_linked_ranges(self, window, cx);
20057                telemetry.log_edit_event("editor", is_via_ssh);
20058            }
20059            multi_buffer::Event::ExcerptsAdded {
20060                buffer,
20061                predecessor,
20062                excerpts,
20063            } => {
20064                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20065                let buffer_id = buffer.read(cx).remote_id();
20066                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20067                    && let Some(project) = &self.project
20068                {
20069                    update_uncommitted_diff_for_buffer(
20070                        cx.entity(),
20071                        project,
20072                        [buffer.clone()],
20073                        self.buffer.clone(),
20074                        cx,
20075                    )
20076                    .detach();
20077                }
20078                self.update_lsp_data(false, Some(buffer_id), window, cx);
20079                cx.emit(EditorEvent::ExcerptsAdded {
20080                    buffer: buffer.clone(),
20081                    predecessor: *predecessor,
20082                    excerpts: excerpts.clone(),
20083                });
20084                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20085            }
20086            multi_buffer::Event::ExcerptsRemoved {
20087                ids,
20088                removed_buffer_ids,
20089            } => {
20090                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20091                let buffer = self.buffer.read(cx);
20092                self.registered_buffers
20093                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20094                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20095                cx.emit(EditorEvent::ExcerptsRemoved {
20096                    ids: ids.clone(),
20097                    removed_buffer_ids: removed_buffer_ids.clone(),
20098                });
20099            }
20100            multi_buffer::Event::ExcerptsEdited {
20101                excerpt_ids,
20102                buffer_ids,
20103            } => {
20104                self.display_map.update(cx, |map, cx| {
20105                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20106                });
20107                cx.emit(EditorEvent::ExcerptsEdited {
20108                    ids: excerpt_ids.clone(),
20109                });
20110            }
20111            multi_buffer::Event::ExcerptsExpanded { ids } => {
20112                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20113                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20114            }
20115            multi_buffer::Event::Reparsed(buffer_id) => {
20116                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20117                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20118
20119                cx.emit(EditorEvent::Reparsed(*buffer_id));
20120            }
20121            multi_buffer::Event::DiffHunksToggled => {
20122                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20123            }
20124            multi_buffer::Event::LanguageChanged(buffer_id) => {
20125                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20126                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20127                cx.emit(EditorEvent::Reparsed(*buffer_id));
20128                cx.notify();
20129            }
20130            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20131            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20132            multi_buffer::Event::FileHandleChanged
20133            | multi_buffer::Event::Reloaded
20134            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20135            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20136            multi_buffer::Event::DiagnosticsUpdated => {
20137                self.update_diagnostics_state(window, cx);
20138            }
20139            _ => {}
20140        };
20141    }
20142
20143    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20144        if !self.diagnostics_enabled() {
20145            return;
20146        }
20147        self.refresh_active_diagnostics(cx);
20148        self.refresh_inline_diagnostics(true, window, cx);
20149        self.scrollbar_marker_state.dirty = true;
20150        cx.notify();
20151    }
20152
20153    pub fn start_temporary_diff_override(&mut self) {
20154        self.load_diff_task.take();
20155        self.temporary_diff_override = true;
20156    }
20157
20158    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20159        self.temporary_diff_override = false;
20160        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20161        self.buffer.update(cx, |buffer, cx| {
20162            buffer.set_all_diff_hunks_collapsed(cx);
20163        });
20164
20165        if let Some(project) = self.project.clone() {
20166            self.load_diff_task = Some(
20167                update_uncommitted_diff_for_buffer(
20168                    cx.entity(),
20169                    &project,
20170                    self.buffer.read(cx).all_buffers(),
20171                    self.buffer.clone(),
20172                    cx,
20173                )
20174                .shared(),
20175            );
20176        }
20177    }
20178
20179    fn on_display_map_changed(
20180        &mut self,
20181        _: Entity<DisplayMap>,
20182        _: &mut Window,
20183        cx: &mut Context<Self>,
20184    ) {
20185        cx.notify();
20186    }
20187
20188    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20189        if self.diagnostics_enabled() {
20190            let new_severity = EditorSettings::get_global(cx)
20191                .diagnostics_max_severity
20192                .unwrap_or(DiagnosticSeverity::Hint);
20193            self.set_max_diagnostics_severity(new_severity, cx);
20194        }
20195        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20196        self.update_edit_prediction_settings(cx);
20197        self.refresh_edit_prediction(true, false, window, cx);
20198        self.refresh_inline_values(cx);
20199        self.refresh_inlay_hints(
20200            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20201                self.selections.newest_anchor().head(),
20202                &self.buffer.read(cx).snapshot(cx),
20203                cx,
20204            )),
20205            cx,
20206        );
20207
20208        let old_cursor_shape = self.cursor_shape;
20209        let old_show_breadcrumbs = self.show_breadcrumbs;
20210
20211        {
20212            let editor_settings = EditorSettings::get_global(cx);
20213            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20214            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20215            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20216            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20217        }
20218
20219        if old_cursor_shape != self.cursor_shape {
20220            cx.emit(EditorEvent::CursorShapeChanged);
20221        }
20222
20223        if old_show_breadcrumbs != self.show_breadcrumbs {
20224            cx.emit(EditorEvent::BreadcrumbsChanged);
20225        }
20226
20227        let project_settings = ProjectSettings::get_global(cx);
20228        self.serialize_dirty_buffers =
20229            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20230
20231        if self.mode.is_full() {
20232            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20233            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20234            if self.show_inline_diagnostics != show_inline_diagnostics {
20235                self.show_inline_diagnostics = show_inline_diagnostics;
20236                self.refresh_inline_diagnostics(false, window, cx);
20237            }
20238
20239            if self.git_blame_inline_enabled != inline_blame_enabled {
20240                self.toggle_git_blame_inline_internal(false, window, cx);
20241            }
20242
20243            let minimap_settings = EditorSettings::get_global(cx).minimap;
20244            if self.minimap_visibility != MinimapVisibility::Disabled {
20245                if self.minimap_visibility.settings_visibility()
20246                    != minimap_settings.minimap_enabled()
20247                {
20248                    self.set_minimap_visibility(
20249                        MinimapVisibility::for_mode(self.mode(), cx),
20250                        window,
20251                        cx,
20252                    );
20253                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20254                    minimap_entity.update(cx, |minimap_editor, cx| {
20255                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20256                    })
20257                }
20258            }
20259        }
20260
20261        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20262            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20263        }) {
20264            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20265                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20266            }
20267            self.refresh_colors(false, None, window, cx);
20268        }
20269
20270        cx.notify();
20271    }
20272
20273    pub fn set_searchable(&mut self, searchable: bool) {
20274        self.searchable = searchable;
20275    }
20276
20277    pub fn searchable(&self) -> bool {
20278        self.searchable
20279    }
20280
20281    fn open_proposed_changes_editor(
20282        &mut self,
20283        _: &OpenProposedChangesEditor,
20284        window: &mut Window,
20285        cx: &mut Context<Self>,
20286    ) {
20287        let Some(workspace) = self.workspace() else {
20288            cx.propagate();
20289            return;
20290        };
20291
20292        let selections = self.selections.all::<usize>(cx);
20293        let multi_buffer = self.buffer.read(cx);
20294        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20295        let mut new_selections_by_buffer = HashMap::default();
20296        for selection in selections {
20297            for (buffer, range, _) in
20298                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20299            {
20300                let mut range = range.to_point(buffer);
20301                range.start.column = 0;
20302                range.end.column = buffer.line_len(range.end.row);
20303                new_selections_by_buffer
20304                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20305                    .or_insert(Vec::new())
20306                    .push(range)
20307            }
20308        }
20309
20310        let proposed_changes_buffers = new_selections_by_buffer
20311            .into_iter()
20312            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20313            .collect::<Vec<_>>();
20314        let proposed_changes_editor = cx.new(|cx| {
20315            ProposedChangesEditor::new(
20316                "Proposed changes",
20317                proposed_changes_buffers,
20318                self.project.clone(),
20319                window,
20320                cx,
20321            )
20322        });
20323
20324        window.defer(cx, move |window, cx| {
20325            workspace.update(cx, |workspace, cx| {
20326                workspace.active_pane().update(cx, |pane, cx| {
20327                    pane.add_item(
20328                        Box::new(proposed_changes_editor),
20329                        true,
20330                        true,
20331                        None,
20332                        window,
20333                        cx,
20334                    );
20335                });
20336            });
20337        });
20338    }
20339
20340    pub fn open_excerpts_in_split(
20341        &mut self,
20342        _: &OpenExcerptsSplit,
20343        window: &mut Window,
20344        cx: &mut Context<Self>,
20345    ) {
20346        self.open_excerpts_common(None, true, window, cx)
20347    }
20348
20349    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20350        self.open_excerpts_common(None, false, window, cx)
20351    }
20352
20353    fn open_excerpts_common(
20354        &mut self,
20355        jump_data: Option<JumpData>,
20356        split: bool,
20357        window: &mut Window,
20358        cx: &mut Context<Self>,
20359    ) {
20360        let Some(workspace) = self.workspace() else {
20361            cx.propagate();
20362            return;
20363        };
20364
20365        if self.buffer.read(cx).is_singleton() {
20366            cx.propagate();
20367            return;
20368        }
20369
20370        let mut new_selections_by_buffer = HashMap::default();
20371        match &jump_data {
20372            Some(JumpData::MultiBufferPoint {
20373                excerpt_id,
20374                position,
20375                anchor,
20376                line_offset_from_top,
20377            }) => {
20378                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20379                if let Some(buffer) = multi_buffer_snapshot
20380                    .buffer_id_for_excerpt(*excerpt_id)
20381                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20382                {
20383                    let buffer_snapshot = buffer.read(cx).snapshot();
20384                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20385                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20386                    } else {
20387                        buffer_snapshot.clip_point(*position, Bias::Left)
20388                    };
20389                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20390                    new_selections_by_buffer.insert(
20391                        buffer,
20392                        (
20393                            vec![jump_to_offset..jump_to_offset],
20394                            Some(*line_offset_from_top),
20395                        ),
20396                    );
20397                }
20398            }
20399            Some(JumpData::MultiBufferRow {
20400                row,
20401                line_offset_from_top,
20402            }) => {
20403                let point = MultiBufferPoint::new(row.0, 0);
20404                if let Some((buffer, buffer_point, _)) =
20405                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20406                {
20407                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20408                    new_selections_by_buffer
20409                        .entry(buffer)
20410                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20411                        .0
20412                        .push(buffer_offset..buffer_offset)
20413                }
20414            }
20415            None => {
20416                let selections = self.selections.all::<usize>(cx);
20417                let multi_buffer = self.buffer.read(cx);
20418                for selection in selections {
20419                    for (snapshot, range, _, anchor) in multi_buffer
20420                        .snapshot(cx)
20421                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20422                    {
20423                        if let Some(anchor) = anchor {
20424                            // selection is in a deleted hunk
20425                            let Some(buffer_id) = anchor.buffer_id else {
20426                                continue;
20427                            };
20428                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20429                                continue;
20430                            };
20431                            let offset = text::ToOffset::to_offset(
20432                                &anchor.text_anchor,
20433                                &buffer_handle.read(cx).snapshot(),
20434                            );
20435                            let range = offset..offset;
20436                            new_selections_by_buffer
20437                                .entry(buffer_handle)
20438                                .or_insert((Vec::new(), None))
20439                                .0
20440                                .push(range)
20441                        } else {
20442                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20443                            else {
20444                                continue;
20445                            };
20446                            new_selections_by_buffer
20447                                .entry(buffer_handle)
20448                                .or_insert((Vec::new(), None))
20449                                .0
20450                                .push(range)
20451                        }
20452                    }
20453                }
20454            }
20455        }
20456
20457        new_selections_by_buffer
20458            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20459
20460        if new_selections_by_buffer.is_empty() {
20461            return;
20462        }
20463
20464        // We defer the pane interaction because we ourselves are a workspace item
20465        // and activating a new item causes the pane to call a method on us reentrantly,
20466        // which panics if we're on the stack.
20467        window.defer(cx, move |window, cx| {
20468            workspace.update(cx, |workspace, cx| {
20469                let pane = if split {
20470                    workspace.adjacent_pane(window, cx)
20471                } else {
20472                    workspace.active_pane().clone()
20473                };
20474
20475                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20476                    let editor = buffer
20477                        .read(cx)
20478                        .file()
20479                        .is_none()
20480                        .then(|| {
20481                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20482                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20483                            // Instead, we try to activate the existing editor in the pane first.
20484                            let (editor, pane_item_index) =
20485                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20486                                    let editor = item.downcast::<Editor>()?;
20487                                    let singleton_buffer =
20488                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20489                                    if singleton_buffer == buffer {
20490                                        Some((editor, i))
20491                                    } else {
20492                                        None
20493                                    }
20494                                })?;
20495                            pane.update(cx, |pane, cx| {
20496                                pane.activate_item(pane_item_index, true, true, window, cx)
20497                            });
20498                            Some(editor)
20499                        })
20500                        .flatten()
20501                        .unwrap_or_else(|| {
20502                            workspace.open_project_item::<Self>(
20503                                pane.clone(),
20504                                buffer,
20505                                true,
20506                                true,
20507                                window,
20508                                cx,
20509                            )
20510                        });
20511
20512                    editor.update(cx, |editor, cx| {
20513                        let autoscroll = match scroll_offset {
20514                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20515                            None => Autoscroll::newest(),
20516                        };
20517                        let nav_history = editor.nav_history.take();
20518                        editor.change_selections(
20519                            SelectionEffects::scroll(autoscroll),
20520                            window,
20521                            cx,
20522                            |s| {
20523                                s.select_ranges(ranges);
20524                            },
20525                        );
20526                        editor.nav_history = nav_history;
20527                    });
20528                }
20529            })
20530        });
20531    }
20532
20533    // For now, don't allow opening excerpts in buffers that aren't backed by
20534    // regular project files.
20535    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20536        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20537    }
20538
20539    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20540        let snapshot = self.buffer.read(cx).read(cx);
20541        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20542        Some(
20543            ranges
20544                .iter()
20545                .map(move |range| {
20546                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20547                })
20548                .collect(),
20549        )
20550    }
20551
20552    fn selection_replacement_ranges(
20553        &self,
20554        range: Range<OffsetUtf16>,
20555        cx: &mut App,
20556    ) -> Vec<Range<OffsetUtf16>> {
20557        let selections = self.selections.all::<OffsetUtf16>(cx);
20558        let newest_selection = selections
20559            .iter()
20560            .max_by_key(|selection| selection.id)
20561            .unwrap();
20562        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20563        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20564        let snapshot = self.buffer.read(cx).read(cx);
20565        selections
20566            .into_iter()
20567            .map(|mut selection| {
20568                selection.start.0 =
20569                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20570                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20571                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20572                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20573            })
20574            .collect()
20575    }
20576
20577    fn report_editor_event(
20578        &self,
20579        reported_event: ReportEditorEvent,
20580        file_extension: Option<String>,
20581        cx: &App,
20582    ) {
20583        if cfg!(any(test, feature = "test-support")) {
20584            return;
20585        }
20586
20587        let Some(project) = &self.project else { return };
20588
20589        // If None, we are in a file without an extension
20590        let file = self
20591            .buffer
20592            .read(cx)
20593            .as_singleton()
20594            .and_then(|b| b.read(cx).file());
20595        let file_extension = file_extension.or(file
20596            .as_ref()
20597            .and_then(|file| Path::new(file.file_name(cx)).extension())
20598            .and_then(|e| e.to_str())
20599            .map(|a| a.to_string()));
20600
20601        let vim_mode = vim_enabled(cx);
20602
20603        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20604        let copilot_enabled = edit_predictions_provider
20605            == language::language_settings::EditPredictionProvider::Copilot;
20606        let copilot_enabled_for_language = self
20607            .buffer
20608            .read(cx)
20609            .language_settings(cx)
20610            .show_edit_predictions;
20611
20612        let project = project.read(cx);
20613        let event_type = reported_event.event_type();
20614
20615        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20616            telemetry::event!(
20617                event_type,
20618                type = if auto_saved {"autosave"} else {"manual"},
20619                file_extension,
20620                vim_mode,
20621                copilot_enabled,
20622                copilot_enabled_for_language,
20623                edit_predictions_provider,
20624                is_via_ssh = project.is_via_ssh(),
20625            );
20626        } else {
20627            telemetry::event!(
20628                event_type,
20629                file_extension,
20630                vim_mode,
20631                copilot_enabled,
20632                copilot_enabled_for_language,
20633                edit_predictions_provider,
20634                is_via_ssh = project.is_via_ssh(),
20635            );
20636        };
20637    }
20638
20639    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20640    /// with each line being an array of {text, highlight} objects.
20641    fn copy_highlight_json(
20642        &mut self,
20643        _: &CopyHighlightJson,
20644        window: &mut Window,
20645        cx: &mut Context<Self>,
20646    ) {
20647        #[derive(Serialize)]
20648        struct Chunk<'a> {
20649            text: String,
20650            highlight: Option<&'a str>,
20651        }
20652
20653        let snapshot = self.buffer.read(cx).snapshot(cx);
20654        let range = self
20655            .selected_text_range(false, window, cx)
20656            .and_then(|selection| {
20657                if selection.range.is_empty() {
20658                    None
20659                } else {
20660                    Some(selection.range)
20661                }
20662            })
20663            .unwrap_or_else(|| 0..snapshot.len());
20664
20665        let chunks = snapshot.chunks(range, true);
20666        let mut lines = Vec::new();
20667        let mut line: VecDeque<Chunk> = VecDeque::new();
20668
20669        let Some(style) = self.style.as_ref() else {
20670            return;
20671        };
20672
20673        for chunk in chunks {
20674            let highlight = chunk
20675                .syntax_highlight_id
20676                .and_then(|id| id.name(&style.syntax));
20677            let mut chunk_lines = chunk.text.split('\n').peekable();
20678            while let Some(text) = chunk_lines.next() {
20679                let mut merged_with_last_token = false;
20680                if let Some(last_token) = line.back_mut()
20681                    && last_token.highlight == highlight
20682                {
20683                    last_token.text.push_str(text);
20684                    merged_with_last_token = true;
20685                }
20686
20687                if !merged_with_last_token {
20688                    line.push_back(Chunk {
20689                        text: text.into(),
20690                        highlight,
20691                    });
20692                }
20693
20694                if chunk_lines.peek().is_some() {
20695                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20696                        line.pop_front();
20697                    }
20698                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20699                        line.pop_back();
20700                    }
20701
20702                    lines.push(mem::take(&mut line));
20703                }
20704            }
20705        }
20706
20707        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20708            return;
20709        };
20710        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20711    }
20712
20713    pub fn open_context_menu(
20714        &mut self,
20715        _: &OpenContextMenu,
20716        window: &mut Window,
20717        cx: &mut Context<Self>,
20718    ) {
20719        self.request_autoscroll(Autoscroll::newest(), cx);
20720        let position = self.selections.newest_display(cx).start;
20721        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20722    }
20723
20724    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20725        &self.inlay_hint_cache
20726    }
20727
20728    pub fn replay_insert_event(
20729        &mut self,
20730        text: &str,
20731        relative_utf16_range: Option<Range<isize>>,
20732        window: &mut Window,
20733        cx: &mut Context<Self>,
20734    ) {
20735        if !self.input_enabled {
20736            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20737            return;
20738        }
20739        if let Some(relative_utf16_range) = relative_utf16_range {
20740            let selections = self.selections.all::<OffsetUtf16>(cx);
20741            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20742                let new_ranges = selections.into_iter().map(|range| {
20743                    let start = OffsetUtf16(
20744                        range
20745                            .head()
20746                            .0
20747                            .saturating_add_signed(relative_utf16_range.start),
20748                    );
20749                    let end = OffsetUtf16(
20750                        range
20751                            .head()
20752                            .0
20753                            .saturating_add_signed(relative_utf16_range.end),
20754                    );
20755                    start..end
20756                });
20757                s.select_ranges(new_ranges);
20758            });
20759        }
20760
20761        self.handle_input(text, window, cx);
20762    }
20763
20764    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20765        let Some(provider) = self.semantics_provider.as_ref() else {
20766            return false;
20767        };
20768
20769        let mut supports = false;
20770        self.buffer().update(cx, |this, cx| {
20771            this.for_each_buffer(|buffer| {
20772                supports |= provider.supports_inlay_hints(buffer, cx);
20773            });
20774        });
20775
20776        supports
20777    }
20778
20779    pub fn is_focused(&self, window: &Window) -> bool {
20780        self.focus_handle.is_focused(window)
20781    }
20782
20783    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20784        cx.emit(EditorEvent::Focused);
20785
20786        if let Some(descendant) = self
20787            .last_focused_descendant
20788            .take()
20789            .and_then(|descendant| descendant.upgrade())
20790        {
20791            window.focus(&descendant);
20792        } else {
20793            if let Some(blame) = self.blame.as_ref() {
20794                blame.update(cx, GitBlame::focus)
20795            }
20796
20797            self.blink_manager.update(cx, BlinkManager::enable);
20798            self.show_cursor_names(window, cx);
20799            self.buffer.update(cx, |buffer, cx| {
20800                buffer.finalize_last_transaction(cx);
20801                if self.leader_id.is_none() {
20802                    buffer.set_active_selections(
20803                        &self.selections.disjoint_anchors(),
20804                        self.selections.line_mode,
20805                        self.cursor_shape,
20806                        cx,
20807                    );
20808                }
20809            });
20810        }
20811    }
20812
20813    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20814        cx.emit(EditorEvent::FocusedIn)
20815    }
20816
20817    fn handle_focus_out(
20818        &mut self,
20819        event: FocusOutEvent,
20820        _window: &mut Window,
20821        cx: &mut Context<Self>,
20822    ) {
20823        if event.blurred != self.focus_handle {
20824            self.last_focused_descendant = Some(event.blurred);
20825        }
20826        self.selection_drag_state = SelectionDragState::None;
20827        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20828    }
20829
20830    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20831        self.blink_manager.update(cx, BlinkManager::disable);
20832        self.buffer
20833            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20834
20835        if let Some(blame) = self.blame.as_ref() {
20836            blame.update(cx, GitBlame::blur)
20837        }
20838        if !self.hover_state.focused(window, cx) {
20839            hide_hover(self, cx);
20840        }
20841        if !self
20842            .context_menu
20843            .borrow()
20844            .as_ref()
20845            .is_some_and(|context_menu| context_menu.focused(window, cx))
20846        {
20847            self.hide_context_menu(window, cx);
20848        }
20849        self.discard_edit_prediction(false, cx);
20850        cx.emit(EditorEvent::Blurred);
20851        cx.notify();
20852    }
20853
20854    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20855        let mut pending: String = window
20856            .pending_input_keystrokes()
20857            .into_iter()
20858            .flatten()
20859            .filter_map(|keystroke| {
20860                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20861                    keystroke.key_char.clone()
20862                } else {
20863                    None
20864                }
20865            })
20866            .collect();
20867
20868        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20869            pending = "".to_string();
20870        }
20871
20872        let existing_pending = self
20873            .text_highlights::<PendingInput>(cx)
20874            .map(|(_, ranges)| ranges.to_vec());
20875        if existing_pending.is_none() && pending.is_empty() {
20876            return;
20877        }
20878        let transaction =
20879            self.transact(window, cx, |this, window, cx| {
20880                let selections = this.selections.all::<usize>(cx);
20881                let edits = selections
20882                    .iter()
20883                    .map(|selection| (selection.end..selection.end, pending.clone()));
20884                this.edit(edits, cx);
20885                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20886                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20887                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20888                    }));
20889                });
20890                if let Some(existing_ranges) = existing_pending {
20891                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20892                    this.edit(edits, cx);
20893                }
20894            });
20895
20896        let snapshot = self.snapshot(window, cx);
20897        let ranges = self
20898            .selections
20899            .all::<usize>(cx)
20900            .into_iter()
20901            .map(|selection| {
20902                snapshot.buffer_snapshot.anchor_after(selection.end)
20903                    ..snapshot
20904                        .buffer_snapshot
20905                        .anchor_before(selection.end + pending.len())
20906            })
20907            .collect();
20908
20909        if pending.is_empty() {
20910            self.clear_highlights::<PendingInput>(cx);
20911        } else {
20912            self.highlight_text::<PendingInput>(
20913                ranges,
20914                HighlightStyle {
20915                    underline: Some(UnderlineStyle {
20916                        thickness: px(1.),
20917                        color: None,
20918                        wavy: false,
20919                    }),
20920                    ..Default::default()
20921                },
20922                cx,
20923            );
20924        }
20925
20926        self.ime_transaction = self.ime_transaction.or(transaction);
20927        if let Some(transaction) = self.ime_transaction {
20928            self.buffer.update(cx, |buffer, cx| {
20929                buffer.group_until_transaction(transaction, cx);
20930            });
20931        }
20932
20933        if self.text_highlights::<PendingInput>(cx).is_none() {
20934            self.ime_transaction.take();
20935        }
20936    }
20937
20938    pub fn register_action_renderer(
20939        &mut self,
20940        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20941    ) -> Subscription {
20942        let id = self.next_editor_action_id.post_inc();
20943        self.editor_actions
20944            .borrow_mut()
20945            .insert(id, Box::new(listener));
20946
20947        let editor_actions = self.editor_actions.clone();
20948        Subscription::new(move || {
20949            editor_actions.borrow_mut().remove(&id);
20950        })
20951    }
20952
20953    pub fn register_action<A: Action>(
20954        &mut self,
20955        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20956    ) -> Subscription {
20957        let id = self.next_editor_action_id.post_inc();
20958        let listener = Arc::new(listener);
20959        self.editor_actions.borrow_mut().insert(
20960            id,
20961            Box::new(move |_, window, _| {
20962                let listener = listener.clone();
20963                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20964                    let action = action.downcast_ref().unwrap();
20965                    if phase == DispatchPhase::Bubble {
20966                        listener(action, window, cx)
20967                    }
20968                })
20969            }),
20970        );
20971
20972        let editor_actions = self.editor_actions.clone();
20973        Subscription::new(move || {
20974            editor_actions.borrow_mut().remove(&id);
20975        })
20976    }
20977
20978    pub fn file_header_size(&self) -> u32 {
20979        FILE_HEADER_HEIGHT
20980    }
20981
20982    pub fn restore(
20983        &mut self,
20984        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20985        window: &mut Window,
20986        cx: &mut Context<Self>,
20987    ) {
20988        let workspace = self.workspace();
20989        let project = self.project();
20990        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20991            let mut tasks = Vec::new();
20992            for (buffer_id, changes) in revert_changes {
20993                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20994                    buffer.update(cx, |buffer, cx| {
20995                        buffer.edit(
20996                            changes
20997                                .into_iter()
20998                                .map(|(range, text)| (range, text.to_string())),
20999                            None,
21000                            cx,
21001                        );
21002                    });
21003
21004                    if let Some(project) =
21005                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21006                    {
21007                        project.update(cx, |project, cx| {
21008                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21009                        })
21010                    }
21011                }
21012            }
21013            tasks
21014        });
21015        cx.spawn_in(window, async move |_, cx| {
21016            for (buffer, task) in save_tasks {
21017                let result = task.await;
21018                if result.is_err() {
21019                    let Some(path) = buffer
21020                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21021                        .ok()
21022                    else {
21023                        continue;
21024                    };
21025                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21026                        let Some(task) = cx
21027                            .update_window_entity(workspace, |workspace, window, cx| {
21028                                workspace
21029                                    .open_path_preview(path, None, false, false, false, window, cx)
21030                            })
21031                            .ok()
21032                        else {
21033                            continue;
21034                        };
21035                        task.await.log_err();
21036                    }
21037                }
21038            }
21039        })
21040        .detach();
21041        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21042            selections.refresh()
21043        });
21044    }
21045
21046    pub fn to_pixel_point(
21047        &self,
21048        source: multi_buffer::Anchor,
21049        editor_snapshot: &EditorSnapshot,
21050        window: &mut Window,
21051    ) -> Option<gpui::Point<Pixels>> {
21052        let source_point = source.to_display_point(editor_snapshot);
21053        self.display_to_pixel_point(source_point, editor_snapshot, window)
21054    }
21055
21056    pub fn display_to_pixel_point(
21057        &self,
21058        source: DisplayPoint,
21059        editor_snapshot: &EditorSnapshot,
21060        window: &mut Window,
21061    ) -> Option<gpui::Point<Pixels>> {
21062        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21063        let text_layout_details = self.text_layout_details(window);
21064        let scroll_top = text_layout_details
21065            .scroll_anchor
21066            .scroll_position(editor_snapshot)
21067            .y;
21068
21069        if source.row().as_f32() < scroll_top.floor() {
21070            return None;
21071        }
21072        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21073        let source_y = line_height * (source.row().as_f32() - scroll_top);
21074        Some(gpui::Point::new(source_x, source_y))
21075    }
21076
21077    pub fn has_visible_completions_menu(&self) -> bool {
21078        !self.edit_prediction_preview_is_active()
21079            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21080                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21081            })
21082    }
21083
21084    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21085        if self.mode.is_minimap() {
21086            return;
21087        }
21088        self.addons
21089            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21090    }
21091
21092    pub fn unregister_addon<T: Addon>(&mut self) {
21093        self.addons.remove(&std::any::TypeId::of::<T>());
21094    }
21095
21096    pub fn addon<T: Addon>(&self) -> Option<&T> {
21097        let type_id = std::any::TypeId::of::<T>();
21098        self.addons
21099            .get(&type_id)
21100            .and_then(|item| item.to_any().downcast_ref::<T>())
21101    }
21102
21103    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21104        let type_id = std::any::TypeId::of::<T>();
21105        self.addons
21106            .get_mut(&type_id)
21107            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21108    }
21109
21110    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21111        let text_layout_details = self.text_layout_details(window);
21112        let style = &text_layout_details.editor_style;
21113        let font_id = window.text_system().resolve_font(&style.text.font());
21114        let font_size = style.text.font_size.to_pixels(window.rem_size());
21115        let line_height = style.text.line_height_in_pixels(window.rem_size());
21116        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21117        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21118
21119        CharacterDimensions {
21120            em_width,
21121            em_advance,
21122            line_height,
21123        }
21124    }
21125
21126    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21127        self.load_diff_task.clone()
21128    }
21129
21130    fn read_metadata_from_db(
21131        &mut self,
21132        item_id: u64,
21133        workspace_id: WorkspaceId,
21134        window: &mut Window,
21135        cx: &mut Context<Editor>,
21136    ) {
21137        if self.is_singleton(cx)
21138            && !self.mode.is_minimap()
21139            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21140        {
21141            let buffer_snapshot = OnceCell::new();
21142
21143            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21144                && !folds.is_empty()
21145            {
21146                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21147                self.fold_ranges(
21148                    folds
21149                        .into_iter()
21150                        .map(|(start, end)| {
21151                            snapshot.clip_offset(start, Bias::Left)
21152                                ..snapshot.clip_offset(end, Bias::Right)
21153                        })
21154                        .collect(),
21155                    false,
21156                    window,
21157                    cx,
21158                );
21159            }
21160
21161            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21162                && !selections.is_empty()
21163            {
21164                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21165                // skip adding the initial selection to selection history
21166                self.selection_history.mode = SelectionHistoryMode::Skipping;
21167                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21168                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21169                        snapshot.clip_offset(start, Bias::Left)
21170                            ..snapshot.clip_offset(end, Bias::Right)
21171                    }));
21172                });
21173                self.selection_history.mode = SelectionHistoryMode::Normal;
21174            };
21175        }
21176
21177        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21178    }
21179
21180    fn update_lsp_data(
21181        &mut self,
21182        ignore_cache: bool,
21183        for_buffer: Option<BufferId>,
21184        window: &mut Window,
21185        cx: &mut Context<'_, Self>,
21186    ) {
21187        self.pull_diagnostics(for_buffer, window, cx);
21188        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21189    }
21190}
21191
21192fn vim_enabled(cx: &App) -> bool {
21193    cx.global::<SettingsStore>()
21194        .raw_user_settings()
21195        .get("vim_mode")
21196        == Some(&serde_json::Value::Bool(true))
21197}
21198
21199fn process_completion_for_edit(
21200    completion: &Completion,
21201    intent: CompletionIntent,
21202    buffer: &Entity<Buffer>,
21203    cursor_position: &text::Anchor,
21204    cx: &mut Context<Editor>,
21205) -> CompletionEdit {
21206    let buffer = buffer.read(cx);
21207    let buffer_snapshot = buffer.snapshot();
21208    let (snippet, new_text) = if completion.is_snippet() {
21209        // Workaround for typescript language server issues so that methods don't expand within
21210        // strings and functions with type expressions. The previous point is used because the query
21211        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21212        let mut snippet_source = completion.new_text.clone();
21213        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21214        previous_point.column = previous_point.column.saturating_sub(1);
21215        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21216            && scope.prefers_label_for_snippet_in_completion()
21217            && let Some(label) = completion.label()
21218            && matches!(
21219                completion.kind(),
21220                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21221            )
21222        {
21223            snippet_source = label;
21224        }
21225        match Snippet::parse(&snippet_source).log_err() {
21226            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21227            None => (None, completion.new_text.clone()),
21228        }
21229    } else {
21230        (None, completion.new_text.clone())
21231    };
21232
21233    let mut range_to_replace = {
21234        let replace_range = &completion.replace_range;
21235        if let CompletionSource::Lsp {
21236            insert_range: Some(insert_range),
21237            ..
21238        } = &completion.source
21239        {
21240            debug_assert_eq!(
21241                insert_range.start, replace_range.start,
21242                "insert_range and replace_range should start at the same position"
21243            );
21244            debug_assert!(
21245                insert_range
21246                    .start
21247                    .cmp(cursor_position, &buffer_snapshot)
21248                    .is_le(),
21249                "insert_range should start before or at cursor position"
21250            );
21251            debug_assert!(
21252                replace_range
21253                    .start
21254                    .cmp(cursor_position, &buffer_snapshot)
21255                    .is_le(),
21256                "replace_range should start before or at cursor position"
21257            );
21258
21259            let should_replace = match intent {
21260                CompletionIntent::CompleteWithInsert => false,
21261                CompletionIntent::CompleteWithReplace => true,
21262                CompletionIntent::Complete | CompletionIntent::Compose => {
21263                    let insert_mode =
21264                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21265                            .completions
21266                            .lsp_insert_mode;
21267                    match insert_mode {
21268                        LspInsertMode::Insert => false,
21269                        LspInsertMode::Replace => true,
21270                        LspInsertMode::ReplaceSubsequence => {
21271                            let mut text_to_replace = buffer.chars_for_range(
21272                                buffer.anchor_before(replace_range.start)
21273                                    ..buffer.anchor_after(replace_range.end),
21274                            );
21275                            let mut current_needle = text_to_replace.next();
21276                            for haystack_ch in completion.label.text.chars() {
21277                                if let Some(needle_ch) = current_needle
21278                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21279                                {
21280                                    current_needle = text_to_replace.next();
21281                                }
21282                            }
21283                            current_needle.is_none()
21284                        }
21285                        LspInsertMode::ReplaceSuffix => {
21286                            if replace_range
21287                                .end
21288                                .cmp(cursor_position, &buffer_snapshot)
21289                                .is_gt()
21290                            {
21291                                let range_after_cursor = *cursor_position..replace_range.end;
21292                                let text_after_cursor = buffer
21293                                    .text_for_range(
21294                                        buffer.anchor_before(range_after_cursor.start)
21295                                            ..buffer.anchor_after(range_after_cursor.end),
21296                                    )
21297                                    .collect::<String>()
21298                                    .to_ascii_lowercase();
21299                                completion
21300                                    .label
21301                                    .text
21302                                    .to_ascii_lowercase()
21303                                    .ends_with(&text_after_cursor)
21304                            } else {
21305                                true
21306                            }
21307                        }
21308                    }
21309                }
21310            };
21311
21312            if should_replace {
21313                replace_range.clone()
21314            } else {
21315                insert_range.clone()
21316            }
21317        } else {
21318            replace_range.clone()
21319        }
21320    };
21321
21322    if range_to_replace
21323        .end
21324        .cmp(cursor_position, &buffer_snapshot)
21325        .is_lt()
21326    {
21327        range_to_replace.end = *cursor_position;
21328    }
21329
21330    CompletionEdit {
21331        new_text,
21332        replace_range: range_to_replace.to_offset(buffer),
21333        snippet,
21334    }
21335}
21336
21337struct CompletionEdit {
21338    new_text: String,
21339    replace_range: Range<usize>,
21340    snippet: Option<Snippet>,
21341}
21342
21343fn insert_extra_newline_brackets(
21344    buffer: &MultiBufferSnapshot,
21345    range: Range<usize>,
21346    language: &language::LanguageScope,
21347) -> bool {
21348    let leading_whitespace_len = buffer
21349        .reversed_chars_at(range.start)
21350        .take_while(|c| c.is_whitespace() && *c != '\n')
21351        .map(|c| c.len_utf8())
21352        .sum::<usize>();
21353    let trailing_whitespace_len = buffer
21354        .chars_at(range.end)
21355        .take_while(|c| c.is_whitespace() && *c != '\n')
21356        .map(|c| c.len_utf8())
21357        .sum::<usize>();
21358    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21359
21360    language.brackets().any(|(pair, enabled)| {
21361        let pair_start = pair.start.trim_end();
21362        let pair_end = pair.end.trim_start();
21363
21364        enabled
21365            && pair.newline
21366            && buffer.contains_str_at(range.end, pair_end)
21367            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21368    })
21369}
21370
21371fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21372    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21373        [(buffer, range, _)] => (*buffer, range.clone()),
21374        _ => return false,
21375    };
21376    let pair = {
21377        let mut result: Option<BracketMatch> = None;
21378
21379        for pair in buffer
21380            .all_bracket_ranges(range.clone())
21381            .filter(move |pair| {
21382                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21383            })
21384        {
21385            let len = pair.close_range.end - pair.open_range.start;
21386
21387            if let Some(existing) = &result {
21388                let existing_len = existing.close_range.end - existing.open_range.start;
21389                if len > existing_len {
21390                    continue;
21391                }
21392            }
21393
21394            result = Some(pair);
21395        }
21396
21397        result
21398    };
21399    let Some(pair) = pair else {
21400        return false;
21401    };
21402    pair.newline_only
21403        && buffer
21404            .chars_for_range(pair.open_range.end..range.start)
21405            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21406            .all(|c| c.is_whitespace() && c != '\n')
21407}
21408
21409fn update_uncommitted_diff_for_buffer(
21410    editor: Entity<Editor>,
21411    project: &Entity<Project>,
21412    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21413    buffer: Entity<MultiBuffer>,
21414    cx: &mut App,
21415) -> Task<()> {
21416    let mut tasks = Vec::new();
21417    project.update(cx, |project, cx| {
21418        for buffer in buffers {
21419            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21420                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21421            }
21422        }
21423    });
21424    cx.spawn(async move |cx| {
21425        let diffs = future::join_all(tasks).await;
21426        if editor
21427            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21428            .unwrap_or(false)
21429        {
21430            return;
21431        }
21432
21433        buffer
21434            .update(cx, |buffer, cx| {
21435                for diff in diffs.into_iter().flatten() {
21436                    buffer.add_diff(diff, cx);
21437                }
21438            })
21439            .ok();
21440    })
21441}
21442
21443fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21444    let tab_size = tab_size.get() as usize;
21445    let mut width = offset;
21446
21447    for ch in text.chars() {
21448        width += if ch == '\t' {
21449            tab_size - (width % tab_size)
21450        } else {
21451            1
21452        };
21453    }
21454
21455    width - offset
21456}
21457
21458#[cfg(test)]
21459mod tests {
21460    use super::*;
21461
21462    #[test]
21463    fn test_string_size_with_expanded_tabs() {
21464        let nz = |val| NonZeroU32::new(val).unwrap();
21465        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21466        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21467        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21468        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21469        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21470        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21471        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21472        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21473    }
21474}
21475
21476/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21477struct WordBreakingTokenizer<'a> {
21478    input: &'a str,
21479}
21480
21481impl<'a> WordBreakingTokenizer<'a> {
21482    fn new(input: &'a str) -> Self {
21483        Self { input }
21484    }
21485}
21486
21487fn is_char_ideographic(ch: char) -> bool {
21488    use unicode_script::Script::*;
21489    use unicode_script::UnicodeScript;
21490    matches!(ch.script(), Han | Tangut | Yi)
21491}
21492
21493fn is_grapheme_ideographic(text: &str) -> bool {
21494    text.chars().any(is_char_ideographic)
21495}
21496
21497fn is_grapheme_whitespace(text: &str) -> bool {
21498    text.chars().any(|x| x.is_whitespace())
21499}
21500
21501fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21502    text.chars()
21503        .next()
21504        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21505}
21506
21507#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21508enum WordBreakToken<'a> {
21509    Word { token: &'a str, grapheme_len: usize },
21510    InlineWhitespace { token: &'a str, grapheme_len: usize },
21511    Newline,
21512}
21513
21514impl<'a> Iterator for WordBreakingTokenizer<'a> {
21515    /// Yields a span, the count of graphemes in the token, and whether it was
21516    /// whitespace. Note that it also breaks at word boundaries.
21517    type Item = WordBreakToken<'a>;
21518
21519    fn next(&mut self) -> Option<Self::Item> {
21520        use unicode_segmentation::UnicodeSegmentation;
21521        if self.input.is_empty() {
21522            return None;
21523        }
21524
21525        let mut iter = self.input.graphemes(true).peekable();
21526        let mut offset = 0;
21527        let mut grapheme_len = 0;
21528        if let Some(first_grapheme) = iter.next() {
21529            let is_newline = first_grapheme == "\n";
21530            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21531            offset += first_grapheme.len();
21532            grapheme_len += 1;
21533            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21534                if let Some(grapheme) = iter.peek().copied()
21535                    && should_stay_with_preceding_ideograph(grapheme)
21536                {
21537                    offset += grapheme.len();
21538                    grapheme_len += 1;
21539                }
21540            } else {
21541                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21542                let mut next_word_bound = words.peek().copied();
21543                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21544                    next_word_bound = words.next();
21545                }
21546                while let Some(grapheme) = iter.peek().copied() {
21547                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21548                        break;
21549                    };
21550                    if is_grapheme_whitespace(grapheme) != is_whitespace
21551                        || (grapheme == "\n") != is_newline
21552                    {
21553                        break;
21554                    };
21555                    offset += grapheme.len();
21556                    grapheme_len += 1;
21557                    iter.next();
21558                }
21559            }
21560            let token = &self.input[..offset];
21561            self.input = &self.input[offset..];
21562            if token == "\n" {
21563                Some(WordBreakToken::Newline)
21564            } else if is_whitespace {
21565                Some(WordBreakToken::InlineWhitespace {
21566                    token,
21567                    grapheme_len,
21568                })
21569            } else {
21570                Some(WordBreakToken::Word {
21571                    token,
21572                    grapheme_len,
21573                })
21574            }
21575        } else {
21576            None
21577        }
21578    }
21579}
21580
21581#[test]
21582fn test_word_breaking_tokenizer() {
21583    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21584        ("", &[]),
21585        ("  ", &[whitespace("  ", 2)]),
21586        ("Ʒ", &[word("Ʒ", 1)]),
21587        ("Ǽ", &[word("Ǽ", 1)]),
21588        ("", &[word("", 1)]),
21589        ("⋑⋑", &[word("⋑⋑", 2)]),
21590        (
21591            "原理,进而",
21592            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21593        ),
21594        (
21595            "hello world",
21596            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21597        ),
21598        (
21599            "hello, world",
21600            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21601        ),
21602        (
21603            "  hello world",
21604            &[
21605                whitespace("  ", 2),
21606                word("hello", 5),
21607                whitespace(" ", 1),
21608                word("world", 5),
21609            ],
21610        ),
21611        (
21612            "这是什么 \n 钢笔",
21613            &[
21614                word("", 1),
21615                word("", 1),
21616                word("", 1),
21617                word("", 1),
21618                whitespace(" ", 1),
21619                newline(),
21620                whitespace(" ", 1),
21621                word("", 1),
21622                word("", 1),
21623            ],
21624        ),
21625        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21626    ];
21627
21628    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21629        WordBreakToken::Word {
21630            token,
21631            grapheme_len,
21632        }
21633    }
21634
21635    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21636        WordBreakToken::InlineWhitespace {
21637            token,
21638            grapheme_len,
21639        }
21640    }
21641
21642    fn newline() -> WordBreakToken<'static> {
21643        WordBreakToken::Newline
21644    }
21645
21646    for (input, result) in tests {
21647        assert_eq!(
21648            WordBreakingTokenizer::new(input)
21649                .collect::<Vec<_>>()
21650                .as_slice(),
21651            *result,
21652        );
21653    }
21654}
21655
21656fn wrap_with_prefix(
21657    first_line_prefix: String,
21658    subsequent_lines_prefix: String,
21659    unwrapped_text: String,
21660    wrap_column: usize,
21661    tab_size: NonZeroU32,
21662    preserve_existing_whitespace: bool,
21663) -> String {
21664    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21665    let subsequent_lines_prefix_len =
21666        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21667    let mut wrapped_text = String::new();
21668    let mut current_line = first_line_prefix;
21669    let mut is_first_line = true;
21670
21671    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21672    let mut current_line_len = first_line_prefix_len;
21673    let mut in_whitespace = false;
21674    for token in tokenizer {
21675        let have_preceding_whitespace = in_whitespace;
21676        match token {
21677            WordBreakToken::Word {
21678                token,
21679                grapheme_len,
21680            } => {
21681                in_whitespace = false;
21682                let current_prefix_len = if is_first_line {
21683                    first_line_prefix_len
21684                } else {
21685                    subsequent_lines_prefix_len
21686                };
21687                if current_line_len + grapheme_len > wrap_column
21688                    && current_line_len != current_prefix_len
21689                {
21690                    wrapped_text.push_str(current_line.trim_end());
21691                    wrapped_text.push('\n');
21692                    is_first_line = false;
21693                    current_line = subsequent_lines_prefix.clone();
21694                    current_line_len = subsequent_lines_prefix_len;
21695                }
21696                current_line.push_str(token);
21697                current_line_len += grapheme_len;
21698            }
21699            WordBreakToken::InlineWhitespace {
21700                mut token,
21701                mut grapheme_len,
21702            } => {
21703                in_whitespace = true;
21704                if have_preceding_whitespace && !preserve_existing_whitespace {
21705                    continue;
21706                }
21707                if !preserve_existing_whitespace {
21708                    token = " ";
21709                    grapheme_len = 1;
21710                }
21711                let current_prefix_len = if is_first_line {
21712                    first_line_prefix_len
21713                } else {
21714                    subsequent_lines_prefix_len
21715                };
21716                if current_line_len + grapheme_len > wrap_column {
21717                    wrapped_text.push_str(current_line.trim_end());
21718                    wrapped_text.push('\n');
21719                    is_first_line = false;
21720                    current_line = subsequent_lines_prefix.clone();
21721                    current_line_len = subsequent_lines_prefix_len;
21722                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21723                    current_line.push_str(token);
21724                    current_line_len += grapheme_len;
21725                }
21726            }
21727            WordBreakToken::Newline => {
21728                in_whitespace = true;
21729                let current_prefix_len = if is_first_line {
21730                    first_line_prefix_len
21731                } else {
21732                    subsequent_lines_prefix_len
21733                };
21734                if preserve_existing_whitespace {
21735                    wrapped_text.push_str(current_line.trim_end());
21736                    wrapped_text.push('\n');
21737                    is_first_line = false;
21738                    current_line = subsequent_lines_prefix.clone();
21739                    current_line_len = subsequent_lines_prefix_len;
21740                } else if have_preceding_whitespace {
21741                    continue;
21742                } else if current_line_len + 1 > wrap_column
21743                    && current_line_len != current_prefix_len
21744                {
21745                    wrapped_text.push_str(current_line.trim_end());
21746                    wrapped_text.push('\n');
21747                    is_first_line = false;
21748                    current_line = subsequent_lines_prefix.clone();
21749                    current_line_len = subsequent_lines_prefix_len;
21750                } else if current_line_len != current_prefix_len {
21751                    current_line.push(' ');
21752                    current_line_len += 1;
21753                }
21754            }
21755        }
21756    }
21757
21758    if !current_line.is_empty() {
21759        wrapped_text.push_str(&current_line);
21760    }
21761    wrapped_text
21762}
21763
21764#[test]
21765fn test_wrap_with_prefix() {
21766    assert_eq!(
21767        wrap_with_prefix(
21768            "# ".to_string(),
21769            "# ".to_string(),
21770            "abcdefg".to_string(),
21771            4,
21772            NonZeroU32::new(4).unwrap(),
21773            false,
21774        ),
21775        "# abcdefg"
21776    );
21777    assert_eq!(
21778        wrap_with_prefix(
21779            "".to_string(),
21780            "".to_string(),
21781            "\thello world".to_string(),
21782            8,
21783            NonZeroU32::new(4).unwrap(),
21784            false,
21785        ),
21786        "hello\nworld"
21787    );
21788    assert_eq!(
21789        wrap_with_prefix(
21790            "// ".to_string(),
21791            "// ".to_string(),
21792            "xx \nyy zz aa bb cc".to_string(),
21793            12,
21794            NonZeroU32::new(4).unwrap(),
21795            false,
21796        ),
21797        "// xx yy zz\n// aa bb cc"
21798    );
21799    assert_eq!(
21800        wrap_with_prefix(
21801            String::new(),
21802            String::new(),
21803            "这是什么 \n 钢笔".to_string(),
21804            3,
21805            NonZeroU32::new(4).unwrap(),
21806            false,
21807        ),
21808        "这是什\n么 钢\n"
21809    );
21810}
21811
21812pub trait CollaborationHub {
21813    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21814    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21815    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21816}
21817
21818impl CollaborationHub for Entity<Project> {
21819    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21820        self.read(cx).collaborators()
21821    }
21822
21823    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21824        self.read(cx).user_store().read(cx).participant_indices()
21825    }
21826
21827    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21828        let this = self.read(cx);
21829        let user_ids = this.collaborators().values().map(|c| c.user_id);
21830        this.user_store().read(cx).participant_names(user_ids, cx)
21831    }
21832}
21833
21834pub trait SemanticsProvider {
21835    fn hover(
21836        &self,
21837        buffer: &Entity<Buffer>,
21838        position: text::Anchor,
21839        cx: &mut App,
21840    ) -> Option<Task<Vec<project::Hover>>>;
21841
21842    fn inline_values(
21843        &self,
21844        buffer_handle: Entity<Buffer>,
21845        range: Range<text::Anchor>,
21846        cx: &mut App,
21847    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21848
21849    fn inlay_hints(
21850        &self,
21851        buffer_handle: Entity<Buffer>,
21852        range: Range<text::Anchor>,
21853        cx: &mut App,
21854    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21855
21856    fn resolve_inlay_hint(
21857        &self,
21858        hint: InlayHint,
21859        buffer_handle: Entity<Buffer>,
21860        server_id: LanguageServerId,
21861        cx: &mut App,
21862    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21863
21864    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21865
21866    fn document_highlights(
21867        &self,
21868        buffer: &Entity<Buffer>,
21869        position: text::Anchor,
21870        cx: &mut App,
21871    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21872
21873    fn definitions(
21874        &self,
21875        buffer: &Entity<Buffer>,
21876        position: text::Anchor,
21877        kind: GotoDefinitionKind,
21878        cx: &mut App,
21879    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21880
21881    fn range_for_rename(
21882        &self,
21883        buffer: &Entity<Buffer>,
21884        position: text::Anchor,
21885        cx: &mut App,
21886    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21887
21888    fn perform_rename(
21889        &self,
21890        buffer: &Entity<Buffer>,
21891        position: text::Anchor,
21892        new_name: String,
21893        cx: &mut App,
21894    ) -> Option<Task<Result<ProjectTransaction>>>;
21895}
21896
21897pub trait CompletionProvider {
21898    fn completions(
21899        &self,
21900        excerpt_id: ExcerptId,
21901        buffer: &Entity<Buffer>,
21902        buffer_position: text::Anchor,
21903        trigger: CompletionContext,
21904        window: &mut Window,
21905        cx: &mut Context<Editor>,
21906    ) -> Task<Result<Vec<CompletionResponse>>>;
21907
21908    fn resolve_completions(
21909        &self,
21910        _buffer: Entity<Buffer>,
21911        _completion_indices: Vec<usize>,
21912        _completions: Rc<RefCell<Box<[Completion]>>>,
21913        _cx: &mut Context<Editor>,
21914    ) -> Task<Result<bool>> {
21915        Task::ready(Ok(false))
21916    }
21917
21918    fn apply_additional_edits_for_completion(
21919        &self,
21920        _buffer: Entity<Buffer>,
21921        _completions: Rc<RefCell<Box<[Completion]>>>,
21922        _completion_index: usize,
21923        _push_to_history: bool,
21924        _cx: &mut Context<Editor>,
21925    ) -> Task<Result<Option<language::Transaction>>> {
21926        Task::ready(Ok(None))
21927    }
21928
21929    fn is_completion_trigger(
21930        &self,
21931        buffer: &Entity<Buffer>,
21932        position: language::Anchor,
21933        text: &str,
21934        trigger_in_words: bool,
21935        menu_is_open: bool,
21936        cx: &mut Context<Editor>,
21937    ) -> bool;
21938
21939    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21940
21941    fn sort_completions(&self) -> bool {
21942        true
21943    }
21944
21945    fn filter_completions(&self) -> bool {
21946        true
21947    }
21948}
21949
21950pub trait CodeActionProvider {
21951    fn id(&self) -> Arc<str>;
21952
21953    fn code_actions(
21954        &self,
21955        buffer: &Entity<Buffer>,
21956        range: Range<text::Anchor>,
21957        window: &mut Window,
21958        cx: &mut App,
21959    ) -> Task<Result<Vec<CodeAction>>>;
21960
21961    fn apply_code_action(
21962        &self,
21963        buffer_handle: Entity<Buffer>,
21964        action: CodeAction,
21965        excerpt_id: ExcerptId,
21966        push_to_history: bool,
21967        window: &mut Window,
21968        cx: &mut App,
21969    ) -> Task<Result<ProjectTransaction>>;
21970}
21971
21972impl CodeActionProvider for Entity<Project> {
21973    fn id(&self) -> Arc<str> {
21974        "project".into()
21975    }
21976
21977    fn code_actions(
21978        &self,
21979        buffer: &Entity<Buffer>,
21980        range: Range<text::Anchor>,
21981        _window: &mut Window,
21982        cx: &mut App,
21983    ) -> Task<Result<Vec<CodeAction>>> {
21984        self.update(cx, |project, cx| {
21985            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21986            let code_actions = project.code_actions(buffer, range, None, cx);
21987            cx.background_spawn(async move {
21988                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21989                Ok(code_lens_actions
21990                    .context("code lens fetch")?
21991                    .into_iter()
21992                    .chain(code_actions.context("code action fetch")?)
21993                    .collect())
21994            })
21995        })
21996    }
21997
21998    fn apply_code_action(
21999        &self,
22000        buffer_handle: Entity<Buffer>,
22001        action: CodeAction,
22002        _excerpt_id: ExcerptId,
22003        push_to_history: bool,
22004        _window: &mut Window,
22005        cx: &mut App,
22006    ) -> Task<Result<ProjectTransaction>> {
22007        self.update(cx, |project, cx| {
22008            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22009        })
22010    }
22011}
22012
22013fn snippet_completions(
22014    project: &Project,
22015    buffer: &Entity<Buffer>,
22016    buffer_position: text::Anchor,
22017    cx: &mut App,
22018) -> Task<Result<CompletionResponse>> {
22019    let languages = buffer.read(cx).languages_at(buffer_position);
22020    let snippet_store = project.snippets().read(cx);
22021
22022    let scopes: Vec<_> = languages
22023        .iter()
22024        .filter_map(|language| {
22025            let language_name = language.lsp_id();
22026            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22027
22028            if snippets.is_empty() {
22029                None
22030            } else {
22031                Some((language.default_scope(), snippets))
22032            }
22033        })
22034        .collect();
22035
22036    if scopes.is_empty() {
22037        return Task::ready(Ok(CompletionResponse {
22038            completions: vec![],
22039            is_incomplete: false,
22040        }));
22041    }
22042
22043    let snapshot = buffer.read(cx).text_snapshot();
22044    let chars: String = snapshot
22045        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22046        .collect();
22047    let executor = cx.background_executor().clone();
22048
22049    cx.background_spawn(async move {
22050        let mut is_incomplete = false;
22051        let mut completions: Vec<Completion> = Vec::new();
22052        for (scope, snippets) in scopes.into_iter() {
22053            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22054            let mut last_word = chars
22055                .chars()
22056                .take_while(|c| classifier.is_word(*c))
22057                .collect::<String>();
22058            last_word = last_word.chars().rev().collect();
22059
22060            if last_word.is_empty() {
22061                return Ok(CompletionResponse {
22062                    completions: vec![],
22063                    is_incomplete: true,
22064                });
22065            }
22066
22067            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22068            let to_lsp = |point: &text::Anchor| {
22069                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22070                point_to_lsp(end)
22071            };
22072            let lsp_end = to_lsp(&buffer_position);
22073
22074            let candidates = snippets
22075                .iter()
22076                .enumerate()
22077                .flat_map(|(ix, snippet)| {
22078                    snippet
22079                        .prefix
22080                        .iter()
22081                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22082                })
22083                .collect::<Vec<StringMatchCandidate>>();
22084
22085            const MAX_RESULTS: usize = 100;
22086            let mut matches = fuzzy::match_strings(
22087                &candidates,
22088                &last_word,
22089                last_word.chars().any(|c| c.is_uppercase()),
22090                true,
22091                MAX_RESULTS,
22092                &Default::default(),
22093                executor.clone(),
22094            )
22095            .await;
22096
22097            if matches.len() >= MAX_RESULTS {
22098                is_incomplete = true;
22099            }
22100
22101            // Remove all candidates where the query's start does not match the start of any word in the candidate
22102            if let Some(query_start) = last_word.chars().next() {
22103                matches.retain(|string_match| {
22104                    split_words(&string_match.string).any(|word| {
22105                        // Check that the first codepoint of the word as lowercase matches the first
22106                        // codepoint of the query as lowercase
22107                        word.chars()
22108                            .flat_map(|codepoint| codepoint.to_lowercase())
22109                            .zip(query_start.to_lowercase())
22110                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22111                    })
22112                });
22113            }
22114
22115            let matched_strings = matches
22116                .into_iter()
22117                .map(|m| m.string)
22118                .collect::<HashSet<_>>();
22119
22120            completions.extend(snippets.iter().filter_map(|snippet| {
22121                let matching_prefix = snippet
22122                    .prefix
22123                    .iter()
22124                    .find(|prefix| matched_strings.contains(*prefix))?;
22125                let start = as_offset - last_word.len();
22126                let start = snapshot.anchor_before(start);
22127                let range = start..buffer_position;
22128                let lsp_start = to_lsp(&start);
22129                let lsp_range = lsp::Range {
22130                    start: lsp_start,
22131                    end: lsp_end,
22132                };
22133                Some(Completion {
22134                    replace_range: range,
22135                    new_text: snippet.body.clone(),
22136                    source: CompletionSource::Lsp {
22137                        insert_range: None,
22138                        server_id: LanguageServerId(usize::MAX),
22139                        resolved: true,
22140                        lsp_completion: Box::new(lsp::CompletionItem {
22141                            label: snippet.prefix.first().unwrap().clone(),
22142                            kind: Some(CompletionItemKind::SNIPPET),
22143                            label_details: snippet.description.as_ref().map(|description| {
22144                                lsp::CompletionItemLabelDetails {
22145                                    detail: Some(description.clone()),
22146                                    description: None,
22147                                }
22148                            }),
22149                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22150                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22151                                lsp::InsertReplaceEdit {
22152                                    new_text: snippet.body.clone(),
22153                                    insert: lsp_range,
22154                                    replace: lsp_range,
22155                                },
22156                            )),
22157                            filter_text: Some(snippet.body.clone()),
22158                            sort_text: Some(char::MAX.to_string()),
22159                            ..lsp::CompletionItem::default()
22160                        }),
22161                        lsp_defaults: None,
22162                    },
22163                    label: CodeLabel {
22164                        text: matching_prefix.clone(),
22165                        runs: Vec::new(),
22166                        filter_range: 0..matching_prefix.len(),
22167                    },
22168                    icon_path: None,
22169                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22170                        single_line: snippet.name.clone().into(),
22171                        plain_text: snippet
22172                            .description
22173                            .clone()
22174                            .map(|description| description.into()),
22175                    }),
22176                    insert_text_mode: None,
22177                    confirm: None,
22178                })
22179            }))
22180        }
22181
22182        Ok(CompletionResponse {
22183            completions,
22184            is_incomplete,
22185        })
22186    })
22187}
22188
22189impl CompletionProvider for Entity<Project> {
22190    fn completions(
22191        &self,
22192        _excerpt_id: ExcerptId,
22193        buffer: &Entity<Buffer>,
22194        buffer_position: text::Anchor,
22195        options: CompletionContext,
22196        _window: &mut Window,
22197        cx: &mut Context<Editor>,
22198    ) -> Task<Result<Vec<CompletionResponse>>> {
22199        self.update(cx, |project, cx| {
22200            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22201            let project_completions = project.completions(buffer, buffer_position, options, cx);
22202            cx.background_spawn(async move {
22203                let mut responses = project_completions.await?;
22204                let snippets = snippets.await?;
22205                if !snippets.completions.is_empty() {
22206                    responses.push(snippets);
22207                }
22208                Ok(responses)
22209            })
22210        })
22211    }
22212
22213    fn resolve_completions(
22214        &self,
22215        buffer: Entity<Buffer>,
22216        completion_indices: Vec<usize>,
22217        completions: Rc<RefCell<Box<[Completion]>>>,
22218        cx: &mut Context<Editor>,
22219    ) -> Task<Result<bool>> {
22220        self.update(cx, |project, cx| {
22221            project.lsp_store().update(cx, |lsp_store, cx| {
22222                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22223            })
22224        })
22225    }
22226
22227    fn apply_additional_edits_for_completion(
22228        &self,
22229        buffer: Entity<Buffer>,
22230        completions: Rc<RefCell<Box<[Completion]>>>,
22231        completion_index: usize,
22232        push_to_history: bool,
22233        cx: &mut Context<Editor>,
22234    ) -> Task<Result<Option<language::Transaction>>> {
22235        self.update(cx, |project, cx| {
22236            project.lsp_store().update(cx, |lsp_store, cx| {
22237                lsp_store.apply_additional_edits_for_completion(
22238                    buffer,
22239                    completions,
22240                    completion_index,
22241                    push_to_history,
22242                    cx,
22243                )
22244            })
22245        })
22246    }
22247
22248    fn is_completion_trigger(
22249        &self,
22250        buffer: &Entity<Buffer>,
22251        position: language::Anchor,
22252        text: &str,
22253        trigger_in_words: bool,
22254        menu_is_open: bool,
22255        cx: &mut Context<Editor>,
22256    ) -> bool {
22257        let mut chars = text.chars();
22258        let char = if let Some(char) = chars.next() {
22259            char
22260        } else {
22261            return false;
22262        };
22263        if chars.next().is_some() {
22264            return false;
22265        }
22266
22267        let buffer = buffer.read(cx);
22268        let snapshot = buffer.snapshot();
22269        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22270            return false;
22271        }
22272        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22273        if trigger_in_words && classifier.is_word(char) {
22274            return true;
22275        }
22276
22277        buffer.completion_triggers().contains(text)
22278    }
22279}
22280
22281impl SemanticsProvider for Entity<Project> {
22282    fn hover(
22283        &self,
22284        buffer: &Entity<Buffer>,
22285        position: text::Anchor,
22286        cx: &mut App,
22287    ) -> Option<Task<Vec<project::Hover>>> {
22288        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22289    }
22290
22291    fn document_highlights(
22292        &self,
22293        buffer: &Entity<Buffer>,
22294        position: text::Anchor,
22295        cx: &mut App,
22296    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22297        Some(self.update(cx, |project, cx| {
22298            project.document_highlights(buffer, position, cx)
22299        }))
22300    }
22301
22302    fn definitions(
22303        &self,
22304        buffer: &Entity<Buffer>,
22305        position: text::Anchor,
22306        kind: GotoDefinitionKind,
22307        cx: &mut App,
22308    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22309        Some(self.update(cx, |project, cx| match kind {
22310            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22311            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22312            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22313            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22314        }))
22315    }
22316
22317    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22318        self.update(cx, |project, cx| {
22319            if project
22320                .active_debug_session(cx)
22321                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22322            {
22323                return true;
22324            }
22325
22326            buffer.update(cx, |buffer, cx| {
22327                project.any_language_server_supports_inlay_hints(buffer, cx)
22328            })
22329        })
22330    }
22331
22332    fn inline_values(
22333        &self,
22334        buffer_handle: Entity<Buffer>,
22335        range: Range<text::Anchor>,
22336        cx: &mut App,
22337    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22338        self.update(cx, |project, cx| {
22339            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22340
22341            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22342        })
22343    }
22344
22345    fn inlay_hints(
22346        &self,
22347        buffer_handle: Entity<Buffer>,
22348        range: Range<text::Anchor>,
22349        cx: &mut App,
22350    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22351        Some(self.update(cx, |project, cx| {
22352            project.inlay_hints(buffer_handle, range, cx)
22353        }))
22354    }
22355
22356    fn resolve_inlay_hint(
22357        &self,
22358        hint: InlayHint,
22359        buffer_handle: Entity<Buffer>,
22360        server_id: LanguageServerId,
22361        cx: &mut App,
22362    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22363        Some(self.update(cx, |project, cx| {
22364            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22365        }))
22366    }
22367
22368    fn range_for_rename(
22369        &self,
22370        buffer: &Entity<Buffer>,
22371        position: text::Anchor,
22372        cx: &mut App,
22373    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22374        Some(self.update(cx, |project, cx| {
22375            let buffer = buffer.clone();
22376            let task = project.prepare_rename(buffer.clone(), position, cx);
22377            cx.spawn(async move |_, cx| {
22378                Ok(match task.await? {
22379                    PrepareRenameResponse::Success(range) => Some(range),
22380                    PrepareRenameResponse::InvalidPosition => None,
22381                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22382                        // Fallback on using TreeSitter info to determine identifier range
22383                        buffer.read_with(cx, |buffer, _| {
22384                            let snapshot = buffer.snapshot();
22385                            let (range, kind) = snapshot.surrounding_word(position, false);
22386                            if kind != Some(CharKind::Word) {
22387                                return None;
22388                            }
22389                            Some(
22390                                snapshot.anchor_before(range.start)
22391                                    ..snapshot.anchor_after(range.end),
22392                            )
22393                        })?
22394                    }
22395                })
22396            })
22397        }))
22398    }
22399
22400    fn perform_rename(
22401        &self,
22402        buffer: &Entity<Buffer>,
22403        position: text::Anchor,
22404        new_name: String,
22405        cx: &mut App,
22406    ) -> Option<Task<Result<ProjectTransaction>>> {
22407        Some(self.update(cx, |project, cx| {
22408            project.perform_rename(buffer.clone(), position, new_name, cx)
22409        }))
22410    }
22411}
22412
22413fn inlay_hint_settings(
22414    location: Anchor,
22415    snapshot: &MultiBufferSnapshot,
22416    cx: &mut Context<Editor>,
22417) -> InlayHintSettings {
22418    let file = snapshot.file_at(location);
22419    let language = snapshot.language_at(location).map(|l| l.name());
22420    language_settings(language, file, cx).inlay_hints
22421}
22422
22423fn consume_contiguous_rows(
22424    contiguous_row_selections: &mut Vec<Selection<Point>>,
22425    selection: &Selection<Point>,
22426    display_map: &DisplaySnapshot,
22427    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22428) -> (MultiBufferRow, MultiBufferRow) {
22429    contiguous_row_selections.push(selection.clone());
22430    let start_row = starting_row(selection, display_map);
22431    let mut end_row = ending_row(selection, display_map);
22432
22433    while let Some(next_selection) = selections.peek() {
22434        if next_selection.start.row <= end_row.0 {
22435            end_row = ending_row(next_selection, display_map);
22436            contiguous_row_selections.push(selections.next().unwrap().clone());
22437        } else {
22438            break;
22439        }
22440    }
22441    (start_row, end_row)
22442}
22443
22444fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22445    if selection.start.column > 0 {
22446        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22447    } else {
22448        MultiBufferRow(selection.start.row)
22449    }
22450}
22451
22452fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22453    if next_selection.end.column > 0 || next_selection.is_empty() {
22454        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22455    } else {
22456        MultiBufferRow(next_selection.end.row)
22457    }
22458}
22459
22460impl EditorSnapshot {
22461    pub fn remote_selections_in_range<'a>(
22462        &'a self,
22463        range: &'a Range<Anchor>,
22464        collaboration_hub: &dyn CollaborationHub,
22465        cx: &'a App,
22466    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22467        let participant_names = collaboration_hub.user_names(cx);
22468        let participant_indices = collaboration_hub.user_participant_indices(cx);
22469        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22470        let collaborators_by_replica_id = collaborators_by_peer_id
22471            .values()
22472            .map(|collaborator| (collaborator.replica_id, collaborator))
22473            .collect::<HashMap<_, _>>();
22474        self.buffer_snapshot
22475            .selections_in_range(range, false)
22476            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22477                if replica_id == AGENT_REPLICA_ID {
22478                    Some(RemoteSelection {
22479                        replica_id,
22480                        selection,
22481                        cursor_shape,
22482                        line_mode,
22483                        collaborator_id: CollaboratorId::Agent,
22484                        user_name: Some("Agent".into()),
22485                        color: cx.theme().players().agent(),
22486                    })
22487                } else {
22488                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22489                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22490                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22491                    Some(RemoteSelection {
22492                        replica_id,
22493                        selection,
22494                        cursor_shape,
22495                        line_mode,
22496                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22497                        user_name,
22498                        color: if let Some(index) = participant_index {
22499                            cx.theme().players().color_for_participant(index.0)
22500                        } else {
22501                            cx.theme().players().absent()
22502                        },
22503                    })
22504                }
22505            })
22506    }
22507
22508    pub fn hunks_for_ranges(
22509        &self,
22510        ranges: impl IntoIterator<Item = Range<Point>>,
22511    ) -> Vec<MultiBufferDiffHunk> {
22512        let mut hunks = Vec::new();
22513        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22514            HashMap::default();
22515        for query_range in ranges {
22516            let query_rows =
22517                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22518            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22519                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22520            ) {
22521                // Include deleted hunks that are adjacent to the query range, because
22522                // otherwise they would be missed.
22523                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22524                if hunk.status().is_deleted() {
22525                    intersects_range |= hunk.row_range.start == query_rows.end;
22526                    intersects_range |= hunk.row_range.end == query_rows.start;
22527                }
22528                if intersects_range {
22529                    if !processed_buffer_rows
22530                        .entry(hunk.buffer_id)
22531                        .or_default()
22532                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22533                    {
22534                        continue;
22535                    }
22536                    hunks.push(hunk);
22537                }
22538            }
22539        }
22540
22541        hunks
22542    }
22543
22544    fn display_diff_hunks_for_rows<'a>(
22545        &'a self,
22546        display_rows: Range<DisplayRow>,
22547        folded_buffers: &'a HashSet<BufferId>,
22548    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22549        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22550        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22551
22552        self.buffer_snapshot
22553            .diff_hunks_in_range(buffer_start..buffer_end)
22554            .filter_map(|hunk| {
22555                if folded_buffers.contains(&hunk.buffer_id) {
22556                    return None;
22557                }
22558
22559                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22560                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22561
22562                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22563                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22564
22565                let display_hunk = if hunk_display_start.column() != 0 {
22566                    DisplayDiffHunk::Folded {
22567                        display_row: hunk_display_start.row(),
22568                    }
22569                } else {
22570                    let mut end_row = hunk_display_end.row();
22571                    if hunk_display_end.column() > 0 {
22572                        end_row.0 += 1;
22573                    }
22574                    let is_created_file = hunk.is_created_file();
22575                    DisplayDiffHunk::Unfolded {
22576                        status: hunk.status(),
22577                        diff_base_byte_range: hunk.diff_base_byte_range,
22578                        display_row_range: hunk_display_start.row()..end_row,
22579                        multi_buffer_range: Anchor::range_in_buffer(
22580                            hunk.excerpt_id,
22581                            hunk.buffer_id,
22582                            hunk.buffer_range,
22583                        ),
22584                        is_created_file,
22585                    }
22586                };
22587
22588                Some(display_hunk)
22589            })
22590    }
22591
22592    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22593        self.display_snapshot.buffer_snapshot.language_at(position)
22594    }
22595
22596    pub fn is_focused(&self) -> bool {
22597        self.is_focused
22598    }
22599
22600    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22601        self.placeholder_text.as_ref()
22602    }
22603
22604    pub fn scroll_position(&self) -> gpui::Point<f32> {
22605        self.scroll_anchor.scroll_position(&self.display_snapshot)
22606    }
22607
22608    fn gutter_dimensions(
22609        &self,
22610        font_id: FontId,
22611        font_size: Pixels,
22612        max_line_number_width: Pixels,
22613        cx: &App,
22614    ) -> Option<GutterDimensions> {
22615        if !self.show_gutter {
22616            return None;
22617        }
22618
22619        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22620        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22621
22622        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22623            matches!(
22624                ProjectSettings::get_global(cx).git.git_gutter,
22625                Some(GitGutterSetting::TrackedFiles)
22626            )
22627        });
22628        let gutter_settings = EditorSettings::get_global(cx).gutter;
22629        let show_line_numbers = self
22630            .show_line_numbers
22631            .unwrap_or(gutter_settings.line_numbers);
22632        let line_gutter_width = if show_line_numbers {
22633            // Avoid flicker-like gutter resizes when the line number gains another digit by
22634            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22635            let min_width_for_number_on_gutter =
22636                ch_advance * gutter_settings.min_line_number_digits as f32;
22637            max_line_number_width.max(min_width_for_number_on_gutter)
22638        } else {
22639            0.0.into()
22640        };
22641
22642        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22643        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22644
22645        let git_blame_entries_width =
22646            self.git_blame_gutter_max_author_length
22647                .map(|max_author_length| {
22648                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22649                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22650
22651                    /// The number of characters to dedicate to gaps and margins.
22652                    const SPACING_WIDTH: usize = 4;
22653
22654                    let max_char_count = max_author_length.min(renderer.max_author_length())
22655                        + ::git::SHORT_SHA_LENGTH
22656                        + MAX_RELATIVE_TIMESTAMP.len()
22657                        + SPACING_WIDTH;
22658
22659                    ch_advance * max_char_count
22660                });
22661
22662        let is_singleton = self.buffer_snapshot.is_singleton();
22663
22664        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22665        left_padding += if !is_singleton {
22666            ch_width * 4.0
22667        } else if show_runnables || show_breakpoints {
22668            ch_width * 3.0
22669        } else if show_git_gutter && show_line_numbers {
22670            ch_width * 2.0
22671        } else if show_git_gutter || show_line_numbers {
22672            ch_width
22673        } else {
22674            px(0.)
22675        };
22676
22677        let shows_folds = is_singleton && gutter_settings.folds;
22678
22679        let right_padding = if shows_folds && show_line_numbers {
22680            ch_width * 4.0
22681        } else if shows_folds || (!is_singleton && show_line_numbers) {
22682            ch_width * 3.0
22683        } else if show_line_numbers {
22684            ch_width
22685        } else {
22686            px(0.)
22687        };
22688
22689        Some(GutterDimensions {
22690            left_padding,
22691            right_padding,
22692            width: line_gutter_width + left_padding + right_padding,
22693            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22694            git_blame_entries_width,
22695        })
22696    }
22697
22698    pub fn render_crease_toggle(
22699        &self,
22700        buffer_row: MultiBufferRow,
22701        row_contains_cursor: bool,
22702        editor: Entity<Editor>,
22703        window: &mut Window,
22704        cx: &mut App,
22705    ) -> Option<AnyElement> {
22706        let folded = self.is_line_folded(buffer_row);
22707        let mut is_foldable = false;
22708
22709        if let Some(crease) = self
22710            .crease_snapshot
22711            .query_row(buffer_row, &self.buffer_snapshot)
22712        {
22713            is_foldable = true;
22714            match crease {
22715                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22716                    if let Some(render_toggle) = render_toggle {
22717                        let toggle_callback =
22718                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22719                                if folded {
22720                                    editor.update(cx, |editor, cx| {
22721                                        editor.fold_at(buffer_row, window, cx)
22722                                    });
22723                                } else {
22724                                    editor.update(cx, |editor, cx| {
22725                                        editor.unfold_at(buffer_row, window, cx)
22726                                    });
22727                                }
22728                            });
22729                        return Some((render_toggle)(
22730                            buffer_row,
22731                            folded,
22732                            toggle_callback,
22733                            window,
22734                            cx,
22735                        ));
22736                    }
22737                }
22738            }
22739        }
22740
22741        is_foldable |= self.starts_indent(buffer_row);
22742
22743        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22744            Some(
22745                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22746                    .toggle_state(folded)
22747                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22748                        if folded {
22749                            this.unfold_at(buffer_row, window, cx);
22750                        } else {
22751                            this.fold_at(buffer_row, window, cx);
22752                        }
22753                    }))
22754                    .into_any_element(),
22755            )
22756        } else {
22757            None
22758        }
22759    }
22760
22761    pub fn render_crease_trailer(
22762        &self,
22763        buffer_row: MultiBufferRow,
22764        window: &mut Window,
22765        cx: &mut App,
22766    ) -> Option<AnyElement> {
22767        let folded = self.is_line_folded(buffer_row);
22768        if let Crease::Inline { render_trailer, .. } = self
22769            .crease_snapshot
22770            .query_row(buffer_row, &self.buffer_snapshot)?
22771        {
22772            let render_trailer = render_trailer.as_ref()?;
22773            Some(render_trailer(buffer_row, folded, window, cx))
22774        } else {
22775            None
22776        }
22777    }
22778}
22779
22780impl Deref for EditorSnapshot {
22781    type Target = DisplaySnapshot;
22782
22783    fn deref(&self) -> &Self::Target {
22784        &self.display_snapshot
22785    }
22786}
22787
22788#[derive(Clone, Debug, PartialEq, Eq)]
22789pub enum EditorEvent {
22790    InputIgnored {
22791        text: Arc<str>,
22792    },
22793    InputHandled {
22794        utf16_range_to_replace: Option<Range<isize>>,
22795        text: Arc<str>,
22796    },
22797    ExcerptsAdded {
22798        buffer: Entity<Buffer>,
22799        predecessor: ExcerptId,
22800        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22801    },
22802    ExcerptsRemoved {
22803        ids: Vec<ExcerptId>,
22804        removed_buffer_ids: Vec<BufferId>,
22805    },
22806    BufferFoldToggled {
22807        ids: Vec<ExcerptId>,
22808        folded: bool,
22809    },
22810    ExcerptsEdited {
22811        ids: Vec<ExcerptId>,
22812    },
22813    ExcerptsExpanded {
22814        ids: Vec<ExcerptId>,
22815    },
22816    BufferEdited,
22817    Edited {
22818        transaction_id: clock::Lamport,
22819    },
22820    Reparsed(BufferId),
22821    Focused,
22822    FocusedIn,
22823    Blurred,
22824    DirtyChanged,
22825    Saved,
22826    TitleChanged,
22827    DiffBaseChanged,
22828    SelectionsChanged {
22829        local: bool,
22830    },
22831    ScrollPositionChanged {
22832        local: bool,
22833        autoscroll: bool,
22834    },
22835    Closed,
22836    TransactionUndone {
22837        transaction_id: clock::Lamport,
22838    },
22839    TransactionBegun {
22840        transaction_id: clock::Lamport,
22841    },
22842    Reloaded,
22843    CursorShapeChanged,
22844    BreadcrumbsChanged,
22845    PushedToNavHistory {
22846        anchor: Anchor,
22847        is_deactivate: bool,
22848    },
22849}
22850
22851impl EventEmitter<EditorEvent> for Editor {}
22852
22853impl Focusable for Editor {
22854    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22855        self.focus_handle.clone()
22856    }
22857}
22858
22859impl Render for Editor {
22860    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22861        let settings = ThemeSettings::get_global(cx);
22862
22863        let mut text_style = match self.mode {
22864            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22865                color: cx.theme().colors().editor_foreground,
22866                font_family: settings.ui_font.family.clone(),
22867                font_features: settings.ui_font.features.clone(),
22868                font_fallbacks: settings.ui_font.fallbacks.clone(),
22869                font_size: rems(0.875).into(),
22870                font_weight: settings.ui_font.weight,
22871                line_height: relative(settings.buffer_line_height.value()),
22872                ..Default::default()
22873            },
22874            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22875                color: cx.theme().colors().editor_foreground,
22876                font_family: settings.buffer_font.family.clone(),
22877                font_features: settings.buffer_font.features.clone(),
22878                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22879                font_size: settings.buffer_font_size(cx).into(),
22880                font_weight: settings.buffer_font.weight,
22881                line_height: relative(settings.buffer_line_height.value()),
22882                ..Default::default()
22883            },
22884        };
22885        if let Some(text_style_refinement) = &self.text_style_refinement {
22886            text_style.refine(text_style_refinement)
22887        }
22888
22889        let background = match self.mode {
22890            EditorMode::SingleLine => cx.theme().system().transparent,
22891            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22892            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22893            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22894        };
22895
22896        EditorElement::new(
22897            &cx.entity(),
22898            EditorStyle {
22899                background,
22900                border: cx.theme().colors().border,
22901                local_player: cx.theme().players().local(),
22902                text: text_style,
22903                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22904                syntax: cx.theme().syntax().clone(),
22905                status: cx.theme().status().clone(),
22906                inlay_hints_style: make_inlay_hints_style(cx),
22907                edit_prediction_styles: make_suggestion_styles(cx),
22908                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22909                show_underlines: self.diagnostics_enabled(),
22910            },
22911        )
22912    }
22913}
22914
22915impl EntityInputHandler for Editor {
22916    fn text_for_range(
22917        &mut self,
22918        range_utf16: Range<usize>,
22919        adjusted_range: &mut Option<Range<usize>>,
22920        _: &mut Window,
22921        cx: &mut Context<Self>,
22922    ) -> Option<String> {
22923        let snapshot = self.buffer.read(cx).read(cx);
22924        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22925        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22926        if (start.0..end.0) != range_utf16 {
22927            adjusted_range.replace(start.0..end.0);
22928        }
22929        Some(snapshot.text_for_range(start..end).collect())
22930    }
22931
22932    fn selected_text_range(
22933        &mut self,
22934        ignore_disabled_input: bool,
22935        _: &mut Window,
22936        cx: &mut Context<Self>,
22937    ) -> Option<UTF16Selection> {
22938        // Prevent the IME menu from appearing when holding down an alphabetic key
22939        // while input is disabled.
22940        if !ignore_disabled_input && !self.input_enabled {
22941            return None;
22942        }
22943
22944        let selection = self.selections.newest::<OffsetUtf16>(cx);
22945        let range = selection.range();
22946
22947        Some(UTF16Selection {
22948            range: range.start.0..range.end.0,
22949            reversed: selection.reversed,
22950        })
22951    }
22952
22953    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22954        let snapshot = self.buffer.read(cx).read(cx);
22955        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22956        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22957    }
22958
22959    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22960        self.clear_highlights::<InputComposition>(cx);
22961        self.ime_transaction.take();
22962    }
22963
22964    fn replace_text_in_range(
22965        &mut self,
22966        range_utf16: Option<Range<usize>>,
22967        text: &str,
22968        window: &mut Window,
22969        cx: &mut Context<Self>,
22970    ) {
22971        if !self.input_enabled {
22972            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22973            return;
22974        }
22975
22976        self.transact(window, cx, |this, window, cx| {
22977            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22978                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22979                Some(this.selection_replacement_ranges(range_utf16, cx))
22980            } else {
22981                this.marked_text_ranges(cx)
22982            };
22983
22984            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22985                let newest_selection_id = this.selections.newest_anchor().id;
22986                this.selections
22987                    .all::<OffsetUtf16>(cx)
22988                    .iter()
22989                    .zip(ranges_to_replace.iter())
22990                    .find_map(|(selection, range)| {
22991                        if selection.id == newest_selection_id {
22992                            Some(
22993                                (range.start.0 as isize - selection.head().0 as isize)
22994                                    ..(range.end.0 as isize - selection.head().0 as isize),
22995                            )
22996                        } else {
22997                            None
22998                        }
22999                    })
23000            });
23001
23002            cx.emit(EditorEvent::InputHandled {
23003                utf16_range_to_replace: range_to_replace,
23004                text: text.into(),
23005            });
23006
23007            if let Some(new_selected_ranges) = new_selected_ranges {
23008                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23009                    selections.select_ranges(new_selected_ranges)
23010                });
23011                this.backspace(&Default::default(), window, cx);
23012            }
23013
23014            this.handle_input(text, window, cx);
23015        });
23016
23017        if let Some(transaction) = self.ime_transaction {
23018            self.buffer.update(cx, |buffer, cx| {
23019                buffer.group_until_transaction(transaction, cx);
23020            });
23021        }
23022
23023        self.unmark_text(window, cx);
23024    }
23025
23026    fn replace_and_mark_text_in_range(
23027        &mut self,
23028        range_utf16: Option<Range<usize>>,
23029        text: &str,
23030        new_selected_range_utf16: Option<Range<usize>>,
23031        window: &mut Window,
23032        cx: &mut Context<Self>,
23033    ) {
23034        if !self.input_enabled {
23035            return;
23036        }
23037
23038        let transaction = self.transact(window, cx, |this, window, cx| {
23039            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23040                let snapshot = this.buffer.read(cx).read(cx);
23041                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23042                    for marked_range in &mut marked_ranges {
23043                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23044                        marked_range.start.0 += relative_range_utf16.start;
23045                        marked_range.start =
23046                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23047                        marked_range.end =
23048                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23049                    }
23050                }
23051                Some(marked_ranges)
23052            } else if let Some(range_utf16) = range_utf16 {
23053                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23054                Some(this.selection_replacement_ranges(range_utf16, cx))
23055            } else {
23056                None
23057            };
23058
23059            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23060                let newest_selection_id = this.selections.newest_anchor().id;
23061                this.selections
23062                    .all::<OffsetUtf16>(cx)
23063                    .iter()
23064                    .zip(ranges_to_replace.iter())
23065                    .find_map(|(selection, range)| {
23066                        if selection.id == newest_selection_id {
23067                            Some(
23068                                (range.start.0 as isize - selection.head().0 as isize)
23069                                    ..(range.end.0 as isize - selection.head().0 as isize),
23070                            )
23071                        } else {
23072                            None
23073                        }
23074                    })
23075            });
23076
23077            cx.emit(EditorEvent::InputHandled {
23078                utf16_range_to_replace: range_to_replace,
23079                text: text.into(),
23080            });
23081
23082            if let Some(ranges) = ranges_to_replace {
23083                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23084                    s.select_ranges(ranges)
23085                });
23086            }
23087
23088            let marked_ranges = {
23089                let snapshot = this.buffer.read(cx).read(cx);
23090                this.selections
23091                    .disjoint_anchors()
23092                    .iter()
23093                    .map(|selection| {
23094                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23095                    })
23096                    .collect::<Vec<_>>()
23097            };
23098
23099            if text.is_empty() {
23100                this.unmark_text(window, cx);
23101            } else {
23102                this.highlight_text::<InputComposition>(
23103                    marked_ranges.clone(),
23104                    HighlightStyle {
23105                        underline: Some(UnderlineStyle {
23106                            thickness: px(1.),
23107                            color: None,
23108                            wavy: false,
23109                        }),
23110                        ..Default::default()
23111                    },
23112                    cx,
23113                );
23114            }
23115
23116            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23117            let use_autoclose = this.use_autoclose;
23118            let use_auto_surround = this.use_auto_surround;
23119            this.set_use_autoclose(false);
23120            this.set_use_auto_surround(false);
23121            this.handle_input(text, window, cx);
23122            this.set_use_autoclose(use_autoclose);
23123            this.set_use_auto_surround(use_auto_surround);
23124
23125            if let Some(new_selected_range) = new_selected_range_utf16 {
23126                let snapshot = this.buffer.read(cx).read(cx);
23127                let new_selected_ranges = marked_ranges
23128                    .into_iter()
23129                    .map(|marked_range| {
23130                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23131                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23132                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23133                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23134                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23135                    })
23136                    .collect::<Vec<_>>();
23137
23138                drop(snapshot);
23139                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23140                    selections.select_ranges(new_selected_ranges)
23141                });
23142            }
23143        });
23144
23145        self.ime_transaction = self.ime_transaction.or(transaction);
23146        if let Some(transaction) = self.ime_transaction {
23147            self.buffer.update(cx, |buffer, cx| {
23148                buffer.group_until_transaction(transaction, cx);
23149            });
23150        }
23151
23152        if self.text_highlights::<InputComposition>(cx).is_none() {
23153            self.ime_transaction.take();
23154        }
23155    }
23156
23157    fn bounds_for_range(
23158        &mut self,
23159        range_utf16: Range<usize>,
23160        element_bounds: gpui::Bounds<Pixels>,
23161        window: &mut Window,
23162        cx: &mut Context<Self>,
23163    ) -> Option<gpui::Bounds<Pixels>> {
23164        let text_layout_details = self.text_layout_details(window);
23165        let CharacterDimensions {
23166            em_width,
23167            em_advance,
23168            line_height,
23169        } = self.character_dimensions(window);
23170
23171        let snapshot = self.snapshot(window, cx);
23172        let scroll_position = snapshot.scroll_position();
23173        let scroll_left = scroll_position.x * em_advance;
23174
23175        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23176        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23177            + self.gutter_dimensions.full_width();
23178        let y = line_height * (start.row().as_f32() - scroll_position.y);
23179
23180        Some(Bounds {
23181            origin: element_bounds.origin + point(x, y),
23182            size: size(em_width, line_height),
23183        })
23184    }
23185
23186    fn character_index_for_point(
23187        &mut self,
23188        point: gpui::Point<Pixels>,
23189        _window: &mut Window,
23190        _cx: &mut Context<Self>,
23191    ) -> Option<usize> {
23192        let position_map = self.last_position_map.as_ref()?;
23193        if !position_map.text_hitbox.contains(&point) {
23194            return None;
23195        }
23196        let display_point = position_map.point_for_position(point).previous_valid;
23197        let anchor = position_map
23198            .snapshot
23199            .display_point_to_anchor(display_point, Bias::Left);
23200        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23201        Some(utf16_offset.0)
23202    }
23203}
23204
23205trait SelectionExt {
23206    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23207    fn spanned_rows(
23208        &self,
23209        include_end_if_at_line_start: bool,
23210        map: &DisplaySnapshot,
23211    ) -> Range<MultiBufferRow>;
23212}
23213
23214impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23215    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23216        let start = self
23217            .start
23218            .to_point(&map.buffer_snapshot)
23219            .to_display_point(map);
23220        let end = self
23221            .end
23222            .to_point(&map.buffer_snapshot)
23223            .to_display_point(map);
23224        if self.reversed {
23225            end..start
23226        } else {
23227            start..end
23228        }
23229    }
23230
23231    fn spanned_rows(
23232        &self,
23233        include_end_if_at_line_start: bool,
23234        map: &DisplaySnapshot,
23235    ) -> Range<MultiBufferRow> {
23236        let start = self.start.to_point(&map.buffer_snapshot);
23237        let mut end = self.end.to_point(&map.buffer_snapshot);
23238        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23239            end.row -= 1;
23240        }
23241
23242        let buffer_start = map.prev_line_boundary(start).0;
23243        let buffer_end = map.next_line_boundary(end).0;
23244        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23245    }
23246}
23247
23248impl<T: InvalidationRegion> InvalidationStack<T> {
23249    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23250    where
23251        S: Clone + ToOffset,
23252    {
23253        while let Some(region) = self.last() {
23254            let all_selections_inside_invalidation_ranges =
23255                if selections.len() == region.ranges().len() {
23256                    selections
23257                        .iter()
23258                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23259                        .all(|(selection, invalidation_range)| {
23260                            let head = selection.head().to_offset(buffer);
23261                            invalidation_range.start <= head && invalidation_range.end >= head
23262                        })
23263                } else {
23264                    false
23265                };
23266
23267            if all_selections_inside_invalidation_ranges {
23268                break;
23269            } else {
23270                self.pop();
23271            }
23272        }
23273    }
23274}
23275
23276impl<T> Default for InvalidationStack<T> {
23277    fn default() -> Self {
23278        Self(Default::default())
23279    }
23280}
23281
23282impl<T> Deref for InvalidationStack<T> {
23283    type Target = Vec<T>;
23284
23285    fn deref(&self) -> &Self::Target {
23286        &self.0
23287    }
23288}
23289
23290impl<T> DerefMut for InvalidationStack<T> {
23291    fn deref_mut(&mut self) -> &mut Self::Target {
23292        &mut self.0
23293    }
23294}
23295
23296impl InvalidationRegion for SnippetState {
23297    fn ranges(&self) -> &[Range<Anchor>] {
23298        &self.ranges[self.active_index]
23299    }
23300}
23301
23302fn edit_prediction_edit_text(
23303    current_snapshot: &BufferSnapshot,
23304    edits: &[(Range<Anchor>, String)],
23305    edit_preview: &EditPreview,
23306    include_deletions: bool,
23307    cx: &App,
23308) -> HighlightedText {
23309    let edits = edits
23310        .iter()
23311        .map(|(anchor, text)| {
23312            (
23313                anchor.start.text_anchor..anchor.end.text_anchor,
23314                text.clone(),
23315            )
23316        })
23317        .collect::<Vec<_>>();
23318
23319    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23320}
23321
23322fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23323    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23324    // Just show the raw edit text with basic styling
23325    let mut text = String::new();
23326    let mut highlights = Vec::new();
23327
23328    let insertion_highlight_style = HighlightStyle {
23329        color: Some(cx.theme().colors().text),
23330        ..Default::default()
23331    };
23332
23333    for (_, edit_text) in edits {
23334        let start_offset = text.len();
23335        text.push_str(edit_text);
23336        let end_offset = text.len();
23337
23338        if start_offset < end_offset {
23339            highlights.push((start_offset..end_offset, insertion_highlight_style));
23340        }
23341    }
23342
23343    HighlightedText {
23344        text: text.into(),
23345        highlights,
23346    }
23347}
23348
23349pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23350    match severity {
23351        lsp::DiagnosticSeverity::ERROR => colors.error,
23352        lsp::DiagnosticSeverity::WARNING => colors.warning,
23353        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23354        lsp::DiagnosticSeverity::HINT => colors.info,
23355        _ => colors.ignored,
23356    }
23357}
23358
23359pub fn styled_runs_for_code_label<'a>(
23360    label: &'a CodeLabel,
23361    syntax_theme: &'a theme::SyntaxTheme,
23362) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23363    let fade_out = HighlightStyle {
23364        fade_out: Some(0.35),
23365        ..Default::default()
23366    };
23367
23368    let mut prev_end = label.filter_range.end;
23369    label
23370        .runs
23371        .iter()
23372        .enumerate()
23373        .flat_map(move |(ix, (range, highlight_id))| {
23374            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23375                style
23376            } else {
23377                return Default::default();
23378            };
23379            let mut muted_style = style;
23380            muted_style.highlight(fade_out);
23381
23382            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23383            if range.start >= label.filter_range.end {
23384                if range.start > prev_end {
23385                    runs.push((prev_end..range.start, fade_out));
23386                }
23387                runs.push((range.clone(), muted_style));
23388            } else if range.end <= label.filter_range.end {
23389                runs.push((range.clone(), style));
23390            } else {
23391                runs.push((range.start..label.filter_range.end, style));
23392                runs.push((label.filter_range.end..range.end, muted_style));
23393            }
23394            prev_end = cmp::max(prev_end, range.end);
23395
23396            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23397                runs.push((prev_end..label.text.len(), fade_out));
23398            }
23399
23400            runs
23401        })
23402}
23403
23404pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23405    let mut prev_index = 0;
23406    let mut prev_codepoint: Option<char> = None;
23407    text.char_indices()
23408        .chain([(text.len(), '\0')])
23409        .filter_map(move |(index, codepoint)| {
23410            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23411            let is_boundary = index == text.len()
23412                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23413                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23414            if is_boundary {
23415                let chunk = &text[prev_index..index];
23416                prev_index = index;
23417                Some(chunk)
23418            } else {
23419                None
23420            }
23421        })
23422}
23423
23424pub trait RangeToAnchorExt: Sized {
23425    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23426
23427    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23428        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23429        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23430    }
23431}
23432
23433impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23434    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23435        let start_offset = self.start.to_offset(snapshot);
23436        let end_offset = self.end.to_offset(snapshot);
23437        if start_offset == end_offset {
23438            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23439        } else {
23440            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23441        }
23442    }
23443}
23444
23445pub trait RowExt {
23446    fn as_f32(&self) -> f32;
23447
23448    fn next_row(&self) -> Self;
23449
23450    fn previous_row(&self) -> Self;
23451
23452    fn minus(&self, other: Self) -> u32;
23453}
23454
23455impl RowExt for DisplayRow {
23456    fn as_f32(&self) -> f32 {
23457        self.0 as f32
23458    }
23459
23460    fn next_row(&self) -> Self {
23461        Self(self.0 + 1)
23462    }
23463
23464    fn previous_row(&self) -> Self {
23465        Self(self.0.saturating_sub(1))
23466    }
23467
23468    fn minus(&self, other: Self) -> u32 {
23469        self.0 - other.0
23470    }
23471}
23472
23473impl RowExt for MultiBufferRow {
23474    fn as_f32(&self) -> f32 {
23475        self.0 as f32
23476    }
23477
23478    fn next_row(&self) -> Self {
23479        Self(self.0 + 1)
23480    }
23481
23482    fn previous_row(&self) -> Self {
23483        Self(self.0.saturating_sub(1))
23484    }
23485
23486    fn minus(&self, other: Self) -> u32 {
23487        self.0 - other.0
23488    }
23489}
23490
23491trait RowRangeExt {
23492    type Row;
23493
23494    fn len(&self) -> usize;
23495
23496    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23497}
23498
23499impl RowRangeExt for Range<MultiBufferRow> {
23500    type Row = MultiBufferRow;
23501
23502    fn len(&self) -> usize {
23503        (self.end.0 - self.start.0) as usize
23504    }
23505
23506    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23507        (self.start.0..self.end.0).map(MultiBufferRow)
23508    }
23509}
23510
23511impl RowRangeExt for Range<DisplayRow> {
23512    type Row = DisplayRow;
23513
23514    fn len(&self) -> usize {
23515        (self.end.0 - self.start.0) as usize
23516    }
23517
23518    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23519        (self.start.0..self.end.0).map(DisplayRow)
23520    }
23521}
23522
23523/// If select range has more than one line, we
23524/// just point the cursor to range.start.
23525fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23526    if range.start.row == range.end.row {
23527        range
23528    } else {
23529        range.start..range.start
23530    }
23531}
23532pub struct KillRing(ClipboardItem);
23533impl Global for KillRing {}
23534
23535const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23536
23537enum BreakpointPromptEditAction {
23538    Log,
23539    Condition,
23540    HitCondition,
23541}
23542
23543struct BreakpointPromptEditor {
23544    pub(crate) prompt: Entity<Editor>,
23545    editor: WeakEntity<Editor>,
23546    breakpoint_anchor: Anchor,
23547    breakpoint: Breakpoint,
23548    edit_action: BreakpointPromptEditAction,
23549    block_ids: HashSet<CustomBlockId>,
23550    editor_margins: Arc<Mutex<EditorMargins>>,
23551    _subscriptions: Vec<Subscription>,
23552}
23553
23554impl BreakpointPromptEditor {
23555    const MAX_LINES: u8 = 4;
23556
23557    fn new(
23558        editor: WeakEntity<Editor>,
23559        breakpoint_anchor: Anchor,
23560        breakpoint: Breakpoint,
23561        edit_action: BreakpointPromptEditAction,
23562        window: &mut Window,
23563        cx: &mut Context<Self>,
23564    ) -> Self {
23565        let base_text = match edit_action {
23566            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23567            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23568            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23569        }
23570        .map(|msg| msg.to_string())
23571        .unwrap_or_default();
23572
23573        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23574        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23575
23576        let prompt = cx.new(|cx| {
23577            let mut prompt = Editor::new(
23578                EditorMode::AutoHeight {
23579                    min_lines: 1,
23580                    max_lines: Some(Self::MAX_LINES as usize),
23581                },
23582                buffer,
23583                None,
23584                window,
23585                cx,
23586            );
23587            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23588            prompt.set_show_cursor_when_unfocused(false, cx);
23589            prompt.set_placeholder_text(
23590                match edit_action {
23591                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23592                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23593                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23594                },
23595                cx,
23596            );
23597
23598            prompt
23599        });
23600
23601        Self {
23602            prompt,
23603            editor,
23604            breakpoint_anchor,
23605            breakpoint,
23606            edit_action,
23607            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23608            block_ids: Default::default(),
23609            _subscriptions: vec![],
23610        }
23611    }
23612
23613    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23614        self.block_ids.extend(block_ids)
23615    }
23616
23617    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23618        if let Some(editor) = self.editor.upgrade() {
23619            let message = self
23620                .prompt
23621                .read(cx)
23622                .buffer
23623                .read(cx)
23624                .as_singleton()
23625                .expect("A multi buffer in breakpoint prompt isn't possible")
23626                .read(cx)
23627                .as_rope()
23628                .to_string();
23629
23630            editor.update(cx, |editor, cx| {
23631                editor.edit_breakpoint_at_anchor(
23632                    self.breakpoint_anchor,
23633                    self.breakpoint.clone(),
23634                    match self.edit_action {
23635                        BreakpointPromptEditAction::Log => {
23636                            BreakpointEditAction::EditLogMessage(message.into())
23637                        }
23638                        BreakpointPromptEditAction::Condition => {
23639                            BreakpointEditAction::EditCondition(message.into())
23640                        }
23641                        BreakpointPromptEditAction::HitCondition => {
23642                            BreakpointEditAction::EditHitCondition(message.into())
23643                        }
23644                    },
23645                    cx,
23646                );
23647
23648                editor.remove_blocks(self.block_ids.clone(), None, cx);
23649                cx.focus_self(window);
23650            });
23651        }
23652    }
23653
23654    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23655        self.editor
23656            .update(cx, |editor, cx| {
23657                editor.remove_blocks(self.block_ids.clone(), None, cx);
23658                window.focus(&editor.focus_handle);
23659            })
23660            .log_err();
23661    }
23662
23663    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23664        let settings = ThemeSettings::get_global(cx);
23665        let text_style = TextStyle {
23666            color: if self.prompt.read(cx).read_only(cx) {
23667                cx.theme().colors().text_disabled
23668            } else {
23669                cx.theme().colors().text
23670            },
23671            font_family: settings.buffer_font.family.clone(),
23672            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23673            font_size: settings.buffer_font_size(cx).into(),
23674            font_weight: settings.buffer_font.weight,
23675            line_height: relative(settings.buffer_line_height.value()),
23676            ..Default::default()
23677        };
23678        EditorElement::new(
23679            &self.prompt,
23680            EditorStyle {
23681                background: cx.theme().colors().editor_background,
23682                local_player: cx.theme().players().local(),
23683                text: text_style,
23684                ..Default::default()
23685            },
23686        )
23687    }
23688}
23689
23690impl Render for BreakpointPromptEditor {
23691    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23692        let editor_margins = *self.editor_margins.lock();
23693        let gutter_dimensions = editor_margins.gutter;
23694        h_flex()
23695            .key_context("Editor")
23696            .bg(cx.theme().colors().editor_background)
23697            .border_y_1()
23698            .border_color(cx.theme().status().info_border)
23699            .size_full()
23700            .py(window.line_height() / 2.5)
23701            .on_action(cx.listener(Self::confirm))
23702            .on_action(cx.listener(Self::cancel))
23703            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23704            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23705    }
23706}
23707
23708impl Focusable for BreakpointPromptEditor {
23709    fn focus_handle(&self, cx: &App) -> FocusHandle {
23710        self.prompt.focus_handle(cx)
23711    }
23712}
23713
23714fn all_edits_insertions_or_deletions(
23715    edits: &Vec<(Range<Anchor>, String)>,
23716    snapshot: &MultiBufferSnapshot,
23717) -> bool {
23718    let mut all_insertions = true;
23719    let mut all_deletions = true;
23720
23721    for (range, new_text) in edits.iter() {
23722        let range_is_empty = range.to_offset(snapshot).is_empty();
23723        let text_is_empty = new_text.is_empty();
23724
23725        if range_is_empty != text_is_empty {
23726            if range_is_empty {
23727                all_deletions = false;
23728            } else {
23729                all_insertions = false;
23730            }
23731        } else {
23732            return false;
23733        }
23734
23735        if !all_insertions && !all_deletions {
23736            return false;
23737        }
23738    }
23739    all_insertions || all_deletions
23740}
23741
23742struct MissingEditPredictionKeybindingTooltip;
23743
23744impl Render for MissingEditPredictionKeybindingTooltip {
23745    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23746        ui::tooltip_container(window, cx, |container, _, cx| {
23747            container
23748                .flex_shrink_0()
23749                .max_w_80()
23750                .min_h(rems_from_px(124.))
23751                .justify_between()
23752                .child(
23753                    v_flex()
23754                        .flex_1()
23755                        .text_ui_sm(cx)
23756                        .child(Label::new("Conflict with Accept Keybinding"))
23757                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23758                )
23759                .child(
23760                    h_flex()
23761                        .pb_1()
23762                        .gap_1()
23763                        .items_end()
23764                        .w_full()
23765                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23766                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23767                        }))
23768                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23769                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23770                        })),
23771                )
23772        })
23773    }
23774}
23775
23776#[derive(Debug, Clone, Copy, PartialEq)]
23777pub struct LineHighlight {
23778    pub background: Background,
23779    pub border: Option<gpui::Hsla>,
23780    pub include_gutter: bool,
23781    pub type_id: Option<TypeId>,
23782}
23783
23784struct LineManipulationResult {
23785    pub new_text: String,
23786    pub line_count_before: usize,
23787    pub line_count_after: usize,
23788}
23789
23790fn render_diff_hunk_controls(
23791    row: u32,
23792    status: &DiffHunkStatus,
23793    hunk_range: Range<Anchor>,
23794    is_created_file: bool,
23795    line_height: Pixels,
23796    editor: &Entity<Editor>,
23797    _window: &mut Window,
23798    cx: &mut App,
23799) -> AnyElement {
23800    h_flex()
23801        .h(line_height)
23802        .mr_1()
23803        .gap_1()
23804        .px_0p5()
23805        .pb_1()
23806        .border_x_1()
23807        .border_b_1()
23808        .border_color(cx.theme().colors().border_variant)
23809        .rounded_b_lg()
23810        .bg(cx.theme().colors().editor_background)
23811        .gap_1()
23812        .block_mouse_except_scroll()
23813        .shadow_md()
23814        .child(if status.has_secondary_hunk() {
23815            Button::new(("stage", row as u64), "Stage")
23816                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23817                .tooltip({
23818                    let focus_handle = editor.focus_handle(cx);
23819                    move |window, cx| {
23820                        Tooltip::for_action_in(
23821                            "Stage Hunk",
23822                            &::git::ToggleStaged,
23823                            &focus_handle,
23824                            window,
23825                            cx,
23826                        )
23827                    }
23828                })
23829                .on_click({
23830                    let editor = editor.clone();
23831                    move |_event, _window, cx| {
23832                        editor.update(cx, |editor, cx| {
23833                            editor.stage_or_unstage_diff_hunks(
23834                                true,
23835                                vec![hunk_range.start..hunk_range.start],
23836                                cx,
23837                            );
23838                        });
23839                    }
23840                })
23841        } else {
23842            Button::new(("unstage", row as u64), "Unstage")
23843                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23844                .tooltip({
23845                    let focus_handle = editor.focus_handle(cx);
23846                    move |window, cx| {
23847                        Tooltip::for_action_in(
23848                            "Unstage Hunk",
23849                            &::git::ToggleStaged,
23850                            &focus_handle,
23851                            window,
23852                            cx,
23853                        )
23854                    }
23855                })
23856                .on_click({
23857                    let editor = editor.clone();
23858                    move |_event, _window, cx| {
23859                        editor.update(cx, |editor, cx| {
23860                            editor.stage_or_unstage_diff_hunks(
23861                                false,
23862                                vec![hunk_range.start..hunk_range.start],
23863                                cx,
23864                            );
23865                        });
23866                    }
23867                })
23868        })
23869        .child(
23870            Button::new(("restore", row as u64), "Restore")
23871                .tooltip({
23872                    let focus_handle = editor.focus_handle(cx);
23873                    move |window, cx| {
23874                        Tooltip::for_action_in(
23875                            "Restore Hunk",
23876                            &::git::Restore,
23877                            &focus_handle,
23878                            window,
23879                            cx,
23880                        )
23881                    }
23882                })
23883                .on_click({
23884                    let editor = editor.clone();
23885                    move |_event, window, cx| {
23886                        editor.update(cx, |editor, cx| {
23887                            let snapshot = editor.snapshot(window, cx);
23888                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23889                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23890                        });
23891                    }
23892                })
23893                .disabled(is_created_file),
23894        )
23895        .when(
23896            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23897            |el| {
23898                el.child(
23899                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23900                        .shape(IconButtonShape::Square)
23901                        .icon_size(IconSize::Small)
23902                        // .disabled(!has_multiple_hunks)
23903                        .tooltip({
23904                            let focus_handle = editor.focus_handle(cx);
23905                            move |window, cx| {
23906                                Tooltip::for_action_in(
23907                                    "Next Hunk",
23908                                    &GoToHunk,
23909                                    &focus_handle,
23910                                    window,
23911                                    cx,
23912                                )
23913                            }
23914                        })
23915                        .on_click({
23916                            let editor = editor.clone();
23917                            move |_event, window, cx| {
23918                                editor.update(cx, |editor, cx| {
23919                                    let snapshot = editor.snapshot(window, cx);
23920                                    let position =
23921                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23922                                    editor.go_to_hunk_before_or_after_position(
23923                                        &snapshot,
23924                                        position,
23925                                        Direction::Next,
23926                                        window,
23927                                        cx,
23928                                    );
23929                                    editor.expand_selected_diff_hunks(cx);
23930                                });
23931                            }
23932                        }),
23933                )
23934                .child(
23935                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23936                        .shape(IconButtonShape::Square)
23937                        .icon_size(IconSize::Small)
23938                        // .disabled(!has_multiple_hunks)
23939                        .tooltip({
23940                            let focus_handle = editor.focus_handle(cx);
23941                            move |window, cx| {
23942                                Tooltip::for_action_in(
23943                                    "Previous Hunk",
23944                                    &GoToPreviousHunk,
23945                                    &focus_handle,
23946                                    window,
23947                                    cx,
23948                                )
23949                            }
23950                        })
23951                        .on_click({
23952                            let editor = editor.clone();
23953                            move |_event, window, cx| {
23954                                editor.update(cx, |editor, cx| {
23955                                    let snapshot = editor.snapshot(window, cx);
23956                                    let point =
23957                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23958                                    editor.go_to_hunk_before_or_after_position(
23959                                        &snapshot,
23960                                        point,
23961                                        Direction::Prev,
23962                                        window,
23963                                        cx,
23964                                    );
23965                                    editor.expand_selected_diff_hunks(cx);
23966                                });
23967                            }
23968                        }),
23969                )
23970            },
23971        )
23972        .into_any_element()
23973}