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//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction_types::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction_types::{EditPredictionDelegate, EditPredictionDelegateHandle};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, Render,
  111    ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle,
  112    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
  113    WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,
  114};
  115use hover_links::{HoverLink, HoveredLinkState, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  125    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143};
  144use parking_lot::Mutex;
  145use persistence::DB;
  146use project::{
  147    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  148    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  149    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  150    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  151    debugger::{
  152        breakpoint_store::{
  153            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  154            BreakpointStore, BreakpointStoreEvent,
  155        },
  156        session::{Session, SessionEvent},
  157    },
  158    git_store::GitStoreEvent,
  159    lsp_store::{
  160        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  161        OpenLspBufferHandle,
  162    },
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  169use serde::{Deserialize, Serialize};
  170use settings::{
  171    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  172    update_settings_file,
  173};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::{Any, TypeId},
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    collections::hash_map,
  182    iter::{self, Peekable},
  183    mem,
  184    num::NonZeroU32,
  185    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  193use theme::{
  194    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    inlays::{
  216        InlineValueCache,
  217        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  218    },
  219    scroll::{ScrollOffset, ScrollPixelOffset},
  220    selections_collection::resolve_selections_wrapping_blocks,
  221    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  222};
  223
  224pub const FILE_HEADER_HEIGHT: u32 = 2;
  225pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  226const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  227const MAX_LINE_LEN: usize = 1024;
  228const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  229const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  230pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  231#[doc(hidden)]
  232pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  233pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  234
  235pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  236pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  238pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  239
  240pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  241pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  242pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  243
  244pub type RenderDiffHunkControlsFn = Arc<
  245    dyn Fn(
  246        u32,
  247        &DiffHunkStatus,
  248        Range<Anchor>,
  249        bool,
  250        Pixels,
  251        &Entity<Editor>,
  252        &mut Window,
  253        &mut App,
  254    ) -> AnyElement,
  255>;
  256
  257enum ReportEditorEvent {
  258    Saved { auto_saved: bool },
  259    EditorOpened,
  260    Closed,
  261}
  262
  263impl ReportEditorEvent {
  264    pub fn event_type(&self) -> &'static str {
  265        match self {
  266            Self::Saved { .. } => "Editor Saved",
  267            Self::EditorOpened => "Editor Opened",
  268            Self::Closed => "Editor Closed",
  269        }
  270    }
  271}
  272
  273pub enum ActiveDebugLine {}
  274pub enum DebugStackFrameLine {}
  275enum DocumentHighlightRead {}
  276enum DocumentHighlightWrite {}
  277enum InputComposition {}
  278pub enum PendingInput {}
  279enum SelectedTextHighlight {}
  280
  281pub enum ConflictsOuter {}
  282pub enum ConflictsOurs {}
  283pub enum ConflictsTheirs {}
  284pub enum ConflictsOursMarker {}
  285pub enum ConflictsTheirsMarker {}
  286
  287pub struct HunkAddedColor;
  288pub struct HunkRemovedColor;
  289
  290#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  291pub enum Navigated {
  292    Yes,
  293    No,
  294}
  295
  296impl Navigated {
  297    pub fn from_bool(yes: bool) -> Navigated {
  298        if yes { Navigated::Yes } else { Navigated::No }
  299    }
  300}
  301
  302#[derive(Debug, Clone, PartialEq, Eq)]
  303enum DisplayDiffHunk {
  304    Folded {
  305        display_row: DisplayRow,
  306    },
  307    Unfolded {
  308        is_created_file: bool,
  309        diff_base_byte_range: Range<usize>,
  310        display_row_range: Range<DisplayRow>,
  311        multi_buffer_range: Range<Anchor>,
  312        status: DiffHunkStatus,
  313        word_diffs: Vec<Range<MultiBufferOffset>>,
  314    },
  315}
  316
  317pub enum HideMouseCursorOrigin {
  318    TypingAction,
  319    MovementAction,
  320}
  321
  322pub fn init(cx: &mut App) {
  323    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  324
  325    workspace::register_project_item::<Editor>(cx);
  326    workspace::FollowableViewRegistry::register::<Editor>(cx);
  327    workspace::register_serializable_item::<Editor>(cx);
  328
  329    cx.observe_new(
  330        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  331            workspace.register_action(Editor::new_file);
  332            workspace.register_action(Editor::new_file_split);
  333            workspace.register_action(Editor::new_file_vertical);
  334            workspace.register_action(Editor::new_file_horizontal);
  335            workspace.register_action(Editor::cancel_language_server_work);
  336            workspace.register_action(Editor::toggle_focus);
  337        },
  338    )
  339    .detach();
  340
  341    cx.on_action(move |_: &workspace::NewFile, cx| {
  342        let app_state = workspace::AppState::global(cx);
  343        if let Some(app_state) = app_state.upgrade() {
  344            workspace::open_new(
  345                Default::default(),
  346                app_state,
  347                cx,
  348                |workspace, window, cx| {
  349                    Editor::new_file(workspace, &Default::default(), window, cx)
  350                },
  351            )
  352            .detach();
  353        }
  354    });
  355    cx.on_action(move |_: &workspace::NewWindow, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    cx.activate(true);
  364                    Editor::new_file(workspace, &Default::default(), window, cx)
  365                },
  366            )
  367            .detach();
  368        }
  369    });
  370}
  371
  372pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  373    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  374}
  375
  376pub trait DiagnosticRenderer {
  377    fn render_group(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        buffer_id: BufferId,
  381        snapshot: EditorSnapshot,
  382        editor: WeakEntity<Editor>,
  383        language_registry: Option<Arc<LanguageRegistry>>,
  384        cx: &mut App,
  385    ) -> Vec<BlockProperties<Anchor>>;
  386
  387    fn render_hover(
  388        &self,
  389        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  390        range: Range<Point>,
  391        buffer_id: BufferId,
  392        language_registry: Option<Arc<LanguageRegistry>>,
  393        cx: &mut App,
  394    ) -> Option<Entity<markdown::Markdown>>;
  395
  396    fn open_link(
  397        &self,
  398        editor: &mut Editor,
  399        link: SharedString,
  400        window: &mut Window,
  401        cx: &mut Context<Editor>,
  402    );
  403}
  404
  405pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  406
  407impl GlobalDiagnosticRenderer {
  408    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  409        cx.try_global::<Self>().map(|g| g.0.clone())
  410    }
  411}
  412
  413impl gpui::Global for GlobalDiagnosticRenderer {}
  414pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  415    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  416}
  417
  418pub struct SearchWithinRange;
  419
  420trait InvalidationRegion {
  421    fn ranges(&self) -> &[Range<Anchor>];
  422}
  423
  424#[derive(Clone, Debug, PartialEq)]
  425pub enum SelectPhase {
  426    Begin {
  427        position: DisplayPoint,
  428        add: bool,
  429        click_count: usize,
  430    },
  431    BeginColumnar {
  432        position: DisplayPoint,
  433        reset: bool,
  434        mode: ColumnarMode,
  435        goal_column: u32,
  436    },
  437    Extend {
  438        position: DisplayPoint,
  439        click_count: usize,
  440    },
  441    Update {
  442        position: DisplayPoint,
  443        goal_column: u32,
  444        scroll_delta: gpui::Point<f32>,
  445    },
  446    End,
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum ColumnarMode {
  451    FromMouse,
  452    FromSelection,
  453}
  454
  455#[derive(Clone, Debug)]
  456pub enum SelectMode {
  457    Character,
  458    Word(Range<Anchor>),
  459    Line(Range<Anchor>),
  460    All,
  461}
  462
  463#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  464pub enum SizingBehavior {
  465    /// The editor will layout itself using `size_full` and will include the vertical
  466    /// scroll margin as requested by user settings.
  467    #[default]
  468    Default,
  469    /// The editor will layout itself using `size_full`, but will not have any
  470    /// vertical overscroll.
  471    ExcludeOverscrollMargin,
  472    /// The editor will request a vertical size according to its content and will be
  473    /// layouted without a vertical scroll margin.
  474    SizeByContent,
  475}
  476
  477#[derive(Clone, PartialEq, Eq, Debug)]
  478pub enum EditorMode {
  479    SingleLine,
  480    AutoHeight {
  481        min_lines: usize,
  482        max_lines: Option<usize>,
  483    },
  484    Full {
  485        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  486        scale_ui_elements_with_buffer_font_size: bool,
  487        /// When set to `true`, the editor will render a background for the active line.
  488        show_active_line_background: bool,
  489        /// Determines the sizing behavior for this editor
  490        sizing_behavior: SizingBehavior,
  491    },
  492    Minimap {
  493        parent: WeakEntity<Editor>,
  494    },
  495}
  496
  497impl EditorMode {
  498    pub fn full() -> Self {
  499        Self::Full {
  500            scale_ui_elements_with_buffer_font_size: true,
  501            show_active_line_background: true,
  502            sizing_behavior: SizingBehavior::Default,
  503        }
  504    }
  505
  506    #[inline]
  507    pub fn is_full(&self) -> bool {
  508        matches!(self, Self::Full { .. })
  509    }
  510
  511    #[inline]
  512    pub fn is_single_line(&self) -> bool {
  513        matches!(self, Self::SingleLine { .. })
  514    }
  515
  516    #[inline]
  517    fn is_minimap(&self) -> bool {
  518        matches!(self, Self::Minimap { .. })
  519    }
  520}
  521
  522#[derive(Copy, Clone, Debug)]
  523pub enum SoftWrap {
  524    /// Prefer not to wrap at all.
  525    ///
  526    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  527    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  528    GitDiff,
  529    /// Prefer a single line generally, unless an overly long line is encountered.
  530    None,
  531    /// Soft wrap lines that exceed the editor width.
  532    EditorWidth,
  533    /// Soft wrap lines at the preferred line length.
  534    Column(u32),
  535    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  536    Bounded(u32),
  537}
  538
  539#[derive(Clone)]
  540pub struct EditorStyle {
  541    pub background: Hsla,
  542    pub border: Hsla,
  543    pub local_player: PlayerColor,
  544    pub text: TextStyle,
  545    pub scrollbar_width: Pixels,
  546    pub syntax: Arc<SyntaxTheme>,
  547    pub status: StatusColors,
  548    pub inlay_hints_style: HighlightStyle,
  549    pub edit_prediction_styles: EditPredictionStyles,
  550    pub unnecessary_code_fade: f32,
  551    pub show_underlines: bool,
  552}
  553
  554impl Default for EditorStyle {
  555    fn default() -> Self {
  556        Self {
  557            background: Hsla::default(),
  558            border: Hsla::default(),
  559            local_player: PlayerColor::default(),
  560            text: TextStyle::default(),
  561            scrollbar_width: Pixels::default(),
  562            syntax: Default::default(),
  563            // HACK: Status colors don't have a real default.
  564            // We should look into removing the status colors from the editor
  565            // style and retrieve them directly from the theme.
  566            status: StatusColors::dark(),
  567            inlay_hints_style: HighlightStyle::default(),
  568            edit_prediction_styles: EditPredictionStyles {
  569                insertion: HighlightStyle::default(),
  570                whitespace: HighlightStyle::default(),
  571            },
  572            unnecessary_code_fade: Default::default(),
  573            show_underlines: true,
  574        }
  575    }
  576}
  577
  578pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  579    let show_background = language_settings::language_settings(None, None, cx)
  580        .inlay_hints
  581        .show_background;
  582
  583    let mut style = cx.theme().syntax().get("hint");
  584
  585    if style.color.is_none() {
  586        style.color = Some(cx.theme().status().hint);
  587    }
  588
  589    if !show_background {
  590        style.background_color = None;
  591        return style;
  592    }
  593
  594    if style.background_color.is_none() {
  595        style.background_color = Some(cx.theme().status().hint_background);
  596    }
  597
  598    style
  599}
  600
  601pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  602    EditPredictionStyles {
  603        insertion: HighlightStyle {
  604            color: Some(cx.theme().status().predictive),
  605            ..HighlightStyle::default()
  606        },
  607        whitespace: HighlightStyle {
  608            background_color: Some(cx.theme().status().created_background),
  609            ..HighlightStyle::default()
  610        },
  611    }
  612}
  613
  614type CompletionId = usize;
  615
  616pub(crate) enum EditDisplayMode {
  617    TabAccept,
  618    DiffPopover,
  619    Inline,
  620}
  621
  622enum EditPrediction {
  623    Edit {
  624        edits: Vec<(Range<Anchor>, Arc<str>)>,
  625        edit_preview: Option<EditPreview>,
  626        display_mode: EditDisplayMode,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in the active editor
  630    MoveWithin {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634    /// Move to a specific location in a different editor (not the active one)
  635    MoveOutside {
  636        target: language::Anchor,
  637        snapshot: BufferSnapshot,
  638    },
  639}
  640
  641struct EditPredictionState {
  642    inlay_ids: Vec<InlayId>,
  643    completion: EditPrediction,
  644    completion_id: Option<SharedString>,
  645    invalidation_range: Option<Range<Anchor>>,
  646}
  647
  648enum EditPredictionSettings {
  649    Disabled,
  650    Enabled {
  651        show_in_menu: bool,
  652        preview_requires_modifier: bool,
  653    },
  654}
  655
  656enum EditPredictionHighlight {}
  657
  658#[derive(Debug, Clone)]
  659struct InlineDiagnostic {
  660    message: SharedString,
  661    group_id: usize,
  662    is_primary: bool,
  663    start: Point,
  664    severity: lsp::DiagnosticSeverity,
  665}
  666
  667pub enum MenuEditPredictionsPolicy {
  668    Never,
  669    ByProvider,
  670}
  671
  672pub enum EditPredictionPreview {
  673    /// Modifier is not pressed
  674    Inactive { released_too_fast: bool },
  675    /// Modifier pressed
  676    Active {
  677        since: Instant,
  678        previous_scroll_position: Option<ScrollAnchor>,
  679    },
  680}
  681
  682impl EditPredictionPreview {
  683    pub fn released_too_fast(&self) -> bool {
  684        match self {
  685            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  686            EditPredictionPreview::Active { .. } => false,
  687        }
  688    }
  689
  690    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  691        if let EditPredictionPreview::Active {
  692            previous_scroll_position,
  693            ..
  694        } = self
  695        {
  696            *previous_scroll_position = scroll_position;
  697        }
  698    }
  699}
  700
  701pub struct ContextMenuOptions {
  702    pub min_entries_visible: usize,
  703    pub max_entries_visible: usize,
  704    pub placement: Option<ContextMenuPlacement>,
  705}
  706
  707#[derive(Debug, Clone, PartialEq, Eq)]
  708pub enum ContextMenuPlacement {
  709    Above,
  710    Below,
  711}
  712
  713#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  714struct EditorActionId(usize);
  715
  716impl EditorActionId {
  717    pub fn post_inc(&mut self) -> Self {
  718        let answer = self.0;
  719
  720        *self = Self(answer + 1);
  721
  722        Self(answer)
  723    }
  724}
  725
  726// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  727// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  728
  729type BackgroundHighlight = (
  730    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  731    Arc<[Range<Anchor>]>,
  732);
  733type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  734
  735#[derive(Default)]
  736struct ScrollbarMarkerState {
  737    scrollbar_size: Size<Pixels>,
  738    dirty: bool,
  739    markers: Arc<[PaintQuad]>,
  740    pending_refresh: Option<Task<Result<()>>>,
  741}
  742
  743impl ScrollbarMarkerState {
  744    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  745        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  746    }
  747}
  748
  749#[derive(Clone, Copy, PartialEq, Eq)]
  750pub enum MinimapVisibility {
  751    Disabled,
  752    Enabled {
  753        /// The configuration currently present in the users settings.
  754        setting_configuration: bool,
  755        /// Whether to override the currently set visibility from the users setting.
  756        toggle_override: bool,
  757    },
  758}
  759
  760impl MinimapVisibility {
  761    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  762        if mode.is_full() {
  763            Self::Enabled {
  764                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  765                toggle_override: false,
  766            }
  767        } else {
  768            Self::Disabled
  769        }
  770    }
  771
  772    fn hidden(&self) -> Self {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                ..
  777            } => Self::Enabled {
  778                setting_configuration,
  779                toggle_override: setting_configuration,
  780            },
  781            Self::Disabled => Self::Disabled,
  782        }
  783    }
  784
  785    fn disabled(&self) -> bool {
  786        matches!(*self, Self::Disabled)
  787    }
  788
  789    fn settings_visibility(&self) -> bool {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                ..
  794            } => setting_configuration,
  795            _ => false,
  796        }
  797    }
  798
  799    fn visible(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                toggle_override,
  804            } => setting_configuration ^ toggle_override,
  805            _ => false,
  806        }
  807    }
  808
  809    fn toggle_visibility(&self) -> Self {
  810        match *self {
  811            Self::Enabled {
  812                toggle_override,
  813                setting_configuration,
  814            } => Self::Enabled {
  815                setting_configuration,
  816                toggle_override: !toggle_override,
  817            },
  818            Self::Disabled => Self::Disabled,
  819        }
  820    }
  821}
  822
  823#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  824pub enum BufferSerialization {
  825    All,
  826    NonDirtyBuffers,
  827}
  828
  829impl BufferSerialization {
  830    fn new(restore_unsaved_buffers: bool) -> Self {
  831        if restore_unsaved_buffers {
  832            Self::All
  833        } else {
  834            Self::NonDirtyBuffers
  835        }
  836    }
  837}
  838
  839#[derive(Clone, Debug)]
  840struct RunnableTasks {
  841    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  842    offset: multi_buffer::Anchor,
  843    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  844    column: u32,
  845    // Values of all named captures, including those starting with '_'
  846    extra_variables: HashMap<String, String>,
  847    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  848    context_range: Range<BufferOffset>,
  849}
  850
  851impl RunnableTasks {
  852    fn resolve<'a>(
  853        &'a self,
  854        cx: &'a task::TaskContext,
  855    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  856        self.templates.iter().filter_map(|(kind, template)| {
  857            template
  858                .resolve_task(&kind.to_id_base(), cx)
  859                .map(|task| (kind.clone(), task))
  860        })
  861    }
  862}
  863
  864#[derive(Clone)]
  865pub struct ResolvedTasks {
  866    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  867    position: Anchor,
  868}
  869
  870/// Addons allow storing per-editor state in other crates (e.g. Vim)
  871pub trait Addon: 'static {
  872    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  873
  874    fn render_buffer_header_controls(
  875        &self,
  876        _: &ExcerptInfo,
  877        _: &Window,
  878        _: &App,
  879    ) -> Option<AnyElement> {
  880        None
  881    }
  882
  883    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  884        None
  885    }
  886
  887    fn to_any(&self) -> &dyn std::any::Any;
  888
  889    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  890        None
  891    }
  892}
  893
  894struct ChangeLocation {
  895    current: Option<Vec<Anchor>>,
  896    original: Vec<Anchor>,
  897}
  898impl ChangeLocation {
  899    fn locations(&self) -> &[Anchor] {
  900        self.current.as_ref().unwrap_or(&self.original)
  901    }
  902}
  903
  904/// A set of caret positions, registered when the editor was edited.
  905pub struct ChangeList {
  906    changes: Vec<ChangeLocation>,
  907    /// Currently "selected" change.
  908    position: Option<usize>,
  909}
  910
  911impl ChangeList {
  912    pub fn new() -> Self {
  913        Self {
  914            changes: Vec::new(),
  915            position: None,
  916        }
  917    }
  918
  919    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  920    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  921    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  922        if self.changes.is_empty() {
  923            return None;
  924        }
  925
  926        let prev = self.position.unwrap_or(self.changes.len());
  927        let next = if direction == Direction::Prev {
  928            prev.saturating_sub(count)
  929        } else {
  930            (prev + count).min(self.changes.len() - 1)
  931        };
  932        self.position = Some(next);
  933        self.changes.get(next).map(|change| change.locations())
  934    }
  935
  936    /// Adds a new change to the list, resetting the change list position.
  937    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  938        self.position.take();
  939        if let Some(last) = self.changes.last_mut()
  940            && group
  941        {
  942            last.current = Some(new_positions)
  943        } else {
  944            self.changes.push(ChangeLocation {
  945                original: new_positions,
  946                current: None,
  947            });
  948        }
  949    }
  950
  951    pub fn last(&self) -> Option<&[Anchor]> {
  952        self.changes.last().map(|change| change.locations())
  953    }
  954
  955    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  956        self.changes.last().map(|change| change.original.as_slice())
  957    }
  958
  959    pub fn invert_last_group(&mut self) {
  960        if let Some(last) = self.changes.last_mut()
  961            && let Some(current) = last.current.as_mut()
  962        {
  963            mem::swap(&mut last.original, current);
  964        }
  965    }
  966}
  967
  968#[derive(Clone)]
  969struct InlineBlamePopoverState {
  970    scroll_handle: ScrollHandle,
  971    commit_message: Option<ParsedCommitMessage>,
  972    markdown: Entity<Markdown>,
  973}
  974
  975struct InlineBlamePopover {
  976    position: gpui::Point<Pixels>,
  977    hide_task: Option<Task<()>>,
  978    popover_bounds: Option<Bounds<Pixels>>,
  979    popover_state: InlineBlamePopoverState,
  980    keyboard_grace: bool,
  981}
  982
  983enum SelectionDragState {
  984    /// State when no drag related activity is detected.
  985    None,
  986    /// State when the mouse is down on a selection that is about to be dragged.
  987    ReadyToDrag {
  988        selection: Selection<Anchor>,
  989        click_position: gpui::Point<Pixels>,
  990        mouse_down_time: Instant,
  991    },
  992    /// State when the mouse is dragging the selection in the editor.
  993    Dragging {
  994        selection: Selection<Anchor>,
  995        drop_cursor: Selection<Anchor>,
  996        hide_drop_cursor: bool,
  997    },
  998}
  999
 1000enum ColumnarSelectionState {
 1001    FromMouse {
 1002        selection_tail: Anchor,
 1003        display_point: Option<DisplayPoint>,
 1004    },
 1005    FromSelection {
 1006        selection_tail: Anchor,
 1007    },
 1008}
 1009
 1010/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1011/// a breakpoint on them.
 1012#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1013struct PhantomBreakpointIndicator {
 1014    display_row: DisplayRow,
 1015    /// There's a small debounce between hovering over the line and showing the indicator.
 1016    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1017    is_active: bool,
 1018    collides_with_existing_breakpoint: bool,
 1019}
 1020
 1021/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1022///
 1023/// See the [module level documentation](self) for more information.
 1024pub struct Editor {
 1025    focus_handle: FocusHandle,
 1026    last_focused_descendant: Option<WeakFocusHandle>,
 1027    /// The text buffer being edited
 1028    buffer: Entity<MultiBuffer>,
 1029    /// Map of how text in the buffer should be displayed.
 1030    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1031    pub display_map: Entity<DisplayMap>,
 1032    placeholder_display_map: Option<Entity<DisplayMap>>,
 1033    pub selections: SelectionsCollection,
 1034    pub scroll_manager: ScrollManager,
 1035    /// When inline assist editors are linked, they all render cursors because
 1036    /// typing enters text into each of them, even the ones that aren't focused.
 1037    pub(crate) show_cursor_when_unfocused: bool,
 1038    columnar_selection_state: Option<ColumnarSelectionState>,
 1039    add_selections_state: Option<AddSelectionsState>,
 1040    select_next_state: Option<SelectNextState>,
 1041    select_prev_state: Option<SelectNextState>,
 1042    selection_history: SelectionHistory,
 1043    defer_selection_effects: bool,
 1044    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1045    autoclose_regions: Vec<AutocloseRegion>,
 1046    snippet_stack: InvalidationStack<SnippetState>,
 1047    select_syntax_node_history: SelectSyntaxNodeHistory,
 1048    ime_transaction: Option<TransactionId>,
 1049    pub diagnostics_max_severity: DiagnosticSeverity,
 1050    active_diagnostics: ActiveDiagnostic,
 1051    show_inline_diagnostics: bool,
 1052    inline_diagnostics_update: Task<()>,
 1053    inline_diagnostics_enabled: bool,
 1054    diagnostics_enabled: bool,
 1055    word_completions_enabled: bool,
 1056    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1057    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1058    hard_wrap: Option<usize>,
 1059    project: Option<Entity<Project>>,
 1060    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1061    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1062    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1063    blink_manager: Entity<BlinkManager>,
 1064    show_cursor_names: bool,
 1065    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1066    pub show_local_selections: bool,
 1067    mode: EditorMode,
 1068    show_breadcrumbs: bool,
 1069    show_gutter: bool,
 1070    show_scrollbars: ScrollbarAxes,
 1071    minimap_visibility: MinimapVisibility,
 1072    offset_content: bool,
 1073    disable_expand_excerpt_buttons: bool,
 1074    show_line_numbers: Option<bool>,
 1075    use_relative_line_numbers: Option<bool>,
 1076    show_git_diff_gutter: Option<bool>,
 1077    show_code_actions: Option<bool>,
 1078    show_runnables: Option<bool>,
 1079    show_breakpoints: Option<bool>,
 1080    show_wrap_guides: Option<bool>,
 1081    show_indent_guides: Option<bool>,
 1082    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1083    highlight_order: usize,
 1084    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1085    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1086    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1087    scrollbar_marker_state: ScrollbarMarkerState,
 1088    active_indent_guides_state: ActiveIndentGuidesState,
 1089    nav_history: Option<ItemNavHistory>,
 1090    context_menu: RefCell<Option<CodeContextMenu>>,
 1091    context_menu_options: Option<ContextMenuOptions>,
 1092    mouse_context_menu: Option<MouseContextMenu>,
 1093    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1094    inline_blame_popover: Option<InlineBlamePopover>,
 1095    inline_blame_popover_show_task: Option<Task<()>>,
 1096    signature_help_state: SignatureHelpState,
 1097    auto_signature_help: Option<bool>,
 1098    find_all_references_task_sources: Vec<Anchor>,
 1099    next_completion_id: CompletionId,
 1100    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1101    code_actions_task: Option<Task<Result<()>>>,
 1102    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1103    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1104    document_highlights_task: Option<Task<()>>,
 1105    linked_editing_range_task: Option<Task<Option<()>>>,
 1106    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1107    pending_rename: Option<RenameState>,
 1108    searchable: bool,
 1109    cursor_shape: CursorShape,
 1110    current_line_highlight: Option<CurrentLineHighlight>,
 1111    pub collapse_matches: bool,
 1112    autoindent_mode: Option<AutoindentMode>,
 1113    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1114    input_enabled: bool,
 1115    use_modal_editing: bool,
 1116    read_only: bool,
 1117    leader_id: Option<CollaboratorId>,
 1118    remote_id: Option<ViewId>,
 1119    pub hover_state: HoverState,
 1120    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1121    gutter_hovered: bool,
 1122    hovered_link_state: Option<HoveredLinkState>,
 1123    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1124    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1125    active_edit_prediction: Option<EditPredictionState>,
 1126    /// Used to prevent flickering as the user types while the menu is open
 1127    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1128    edit_prediction_settings: EditPredictionSettings,
 1129    edit_predictions_hidden_for_vim_mode: bool,
 1130    show_edit_predictions_override: Option<bool>,
 1131    show_completions_on_input_override: Option<bool>,
 1132    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1133    edit_prediction_preview: EditPredictionPreview,
 1134    edit_prediction_indent_conflict: bool,
 1135    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1136    next_inlay_id: usize,
 1137    next_color_inlay_id: usize,
 1138    _subscriptions: Vec<Subscription>,
 1139    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1140    gutter_dimensions: GutterDimensions,
 1141    style: Option<EditorStyle>,
 1142    text_style_refinement: Option<TextStyleRefinement>,
 1143    next_editor_action_id: EditorActionId,
 1144    editor_actions: Rc<
 1145        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1146    >,
 1147    use_autoclose: bool,
 1148    use_auto_surround: bool,
 1149    auto_replace_emoji_shortcode: bool,
 1150    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1151    show_git_blame_gutter: bool,
 1152    show_git_blame_inline: bool,
 1153    show_git_blame_inline_delay_task: Option<Task<()>>,
 1154    git_blame_inline_enabled: bool,
 1155    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1156    buffer_serialization: Option<BufferSerialization>,
 1157    show_selection_menu: Option<bool>,
 1158    blame: Option<Entity<GitBlame>>,
 1159    blame_subscription: Option<Subscription>,
 1160    custom_context_menu: Option<
 1161        Box<
 1162            dyn 'static
 1163                + Fn(
 1164                    &mut Self,
 1165                    DisplayPoint,
 1166                    &mut Window,
 1167                    &mut Context<Self>,
 1168                ) -> Option<Entity<ui::ContextMenu>>,
 1169        >,
 1170    >,
 1171    last_bounds: Option<Bounds<Pixels>>,
 1172    last_position_map: Option<Rc<PositionMap>>,
 1173    expect_bounds_change: Option<Bounds<Pixels>>,
 1174    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1175    tasks_update_task: Option<Task<()>>,
 1176    breakpoint_store: Option<Entity<BreakpointStore>>,
 1177    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1178    hovered_diff_hunk_row: Option<DisplayRow>,
 1179    pull_diagnostics_task: Task<()>,
 1180    pull_diagnostics_background_task: Task<()>,
 1181    in_project_search: bool,
 1182    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1183    breadcrumb_header: Option<String>,
 1184    focused_block: Option<FocusedBlock>,
 1185    next_scroll_position: NextScrollCursorCenterTopBottom,
 1186    addons: HashMap<TypeId, Box<dyn Addon>>,
 1187    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1188    load_diff_task: Option<Shared<Task<()>>>,
 1189    /// Whether we are temporarily displaying a diff other than git's
 1190    temporary_diff_override: bool,
 1191    selection_mark_mode: bool,
 1192    toggle_fold_multiple_buffers: Task<()>,
 1193    _scroll_cursor_center_top_bottom_task: Task<()>,
 1194    serialize_selections: Task<()>,
 1195    serialize_folds: Task<()>,
 1196    mouse_cursor_hidden: bool,
 1197    minimap: Option<Entity<Self>>,
 1198    hide_mouse_mode: HideMouseMode,
 1199    pub change_list: ChangeList,
 1200    inline_value_cache: InlineValueCache,
 1201
 1202    selection_drag_state: SelectionDragState,
 1203    colors: Option<LspColorData>,
 1204    post_scroll_update: Task<()>,
 1205    refresh_colors_task: Task<()>,
 1206    inlay_hints: Option<LspInlayHintData>,
 1207    folding_newlines: Task<()>,
 1208    select_next_is_case_sensitive: Option<bool>,
 1209    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1210    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1211    accent_data: Option<AccentData>,
 1212    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1213    use_base_text_line_numbers: bool,
 1214}
 1215
 1216#[derive(Debug, PartialEq)]
 1217struct AccentData {
 1218    colors: AccentColors,
 1219    overrides: Vec<SharedString>,
 1220}
 1221
 1222fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1223    if debounce_ms > 0 {
 1224        Some(Duration::from_millis(debounce_ms))
 1225    } else {
 1226        None
 1227    }
 1228}
 1229
 1230#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1231enum NextScrollCursorCenterTopBottom {
 1232    #[default]
 1233    Center,
 1234    Top,
 1235    Bottom,
 1236}
 1237
 1238impl NextScrollCursorCenterTopBottom {
 1239    fn next(&self) -> Self {
 1240        match self {
 1241            Self::Center => Self::Top,
 1242            Self::Top => Self::Bottom,
 1243            Self::Bottom => Self::Center,
 1244        }
 1245    }
 1246}
 1247
 1248#[derive(Clone)]
 1249pub struct EditorSnapshot {
 1250    pub mode: EditorMode,
 1251    show_gutter: bool,
 1252    show_line_numbers: Option<bool>,
 1253    show_git_diff_gutter: Option<bool>,
 1254    show_code_actions: Option<bool>,
 1255    show_runnables: Option<bool>,
 1256    show_breakpoints: Option<bool>,
 1257    git_blame_gutter_max_author_length: Option<usize>,
 1258    pub display_snapshot: DisplaySnapshot,
 1259    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1260    is_focused: bool,
 1261    scroll_anchor: ScrollAnchor,
 1262    ongoing_scroll: OngoingScroll,
 1263    current_line_highlight: CurrentLineHighlight,
 1264    gutter_hovered: bool,
 1265}
 1266
 1267#[derive(Default, Debug, Clone, Copy)]
 1268pub struct GutterDimensions {
 1269    pub left_padding: Pixels,
 1270    pub right_padding: Pixels,
 1271    pub width: Pixels,
 1272    pub margin: Pixels,
 1273    pub git_blame_entries_width: Option<Pixels>,
 1274}
 1275
 1276impl GutterDimensions {
 1277    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1278        Self {
 1279            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1280            ..Default::default()
 1281        }
 1282    }
 1283
 1284    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1285        -cx.text_system().descent(font_id, font_size)
 1286    }
 1287    /// The full width of the space taken up by the gutter.
 1288    pub fn full_width(&self) -> Pixels {
 1289        self.margin + self.width
 1290    }
 1291
 1292    /// The width of the space reserved for the fold indicators,
 1293    /// use alongside 'justify_end' and `gutter_width` to
 1294    /// right align content with the line numbers
 1295    pub fn fold_area_width(&self) -> Pixels {
 1296        self.margin + self.right_padding
 1297    }
 1298}
 1299
 1300struct CharacterDimensions {
 1301    em_width: Pixels,
 1302    em_advance: Pixels,
 1303    line_height: Pixels,
 1304}
 1305
 1306#[derive(Debug)]
 1307pub struct RemoteSelection {
 1308    pub replica_id: ReplicaId,
 1309    pub selection: Selection<Anchor>,
 1310    pub cursor_shape: CursorShape,
 1311    pub collaborator_id: CollaboratorId,
 1312    pub line_mode: bool,
 1313    pub user_name: Option<SharedString>,
 1314    pub color: PlayerColor,
 1315}
 1316
 1317#[derive(Clone, Debug)]
 1318struct SelectionHistoryEntry {
 1319    selections: Arc<[Selection<Anchor>]>,
 1320    select_next_state: Option<SelectNextState>,
 1321    select_prev_state: Option<SelectNextState>,
 1322    add_selections_state: Option<AddSelectionsState>,
 1323}
 1324
 1325#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1326enum SelectionHistoryMode {
 1327    #[default]
 1328    Normal,
 1329    Undoing,
 1330    Redoing,
 1331    Skipping,
 1332}
 1333
 1334#[derive(Clone, PartialEq, Eq, Hash)]
 1335struct HoveredCursor {
 1336    replica_id: ReplicaId,
 1337    selection_id: usize,
 1338}
 1339
 1340#[derive(Debug)]
 1341/// SelectionEffects controls the side-effects of updating the selection.
 1342///
 1343/// The default behaviour does "what you mostly want":
 1344/// - it pushes to the nav history if the cursor moved by >10 lines
 1345/// - it re-triggers completion requests
 1346/// - it scrolls to fit
 1347///
 1348/// You might want to modify these behaviours. For example when doing a "jump"
 1349/// like go to definition, we always want to add to nav history; but when scrolling
 1350/// in vim mode we never do.
 1351///
 1352/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1353/// move.
 1354#[derive(Clone)]
 1355pub struct SelectionEffects {
 1356    nav_history: Option<bool>,
 1357    completions: bool,
 1358    scroll: Option<Autoscroll>,
 1359}
 1360
 1361impl Default for SelectionEffects {
 1362    fn default() -> Self {
 1363        Self {
 1364            nav_history: None,
 1365            completions: true,
 1366            scroll: Some(Autoscroll::fit()),
 1367        }
 1368    }
 1369}
 1370impl SelectionEffects {
 1371    pub fn scroll(scroll: Autoscroll) -> Self {
 1372        Self {
 1373            scroll: Some(scroll),
 1374            ..Default::default()
 1375        }
 1376    }
 1377
 1378    pub fn no_scroll() -> Self {
 1379        Self {
 1380            scroll: None,
 1381            ..Default::default()
 1382        }
 1383    }
 1384
 1385    pub fn completions(self, completions: bool) -> Self {
 1386        Self {
 1387            completions,
 1388            ..self
 1389        }
 1390    }
 1391
 1392    pub fn nav_history(self, nav_history: bool) -> Self {
 1393        Self {
 1394            nav_history: Some(nav_history),
 1395            ..self
 1396        }
 1397    }
 1398}
 1399
 1400struct DeferredSelectionEffectsState {
 1401    changed: bool,
 1402    effects: SelectionEffects,
 1403    old_cursor_position: Anchor,
 1404    history_entry: SelectionHistoryEntry,
 1405}
 1406
 1407#[derive(Default)]
 1408struct SelectionHistory {
 1409    #[allow(clippy::type_complexity)]
 1410    selections_by_transaction:
 1411        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1412    mode: SelectionHistoryMode,
 1413    undo_stack: VecDeque<SelectionHistoryEntry>,
 1414    redo_stack: VecDeque<SelectionHistoryEntry>,
 1415}
 1416
 1417impl SelectionHistory {
 1418    #[track_caller]
 1419    fn insert_transaction(
 1420        &mut self,
 1421        transaction_id: TransactionId,
 1422        selections: Arc<[Selection<Anchor>]>,
 1423    ) {
 1424        if selections.is_empty() {
 1425            log::error!(
 1426                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1427                std::panic::Location::caller()
 1428            );
 1429            return;
 1430        }
 1431        self.selections_by_transaction
 1432            .insert(transaction_id, (selections, None));
 1433    }
 1434
 1435    #[allow(clippy::type_complexity)]
 1436    fn transaction(
 1437        &self,
 1438        transaction_id: TransactionId,
 1439    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1440        self.selections_by_transaction.get(&transaction_id)
 1441    }
 1442
 1443    #[allow(clippy::type_complexity)]
 1444    fn transaction_mut(
 1445        &mut self,
 1446        transaction_id: TransactionId,
 1447    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1448        self.selections_by_transaction.get_mut(&transaction_id)
 1449    }
 1450
 1451    fn push(&mut self, entry: SelectionHistoryEntry) {
 1452        if !entry.selections.is_empty() {
 1453            match self.mode {
 1454                SelectionHistoryMode::Normal => {
 1455                    self.push_undo(entry);
 1456                    self.redo_stack.clear();
 1457                }
 1458                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1459                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1460                SelectionHistoryMode::Skipping => {}
 1461            }
 1462        }
 1463    }
 1464
 1465    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1466        if self
 1467            .undo_stack
 1468            .back()
 1469            .is_none_or(|e| e.selections != entry.selections)
 1470        {
 1471            self.undo_stack.push_back(entry);
 1472            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1473                self.undo_stack.pop_front();
 1474            }
 1475        }
 1476    }
 1477
 1478    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1479        if self
 1480            .redo_stack
 1481            .back()
 1482            .is_none_or(|e| e.selections != entry.selections)
 1483        {
 1484            self.redo_stack.push_back(entry);
 1485            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1486                self.redo_stack.pop_front();
 1487            }
 1488        }
 1489    }
 1490}
 1491
 1492#[derive(Clone, Copy)]
 1493pub struct RowHighlightOptions {
 1494    pub autoscroll: bool,
 1495    pub include_gutter: bool,
 1496}
 1497
 1498impl Default for RowHighlightOptions {
 1499    fn default() -> Self {
 1500        Self {
 1501            autoscroll: Default::default(),
 1502            include_gutter: true,
 1503        }
 1504    }
 1505}
 1506
 1507struct RowHighlight {
 1508    index: usize,
 1509    range: Range<Anchor>,
 1510    color: Hsla,
 1511    options: RowHighlightOptions,
 1512    type_id: TypeId,
 1513}
 1514
 1515#[derive(Clone, Debug)]
 1516struct AddSelectionsState {
 1517    groups: Vec<AddSelectionsGroup>,
 1518}
 1519
 1520#[derive(Clone, Debug)]
 1521struct AddSelectionsGroup {
 1522    above: bool,
 1523    stack: Vec<usize>,
 1524}
 1525
 1526#[derive(Clone)]
 1527struct SelectNextState {
 1528    query: AhoCorasick,
 1529    wordwise: bool,
 1530    done: bool,
 1531}
 1532
 1533impl std::fmt::Debug for SelectNextState {
 1534    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1535        f.debug_struct(std::any::type_name::<Self>())
 1536            .field("wordwise", &self.wordwise)
 1537            .field("done", &self.done)
 1538            .finish()
 1539    }
 1540}
 1541
 1542#[derive(Debug)]
 1543struct AutocloseRegion {
 1544    selection_id: usize,
 1545    range: Range<Anchor>,
 1546    pair: BracketPair,
 1547}
 1548
 1549#[derive(Debug)]
 1550struct SnippetState {
 1551    ranges: Vec<Vec<Range<Anchor>>>,
 1552    active_index: usize,
 1553    choices: Vec<Option<Vec<String>>>,
 1554}
 1555
 1556#[doc(hidden)]
 1557pub struct RenameState {
 1558    pub range: Range<Anchor>,
 1559    pub old_name: Arc<str>,
 1560    pub editor: Entity<Editor>,
 1561    block_id: CustomBlockId,
 1562}
 1563
 1564struct InvalidationStack<T>(Vec<T>);
 1565
 1566struct RegisteredEditPredictionDelegate {
 1567    provider: Arc<dyn EditPredictionDelegateHandle>,
 1568    _subscription: Subscription,
 1569}
 1570
 1571#[derive(Debug, PartialEq, Eq)]
 1572pub struct ActiveDiagnosticGroup {
 1573    pub active_range: Range<Anchor>,
 1574    pub active_message: String,
 1575    pub group_id: usize,
 1576    pub blocks: HashSet<CustomBlockId>,
 1577}
 1578
 1579#[derive(Debug, PartialEq, Eq)]
 1580
 1581pub(crate) enum ActiveDiagnostic {
 1582    None,
 1583    All,
 1584    Group(ActiveDiagnosticGroup),
 1585}
 1586
 1587#[derive(Serialize, Deserialize, Clone, Debug)]
 1588pub struct ClipboardSelection {
 1589    /// The number of bytes in this selection.
 1590    pub len: usize,
 1591    /// Whether this was a full-line selection.
 1592    pub is_entire_line: bool,
 1593    /// The indentation of the first line when this content was originally copied.
 1594    pub first_line_indent: u32,
 1595}
 1596
 1597// selections, scroll behavior, was newest selection reversed
 1598type SelectSyntaxNodeHistoryState = (
 1599    Box<[Selection<MultiBufferOffset>]>,
 1600    SelectSyntaxNodeScrollBehavior,
 1601    bool,
 1602);
 1603
 1604#[derive(Default)]
 1605struct SelectSyntaxNodeHistory {
 1606    stack: Vec<SelectSyntaxNodeHistoryState>,
 1607    // disable temporarily to allow changing selections without losing the stack
 1608    pub disable_clearing: bool,
 1609}
 1610
 1611impl SelectSyntaxNodeHistory {
 1612    pub fn try_clear(&mut self) {
 1613        if !self.disable_clearing {
 1614            self.stack.clear();
 1615        }
 1616    }
 1617
 1618    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1619        self.stack.push(selection);
 1620    }
 1621
 1622    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1623        self.stack.pop()
 1624    }
 1625}
 1626
 1627enum SelectSyntaxNodeScrollBehavior {
 1628    CursorTop,
 1629    FitSelection,
 1630    CursorBottom,
 1631}
 1632
 1633#[derive(Debug)]
 1634pub(crate) struct NavigationData {
 1635    cursor_anchor: Anchor,
 1636    cursor_position: Point,
 1637    scroll_anchor: ScrollAnchor,
 1638    scroll_top_row: u32,
 1639}
 1640
 1641#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1642pub enum GotoDefinitionKind {
 1643    Symbol,
 1644    Declaration,
 1645    Type,
 1646    Implementation,
 1647}
 1648
 1649pub enum FormatTarget {
 1650    Buffers(HashSet<Entity<Buffer>>),
 1651    Ranges(Vec<Range<MultiBufferPoint>>),
 1652}
 1653
 1654pub(crate) struct FocusedBlock {
 1655    id: BlockId,
 1656    focus_handle: WeakFocusHandle,
 1657}
 1658
 1659#[derive(Clone, Debug)]
 1660enum JumpData {
 1661    MultiBufferRow {
 1662        row: MultiBufferRow,
 1663        line_offset_from_top: u32,
 1664    },
 1665    MultiBufferPoint {
 1666        excerpt_id: ExcerptId,
 1667        position: Point,
 1668        anchor: text::Anchor,
 1669        line_offset_from_top: u32,
 1670    },
 1671}
 1672
 1673pub enum MultibufferSelectionMode {
 1674    First,
 1675    All,
 1676}
 1677
 1678#[derive(Clone, Copy, Debug, Default)]
 1679pub struct RewrapOptions {
 1680    pub override_language_settings: bool,
 1681    pub preserve_existing_whitespace: bool,
 1682}
 1683
 1684impl Editor {
 1685    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1689    }
 1690
 1691    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(EditorMode::full(), buffer, None, window, cx)
 1695    }
 1696
 1697    pub fn auto_height(
 1698        min_lines: usize,
 1699        max_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: Some(max_lines),
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1718    /// The editor grows as tall as needed to fit its content.
 1719    pub fn auto_height_unbounded(
 1720        min_lines: usize,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| Buffer::local("", cx));
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(
 1727            EditorMode::AutoHeight {
 1728                min_lines,
 1729                max_lines: None,
 1730            },
 1731            buffer,
 1732            None,
 1733            window,
 1734            cx,
 1735        )
 1736    }
 1737
 1738    pub fn for_buffer(
 1739        buffer: Entity<Buffer>,
 1740        project: Option<Entity<Project>>,
 1741        window: &mut Window,
 1742        cx: &mut Context<Self>,
 1743    ) -> Self {
 1744        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1745        Self::new(EditorMode::full(), buffer, project, window, cx)
 1746    }
 1747
 1748    pub fn for_multibuffer(
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Self::new(EditorMode::full(), buffer, project, window, cx)
 1755    }
 1756
 1757    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1758        let mut clone = Self::new(
 1759            self.mode.clone(),
 1760            self.buffer.clone(),
 1761            self.project.clone(),
 1762            window,
 1763            cx,
 1764        );
 1765        self.display_map.update(cx, |display_map, cx| {
 1766            let snapshot = display_map.snapshot(cx);
 1767            clone.display_map.update(cx, |display_map, cx| {
 1768                display_map.set_state(&snapshot, cx);
 1769            });
 1770        });
 1771        clone.folds_did_change(cx);
 1772        clone.selections.clone_state(&self.selections);
 1773        clone.scroll_manager.clone_state(&self.scroll_manager);
 1774        clone.searchable = self.searchable;
 1775        clone.read_only = self.read_only;
 1776        clone
 1777    }
 1778
 1779    pub fn new(
 1780        mode: EditorMode,
 1781        buffer: Entity<MultiBuffer>,
 1782        project: Option<Entity<Project>>,
 1783        window: &mut Window,
 1784        cx: &mut Context<Self>,
 1785    ) -> Self {
 1786        Editor::new_internal(mode, buffer, project, None, window, cx)
 1787    }
 1788
 1789    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1790        let multi_buffer = self.buffer().read(cx);
 1791        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1792        let multi_buffer_visible_start = self
 1793            .scroll_manager
 1794            .anchor()
 1795            .anchor
 1796            .to_point(&multi_buffer_snapshot);
 1797        let max_row = multi_buffer_snapshot.max_point().row;
 1798
 1799        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1800        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1801
 1802        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1803            let outline_items = buffer
 1804                .outline_items_containing(
 1805                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1806                    true,
 1807                    self.style().map(|style| style.syntax.as_ref()),
 1808                )
 1809                .into_iter()
 1810                .map(|outline_item| OutlineItem {
 1811                    depth: outline_item.depth,
 1812                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1813                    source_range_for_text: Anchor::range_in_buffer(
 1814                        *excerpt_id,
 1815                        outline_item.source_range_for_text,
 1816                    ),
 1817                    text: outline_item.text,
 1818                    highlight_ranges: outline_item.highlight_ranges,
 1819                    name_ranges: outline_item.name_ranges,
 1820                    body_range: outline_item
 1821                        .body_range
 1822                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1823                    annotation_range: outline_item
 1824                        .annotation_range
 1825                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1826                });
 1827            return Some(outline_items.collect());
 1828        }
 1829
 1830        None
 1831    }
 1832
 1833    fn new_internal(
 1834        mode: EditorMode,
 1835        multi_buffer: Entity<MultiBuffer>,
 1836        project: Option<Entity<Project>>,
 1837        display_map: Option<Entity<DisplayMap>>,
 1838        window: &mut Window,
 1839        cx: &mut Context<Self>,
 1840    ) -> Self {
 1841        debug_assert!(
 1842            display_map.is_none() || mode.is_minimap(),
 1843            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1844        );
 1845
 1846        let full_mode = mode.is_full();
 1847        let is_minimap = mode.is_minimap();
 1848        let diagnostics_max_severity = if full_mode {
 1849            EditorSettings::get_global(cx)
 1850                .diagnostics_max_severity
 1851                .unwrap_or(DiagnosticSeverity::Hint)
 1852        } else {
 1853            DiagnosticSeverity::Off
 1854        };
 1855        let style = window.text_style();
 1856        let font_size = style.font_size.to_pixels(window.rem_size());
 1857        let editor = cx.entity().downgrade();
 1858        let fold_placeholder = FoldPlaceholder {
 1859            constrain_width: false,
 1860            render: Arc::new(move |fold_id, fold_range, cx| {
 1861                let editor = editor.clone();
 1862                div()
 1863                    .id(fold_id)
 1864                    .bg(cx.theme().colors().ghost_element_background)
 1865                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1866                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1867                    .rounded_xs()
 1868                    .size_full()
 1869                    .cursor_pointer()
 1870                    .child("")
 1871                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1872                    .on_click(move |_, _window, cx| {
 1873                        editor
 1874                            .update(cx, |editor, cx| {
 1875                                editor.unfold_ranges(
 1876                                    &[fold_range.start..fold_range.end],
 1877                                    true,
 1878                                    false,
 1879                                    cx,
 1880                                );
 1881                                cx.stop_propagation();
 1882                            })
 1883                            .ok();
 1884                    })
 1885                    .into_any()
 1886            }),
 1887            merge_adjacent: true,
 1888            ..FoldPlaceholder::default()
 1889        };
 1890        let display_map = display_map.unwrap_or_else(|| {
 1891            cx.new(|cx| {
 1892                DisplayMap::new(
 1893                    multi_buffer.clone(),
 1894                    style.font(),
 1895                    font_size,
 1896                    None,
 1897                    FILE_HEADER_HEIGHT,
 1898                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1899                    fold_placeholder,
 1900                    diagnostics_max_severity,
 1901                    cx,
 1902                )
 1903            })
 1904        });
 1905
 1906        let selections = SelectionsCollection::new();
 1907
 1908        let blink_manager = cx.new(|cx| {
 1909            let mut blink_manager = BlinkManager::new(
 1910                CURSOR_BLINK_INTERVAL,
 1911                |cx| EditorSettings::get_global(cx).cursor_blink,
 1912                cx,
 1913            );
 1914            if is_minimap {
 1915                blink_manager.disable(cx);
 1916            }
 1917            blink_manager
 1918        });
 1919
 1920        let soft_wrap_mode_override =
 1921            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1922
 1923        let mut project_subscriptions = Vec::new();
 1924        if full_mode && let Some(project) = project.as_ref() {
 1925            project_subscriptions.push(cx.subscribe_in(
 1926                project,
 1927                window,
 1928                |editor, _, event, window, cx| match event {
 1929                    project::Event::RefreshCodeLens => {
 1930                        // we always query lens with actions, without storing them, always refreshing them
 1931                    }
 1932                    project::Event::RefreshInlayHints {
 1933                        server_id,
 1934                        request_id,
 1935                    } => {
 1936                        editor.refresh_inlay_hints(
 1937                            InlayHintRefreshReason::RefreshRequested {
 1938                                server_id: *server_id,
 1939                                request_id: *request_id,
 1940                            },
 1941                            cx,
 1942                        );
 1943                    }
 1944                    project::Event::LanguageServerRemoved(..) => {
 1945                        if editor.tasks_update_task.is_none() {
 1946                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1947                        }
 1948                        editor.registered_buffers.clear();
 1949                        editor.register_visible_buffers(cx);
 1950                    }
 1951                    project::Event::LanguageServerAdded(..) => {
 1952                        if editor.tasks_update_task.is_none() {
 1953                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1954                        }
 1955                    }
 1956                    project::Event::SnippetEdit(id, snippet_edits) => {
 1957                        // todo(lw): Non singletons
 1958                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1959                            let snapshot = buffer.read(cx).snapshot();
 1960                            let focus_handle = editor.focus_handle(cx);
 1961                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1962                                for (range, snippet) in snippet_edits {
 1963                                    let buffer_range =
 1964                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1965                                    editor
 1966                                        .insert_snippet(
 1967                                            &[MultiBufferOffset(buffer_range.start)
 1968                                                ..MultiBufferOffset(buffer_range.end)],
 1969                                            snippet.clone(),
 1970                                            window,
 1971                                            cx,
 1972                                        )
 1973                                        .ok();
 1974                                }
 1975                            }
 1976                        }
 1977                    }
 1978                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1979                        let buffer_id = *buffer_id;
 1980                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1981                            editor.register_buffer(buffer_id, cx);
 1982                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1983                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1984                            refresh_linked_ranges(editor, window, cx);
 1985                            editor.refresh_code_actions(window, cx);
 1986                            editor.refresh_document_highlights(cx);
 1987                        }
 1988                    }
 1989
 1990                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1991                        let Some(workspace) = editor.workspace() else {
 1992                            return;
 1993                        };
 1994                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1995                        else {
 1996                            return;
 1997                        };
 1998
 1999                        if active_editor.entity_id() == cx.entity_id() {
 2000                            let entity_id = cx.entity_id();
 2001                            workspace.update(cx, |this, cx| {
 2002                                this.panes_mut()
 2003                                    .iter_mut()
 2004                                    .filter(|pane| pane.entity_id() != entity_id)
 2005                                    .for_each(|p| {
 2006                                        p.update(cx, |pane, _| {
 2007                                            pane.nav_history_mut().rename_item(
 2008                                                entity_id,
 2009                                                project_path.clone(),
 2010                                                abs_path.clone().into(),
 2011                                            );
 2012                                        })
 2013                                    });
 2014                            });
 2015                            let edited_buffers_already_open = {
 2016                                let other_editors: Vec<Entity<Editor>> = workspace
 2017                                    .read(cx)
 2018                                    .panes()
 2019                                    .iter()
 2020                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2021                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2022                                    .collect();
 2023
 2024                                transaction.0.keys().all(|buffer| {
 2025                                    other_editors.iter().any(|editor| {
 2026                                        let multi_buffer = editor.read(cx).buffer();
 2027                                        multi_buffer.read(cx).is_singleton()
 2028                                            && multi_buffer.read(cx).as_singleton().map_or(
 2029                                                false,
 2030                                                |singleton| {
 2031                                                    singleton.entity_id() == buffer.entity_id()
 2032                                                },
 2033                                            )
 2034                                    })
 2035                                })
 2036                            };
 2037                            if !edited_buffers_already_open {
 2038                                let workspace = workspace.downgrade();
 2039                                let transaction = transaction.clone();
 2040                                cx.defer_in(window, move |_, window, cx| {
 2041                                    cx.spawn_in(window, async move |editor, cx| {
 2042                                        Self::open_project_transaction(
 2043                                            &editor,
 2044                                            workspace,
 2045                                            transaction,
 2046                                            "Rename".to_string(),
 2047                                            cx,
 2048                                        )
 2049                                        .await
 2050                                        .ok()
 2051                                    })
 2052                                    .detach();
 2053                                });
 2054                            }
 2055                        }
 2056                    }
 2057
 2058                    _ => {}
 2059                },
 2060            ));
 2061            if let Some(task_inventory) = project
 2062                .read(cx)
 2063                .task_store()
 2064                .read(cx)
 2065                .task_inventory()
 2066                .cloned()
 2067            {
 2068                project_subscriptions.push(cx.observe_in(
 2069                    &task_inventory,
 2070                    window,
 2071                    |editor, _, window, cx| {
 2072                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2073                    },
 2074                ));
 2075            };
 2076
 2077            project_subscriptions.push(cx.subscribe_in(
 2078                &project.read(cx).breakpoint_store(),
 2079                window,
 2080                |editor, _, event, window, cx| match event {
 2081                    BreakpointStoreEvent::ClearDebugLines => {
 2082                        editor.clear_row_highlights::<ActiveDebugLine>();
 2083                        editor.refresh_inline_values(cx);
 2084                    }
 2085                    BreakpointStoreEvent::SetDebugLine => {
 2086                        if editor.go_to_active_debug_line(window, cx) {
 2087                            cx.stop_propagation();
 2088                        }
 2089
 2090                        editor.refresh_inline_values(cx);
 2091                    }
 2092                    _ => {}
 2093                },
 2094            ));
 2095            let git_store = project.read(cx).git_store().clone();
 2096            let project = project.clone();
 2097            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2098                if let GitStoreEvent::RepositoryAdded = event {
 2099                    this.load_diff_task = Some(
 2100                        update_uncommitted_diff_for_buffer(
 2101                            cx.entity(),
 2102                            &project,
 2103                            this.buffer.read(cx).all_buffers(),
 2104                            this.buffer.clone(),
 2105                            cx,
 2106                        )
 2107                        .shared(),
 2108                    );
 2109                }
 2110            }));
 2111        }
 2112
 2113        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2114
 2115        let inlay_hint_settings =
 2116            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2117        let focus_handle = cx.focus_handle();
 2118        if !is_minimap {
 2119            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2120                .detach();
 2121            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2122                .detach();
 2123            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2124                .detach();
 2125            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2126                .detach();
 2127            cx.observe_pending_input(window, Self::observe_pending_input)
 2128                .detach();
 2129        }
 2130
 2131        let show_indent_guides =
 2132            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2133                Some(false)
 2134            } else {
 2135                None
 2136            };
 2137
 2138        let breakpoint_store = match (&mode, project.as_ref()) {
 2139            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2140            _ => None,
 2141        };
 2142
 2143        let mut code_action_providers = Vec::new();
 2144        let mut load_uncommitted_diff = None;
 2145        if let Some(project) = project.clone() {
 2146            load_uncommitted_diff = Some(
 2147                update_uncommitted_diff_for_buffer(
 2148                    cx.entity(),
 2149                    &project,
 2150                    multi_buffer.read(cx).all_buffers(),
 2151                    multi_buffer.clone(),
 2152                    cx,
 2153                )
 2154                .shared(),
 2155            );
 2156            code_action_providers.push(Rc::new(project) as Rc<_>);
 2157        }
 2158
 2159        let mut editor = Self {
 2160            focus_handle,
 2161            show_cursor_when_unfocused: false,
 2162            last_focused_descendant: None,
 2163            buffer: multi_buffer.clone(),
 2164            display_map: display_map.clone(),
 2165            placeholder_display_map: None,
 2166            selections,
 2167            scroll_manager: ScrollManager::new(cx),
 2168            columnar_selection_state: None,
 2169            add_selections_state: None,
 2170            select_next_state: None,
 2171            select_prev_state: None,
 2172            selection_history: SelectionHistory::default(),
 2173            defer_selection_effects: false,
 2174            deferred_selection_effects_state: None,
 2175            autoclose_regions: Vec::new(),
 2176            snippet_stack: InvalidationStack::default(),
 2177            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2178            ime_transaction: None,
 2179            active_diagnostics: ActiveDiagnostic::None,
 2180            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2181            inline_diagnostics_update: Task::ready(()),
 2182            inline_diagnostics: Vec::new(),
 2183            soft_wrap_mode_override,
 2184            diagnostics_max_severity,
 2185            hard_wrap: None,
 2186            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2187            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2188            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2189            project,
 2190            blink_manager: blink_manager.clone(),
 2191            show_local_selections: true,
 2192            show_scrollbars: ScrollbarAxes {
 2193                horizontal: full_mode,
 2194                vertical: full_mode,
 2195            },
 2196            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2197            offset_content: !matches!(mode, EditorMode::SingleLine),
 2198            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2199            show_gutter: full_mode,
 2200            show_line_numbers: (!full_mode).then_some(false),
 2201            use_relative_line_numbers: None,
 2202            disable_expand_excerpt_buttons: !full_mode,
 2203            show_git_diff_gutter: None,
 2204            show_code_actions: None,
 2205            show_runnables: None,
 2206            show_breakpoints: None,
 2207            show_wrap_guides: None,
 2208            show_indent_guides,
 2209            buffers_with_disabled_indent_guides: HashSet::default(),
 2210            highlight_order: 0,
 2211            highlighted_rows: HashMap::default(),
 2212            background_highlights: HashMap::default(),
 2213            gutter_highlights: HashMap::default(),
 2214            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2215            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2216            nav_history: None,
 2217            context_menu: RefCell::new(None),
 2218            context_menu_options: None,
 2219            mouse_context_menu: None,
 2220            completion_tasks: Vec::new(),
 2221            inline_blame_popover: None,
 2222            inline_blame_popover_show_task: None,
 2223            signature_help_state: SignatureHelpState::default(),
 2224            auto_signature_help: None,
 2225            find_all_references_task_sources: Vec::new(),
 2226            next_completion_id: 0,
 2227            next_inlay_id: 0,
 2228            code_action_providers,
 2229            available_code_actions: None,
 2230            code_actions_task: None,
 2231            quick_selection_highlight_task: None,
 2232            debounced_selection_highlight_task: None,
 2233            document_highlights_task: None,
 2234            linked_editing_range_task: None,
 2235            pending_rename: None,
 2236            searchable: !is_minimap,
 2237            cursor_shape: EditorSettings::get_global(cx)
 2238                .cursor_shape
 2239                .unwrap_or_default(),
 2240            current_line_highlight: None,
 2241            autoindent_mode: Some(AutoindentMode::EachLine),
 2242            collapse_matches: false,
 2243            workspace: None,
 2244            input_enabled: !is_minimap,
 2245            use_modal_editing: full_mode,
 2246            read_only: is_minimap,
 2247            use_autoclose: true,
 2248            use_auto_surround: true,
 2249            auto_replace_emoji_shortcode: false,
 2250            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2251            leader_id: None,
 2252            remote_id: None,
 2253            hover_state: HoverState::default(),
 2254            pending_mouse_down: None,
 2255            hovered_link_state: None,
 2256            edit_prediction_provider: None,
 2257            active_edit_prediction: None,
 2258            stale_edit_prediction_in_menu: None,
 2259            edit_prediction_preview: EditPredictionPreview::Inactive {
 2260                released_too_fast: false,
 2261            },
 2262            inline_diagnostics_enabled: full_mode,
 2263            diagnostics_enabled: full_mode,
 2264            word_completions_enabled: full_mode,
 2265            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2266            gutter_hovered: false,
 2267            pixel_position_of_newest_cursor: None,
 2268            last_bounds: None,
 2269            last_position_map: None,
 2270            expect_bounds_change: None,
 2271            gutter_dimensions: GutterDimensions::default(),
 2272            style: None,
 2273            show_cursor_names: false,
 2274            hovered_cursors: HashMap::default(),
 2275            next_editor_action_id: EditorActionId::default(),
 2276            editor_actions: Rc::default(),
 2277            edit_predictions_hidden_for_vim_mode: false,
 2278            show_edit_predictions_override: None,
 2279            show_completions_on_input_override: None,
 2280            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2281            edit_prediction_settings: EditPredictionSettings::Disabled,
 2282            edit_prediction_indent_conflict: false,
 2283            edit_prediction_requires_modifier_in_indent_conflict: true,
 2284            custom_context_menu: None,
 2285            show_git_blame_gutter: false,
 2286            show_git_blame_inline: false,
 2287            show_selection_menu: None,
 2288            show_git_blame_inline_delay_task: None,
 2289            git_blame_inline_enabled: full_mode
 2290                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2291            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2292            buffer_serialization: is_minimap.not().then(|| {
 2293                BufferSerialization::new(
 2294                    ProjectSettings::get_global(cx)
 2295                        .session
 2296                        .restore_unsaved_buffers,
 2297                )
 2298            }),
 2299            blame: None,
 2300            blame_subscription: None,
 2301            tasks: BTreeMap::default(),
 2302
 2303            breakpoint_store,
 2304            gutter_breakpoint_indicator: (None, None),
 2305            hovered_diff_hunk_row: None,
 2306            _subscriptions: (!is_minimap)
 2307                .then(|| {
 2308                    vec![
 2309                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2310                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2311                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2312                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2313                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2314                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2315                        cx.observe_window_activation(window, |editor, window, cx| {
 2316                            let active = window.is_window_active();
 2317                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2318                                if active {
 2319                                    blink_manager.enable(cx);
 2320                                } else {
 2321                                    blink_manager.disable(cx);
 2322                                }
 2323                            });
 2324                            if active {
 2325                                editor.show_mouse_cursor(cx);
 2326                            }
 2327                        }),
 2328                    ]
 2329                })
 2330                .unwrap_or_default(),
 2331            tasks_update_task: None,
 2332            pull_diagnostics_task: Task::ready(()),
 2333            pull_diagnostics_background_task: Task::ready(()),
 2334            colors: None,
 2335            refresh_colors_task: Task::ready(()),
 2336            inlay_hints: None,
 2337            next_color_inlay_id: 0,
 2338            post_scroll_update: Task::ready(()),
 2339            linked_edit_ranges: Default::default(),
 2340            in_project_search: false,
 2341            previous_search_ranges: None,
 2342            breadcrumb_header: None,
 2343            focused_block: None,
 2344            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2345            addons: HashMap::default(),
 2346            registered_buffers: HashMap::default(),
 2347            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2348            selection_mark_mode: false,
 2349            toggle_fold_multiple_buffers: Task::ready(()),
 2350            serialize_selections: Task::ready(()),
 2351            serialize_folds: Task::ready(()),
 2352            text_style_refinement: None,
 2353            load_diff_task: load_uncommitted_diff,
 2354            temporary_diff_override: false,
 2355            mouse_cursor_hidden: false,
 2356            minimap: None,
 2357            hide_mouse_mode: EditorSettings::get_global(cx)
 2358                .hide_mouse
 2359                .unwrap_or_default(),
 2360            change_list: ChangeList::new(),
 2361            mode,
 2362            selection_drag_state: SelectionDragState::None,
 2363            folding_newlines: Task::ready(()),
 2364            lookup_key: None,
 2365            select_next_is_case_sensitive: None,
 2366            applicable_language_settings: HashMap::default(),
 2367            accent_data: None,
 2368            fetched_tree_sitter_chunks: HashMap::default(),
 2369            use_base_text_line_numbers: false,
 2370        };
 2371
 2372        if is_minimap {
 2373            return editor;
 2374        }
 2375
 2376        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2377        editor.accent_data = editor.fetch_accent_data(cx);
 2378
 2379        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2380            editor
 2381                ._subscriptions
 2382                .push(cx.observe(breakpoints, |_, _, cx| {
 2383                    cx.notify();
 2384                }));
 2385        }
 2386        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2387        editor._subscriptions.extend(project_subscriptions);
 2388
 2389        editor._subscriptions.push(cx.subscribe_in(
 2390            &cx.entity(),
 2391            window,
 2392            |editor, _, e: &EditorEvent, window, cx| match e {
 2393                EditorEvent::ScrollPositionChanged { local, .. } => {
 2394                    if *local {
 2395                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2396                        editor.inline_blame_popover.take();
 2397                        let new_anchor = editor.scroll_manager.anchor();
 2398                        let snapshot = editor.snapshot(window, cx);
 2399                        editor.update_restoration_data(cx, move |data| {
 2400                            data.scroll_position = (
 2401                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2402                                new_anchor.offset,
 2403                            );
 2404                        });
 2405
 2406                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2407                            cx.background_executor()
 2408                                .timer(Duration::from_millis(50))
 2409                                .await;
 2410                            editor
 2411                                .update_in(cx, |editor, window, cx| {
 2412                                    editor.register_visible_buffers(cx);
 2413                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2414                                    editor.refresh_inlay_hints(
 2415                                        InlayHintRefreshReason::NewLinesShown,
 2416                                        cx,
 2417                                    );
 2418                                    editor.colorize_brackets(false, cx);
 2419                                })
 2420                                .ok();
 2421                        });
 2422                    }
 2423                }
 2424                EditorEvent::Edited { .. } => {
 2425                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2426                        .map(|vim_mode| vim_mode.0)
 2427                        .unwrap_or(false);
 2428                    if !vim_mode {
 2429                        let display_map = editor.display_snapshot(cx);
 2430                        let selections = editor.selections.all_adjusted_display(&display_map);
 2431                        let pop_state = editor
 2432                            .change_list
 2433                            .last()
 2434                            .map(|previous| {
 2435                                previous.len() == selections.len()
 2436                                    && previous.iter().enumerate().all(|(ix, p)| {
 2437                                        p.to_display_point(&display_map).row()
 2438                                            == selections[ix].head().row()
 2439                                    })
 2440                            })
 2441                            .unwrap_or(false);
 2442                        let new_positions = selections
 2443                            .into_iter()
 2444                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2445                            .collect();
 2446                        editor
 2447                            .change_list
 2448                            .push_to_change_list(pop_state, new_positions);
 2449                    }
 2450                }
 2451                _ => (),
 2452            },
 2453        ));
 2454
 2455        if let Some(dap_store) = editor
 2456            .project
 2457            .as_ref()
 2458            .map(|project| project.read(cx).dap_store())
 2459        {
 2460            let weak_editor = cx.weak_entity();
 2461
 2462            editor
 2463                ._subscriptions
 2464                .push(
 2465                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2466                        let session_entity = cx.entity();
 2467                        weak_editor
 2468                            .update(cx, |editor, cx| {
 2469                                editor._subscriptions.push(
 2470                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2471                                );
 2472                            })
 2473                            .ok();
 2474                    }),
 2475                );
 2476
 2477            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2478                editor
 2479                    ._subscriptions
 2480                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2481            }
 2482        }
 2483
 2484        // skip adding the initial selection to selection history
 2485        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2486        editor.end_selection(window, cx);
 2487        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2488
 2489        editor.scroll_manager.show_scrollbars(window, cx);
 2490        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2491
 2492        if full_mode {
 2493            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2494            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2495
 2496            if editor.git_blame_inline_enabled {
 2497                editor.start_git_blame_inline(false, window, cx);
 2498            }
 2499
 2500            editor.go_to_active_debug_line(window, cx);
 2501
 2502            editor.minimap =
 2503                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2504            editor.colors = Some(LspColorData::new(cx));
 2505            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2506
 2507            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2508                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2509            }
 2510            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2511        }
 2512
 2513        editor
 2514    }
 2515
 2516    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2517        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2518    }
 2519
 2520    pub fn deploy_mouse_context_menu(
 2521        &mut self,
 2522        position: gpui::Point<Pixels>,
 2523        context_menu: Entity<ContextMenu>,
 2524        window: &mut Window,
 2525        cx: &mut Context<Self>,
 2526    ) {
 2527        self.mouse_context_menu = Some(MouseContextMenu::new(
 2528            self,
 2529            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2530            context_menu,
 2531            window,
 2532            cx,
 2533        ));
 2534    }
 2535
 2536    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2537        self.mouse_context_menu
 2538            .as_ref()
 2539            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2540    }
 2541
 2542    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2543        if self
 2544            .selections
 2545            .pending_anchor()
 2546            .is_some_and(|pending_selection| {
 2547                let snapshot = self.buffer().read(cx).snapshot(cx);
 2548                pending_selection.range().includes(range, &snapshot)
 2549            })
 2550        {
 2551            return true;
 2552        }
 2553
 2554        self.selections
 2555            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2556            .into_iter()
 2557            .any(|selection| {
 2558                // This is needed to cover a corner case, if we just check for an existing
 2559                // selection in the fold range, having a cursor at the start of the fold
 2560                // marks it as selected. Non-empty selections don't cause this.
 2561                let length = selection.end - selection.start;
 2562                length > 0
 2563            })
 2564    }
 2565
 2566    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2567        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2568    }
 2569
 2570    fn key_context_internal(
 2571        &self,
 2572        has_active_edit_prediction: bool,
 2573        window: &mut Window,
 2574        cx: &mut App,
 2575    ) -> KeyContext {
 2576        let mut key_context = KeyContext::new_with_defaults();
 2577        key_context.add("Editor");
 2578        let mode = match self.mode {
 2579            EditorMode::SingleLine => "single_line",
 2580            EditorMode::AutoHeight { .. } => "auto_height",
 2581            EditorMode::Minimap { .. } => "minimap",
 2582            EditorMode::Full { .. } => "full",
 2583        };
 2584
 2585        if EditorSettings::jupyter_enabled(cx) {
 2586            key_context.add("jupyter");
 2587        }
 2588
 2589        key_context.set("mode", mode);
 2590        if self.pending_rename.is_some() {
 2591            key_context.add("renaming");
 2592        }
 2593
 2594        if let Some(snippet_stack) = self.snippet_stack.last() {
 2595            key_context.add("in_snippet");
 2596
 2597            if snippet_stack.active_index > 0 {
 2598                key_context.add("has_previous_tabstop");
 2599            }
 2600
 2601            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2602                key_context.add("has_next_tabstop");
 2603            }
 2604        }
 2605
 2606        match self.context_menu.borrow().as_ref() {
 2607            Some(CodeContextMenu::Completions(menu)) => {
 2608                if menu.visible() {
 2609                    key_context.add("menu");
 2610                    key_context.add("showing_completions");
 2611                }
 2612            }
 2613            Some(CodeContextMenu::CodeActions(menu)) => {
 2614                if menu.visible() {
 2615                    key_context.add("menu");
 2616                    key_context.add("showing_code_actions")
 2617                }
 2618            }
 2619            None => {}
 2620        }
 2621
 2622        if self.signature_help_state.has_multiple_signatures() {
 2623            key_context.add("showing_signature_help");
 2624        }
 2625
 2626        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2627        if !self.focus_handle(cx).contains_focused(window, cx)
 2628            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2629        {
 2630            for addon in self.addons.values() {
 2631                addon.extend_key_context(&mut key_context, cx)
 2632            }
 2633        }
 2634
 2635        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2636            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2637                Some(
 2638                    file.full_path(cx)
 2639                        .extension()?
 2640                        .to_string_lossy()
 2641                        .into_owned(),
 2642                )
 2643            }) {
 2644                key_context.set("extension", extension);
 2645            }
 2646        } else {
 2647            key_context.add("multibuffer");
 2648        }
 2649
 2650        if has_active_edit_prediction {
 2651            if self.edit_prediction_in_conflict() {
 2652                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2653            } else {
 2654                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2655                key_context.add("copilot_suggestion");
 2656            }
 2657        }
 2658
 2659        if self.selection_mark_mode {
 2660            key_context.add("selection_mode");
 2661        }
 2662
 2663        let disjoint = self.selections.disjoint_anchors();
 2664        let snapshot = self.snapshot(window, cx);
 2665        let snapshot = snapshot.buffer_snapshot();
 2666        if self.mode == EditorMode::SingleLine
 2667            && let [selection] = disjoint
 2668            && selection.start == selection.end
 2669            && selection.end.to_offset(snapshot) == snapshot.len()
 2670        {
 2671            key_context.add("end_of_input");
 2672        }
 2673
 2674        if self.has_any_expanded_diff_hunks(cx) {
 2675            key_context.add("diffs_expanded");
 2676        }
 2677
 2678        key_context
 2679    }
 2680
 2681    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2682        self.last_bounds.as_ref()
 2683    }
 2684
 2685    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2686        if self.mouse_cursor_hidden {
 2687            self.mouse_cursor_hidden = false;
 2688            cx.notify();
 2689        }
 2690    }
 2691
 2692    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2693        let hide_mouse_cursor = match origin {
 2694            HideMouseCursorOrigin::TypingAction => {
 2695                matches!(
 2696                    self.hide_mouse_mode,
 2697                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2698                )
 2699            }
 2700            HideMouseCursorOrigin::MovementAction => {
 2701                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2702            }
 2703        };
 2704        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2705            self.mouse_cursor_hidden = hide_mouse_cursor;
 2706            cx.notify();
 2707        }
 2708    }
 2709
 2710    pub fn edit_prediction_in_conflict(&self) -> bool {
 2711        if !self.show_edit_predictions_in_menu() {
 2712            return false;
 2713        }
 2714
 2715        let showing_completions = self
 2716            .context_menu
 2717            .borrow()
 2718            .as_ref()
 2719            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2720
 2721        showing_completions
 2722            || self.edit_prediction_requires_modifier()
 2723            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2724            // bindings to insert tab characters.
 2725            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2726    }
 2727
 2728    pub fn accept_edit_prediction_keybind(
 2729        &self,
 2730        accept_partial: bool,
 2731        window: &mut Window,
 2732        cx: &mut App,
 2733    ) -> AcceptEditPredictionBinding {
 2734        let key_context = self.key_context_internal(true, window, cx);
 2735        let in_conflict = self.edit_prediction_in_conflict();
 2736
 2737        let bindings = if accept_partial {
 2738            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2739        } else {
 2740            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2741        };
 2742
 2743        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2744        // just the first one.
 2745        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2746            !in_conflict
 2747                || binding
 2748                    .keystrokes()
 2749                    .first()
 2750                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2751        }))
 2752    }
 2753
 2754    pub fn new_file(
 2755        workspace: &mut Workspace,
 2756        _: &workspace::NewFile,
 2757        window: &mut Window,
 2758        cx: &mut Context<Workspace>,
 2759    ) {
 2760        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2761            "Failed to create buffer",
 2762            window,
 2763            cx,
 2764            |e, _, _| match e.error_code() {
 2765                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2766                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2767                e.error_tag("required").unwrap_or("the latest version")
 2768            )),
 2769                _ => None,
 2770            },
 2771        );
 2772    }
 2773
 2774    pub fn new_in_workspace(
 2775        workspace: &mut Workspace,
 2776        window: &mut Window,
 2777        cx: &mut Context<Workspace>,
 2778    ) -> Task<Result<Entity<Editor>>> {
 2779        let project = workspace.project().clone();
 2780        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2781
 2782        cx.spawn_in(window, async move |workspace, cx| {
 2783            let buffer = create.await?;
 2784            workspace.update_in(cx, |workspace, window, cx| {
 2785                let editor =
 2786                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2787                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2788                editor
 2789            })
 2790        })
 2791    }
 2792
 2793    fn new_file_vertical(
 2794        workspace: &mut Workspace,
 2795        _: &workspace::NewFileSplitVertical,
 2796        window: &mut Window,
 2797        cx: &mut Context<Workspace>,
 2798    ) {
 2799        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2800    }
 2801
 2802    fn new_file_horizontal(
 2803        workspace: &mut Workspace,
 2804        _: &workspace::NewFileSplitHorizontal,
 2805        window: &mut Window,
 2806        cx: &mut Context<Workspace>,
 2807    ) {
 2808        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2809    }
 2810
 2811    fn new_file_split(
 2812        workspace: &mut Workspace,
 2813        action: &workspace::NewFileSplit,
 2814        window: &mut Window,
 2815        cx: &mut Context<Workspace>,
 2816    ) {
 2817        Self::new_file_in_direction(workspace, action.0, window, cx)
 2818    }
 2819
 2820    fn new_file_in_direction(
 2821        workspace: &mut Workspace,
 2822        direction: SplitDirection,
 2823        window: &mut Window,
 2824        cx: &mut Context<Workspace>,
 2825    ) {
 2826        let project = workspace.project().clone();
 2827        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2828
 2829        cx.spawn_in(window, async move |workspace, cx| {
 2830            let buffer = create.await?;
 2831            workspace.update_in(cx, move |workspace, window, cx| {
 2832                workspace.split_item(
 2833                    direction,
 2834                    Box::new(
 2835                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2836                    ),
 2837                    window,
 2838                    cx,
 2839                )
 2840            })?;
 2841            anyhow::Ok(())
 2842        })
 2843        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2844            match e.error_code() {
 2845                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2846                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2847                e.error_tag("required").unwrap_or("the latest version")
 2848            )),
 2849                _ => None,
 2850            }
 2851        });
 2852    }
 2853
 2854    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2855        self.leader_id
 2856    }
 2857
 2858    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2859        &self.buffer
 2860    }
 2861
 2862    pub fn project(&self) -> Option<&Entity<Project>> {
 2863        self.project.as_ref()
 2864    }
 2865
 2866    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2867        self.workspace.as_ref()?.0.upgrade()
 2868    }
 2869
 2870    /// Returns the workspace serialization ID if this editor should be serialized.
 2871    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2872        self.workspace
 2873            .as_ref()
 2874            .filter(|_| self.should_serialize_buffer())
 2875            .and_then(|workspace| workspace.1)
 2876    }
 2877
 2878    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2879        self.buffer().read(cx).title(cx)
 2880    }
 2881
 2882    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2883        let git_blame_gutter_max_author_length = self
 2884            .render_git_blame_gutter(cx)
 2885            .then(|| {
 2886                if let Some(blame) = self.blame.as_ref() {
 2887                    let max_author_length =
 2888                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2889                    Some(max_author_length)
 2890                } else {
 2891                    None
 2892                }
 2893            })
 2894            .flatten();
 2895
 2896        EditorSnapshot {
 2897            mode: self.mode.clone(),
 2898            show_gutter: self.show_gutter,
 2899            show_line_numbers: self.show_line_numbers,
 2900            show_git_diff_gutter: self.show_git_diff_gutter,
 2901            show_code_actions: self.show_code_actions,
 2902            show_runnables: self.show_runnables,
 2903            show_breakpoints: self.show_breakpoints,
 2904            git_blame_gutter_max_author_length,
 2905            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2906            placeholder_display_snapshot: self
 2907                .placeholder_display_map
 2908                .as_ref()
 2909                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2910            scroll_anchor: self.scroll_manager.anchor(),
 2911            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2912            is_focused: self.focus_handle.is_focused(window),
 2913            current_line_highlight: self
 2914                .current_line_highlight
 2915                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2916            gutter_hovered: self.gutter_hovered,
 2917        }
 2918    }
 2919
 2920    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2921        self.buffer.read(cx).language_at(point, cx)
 2922    }
 2923
 2924    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2925        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2926    }
 2927
 2928    pub fn active_excerpt(
 2929        &self,
 2930        cx: &App,
 2931    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2932        self.buffer
 2933            .read(cx)
 2934            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2935    }
 2936
 2937    pub fn mode(&self) -> &EditorMode {
 2938        &self.mode
 2939    }
 2940
 2941    pub fn set_mode(&mut self, mode: EditorMode) {
 2942        self.mode = mode;
 2943    }
 2944
 2945    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2946        self.collaboration_hub.as_deref()
 2947    }
 2948
 2949    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2950        self.collaboration_hub = Some(hub);
 2951    }
 2952
 2953    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2954        self.in_project_search = in_project_search;
 2955    }
 2956
 2957    pub fn set_custom_context_menu(
 2958        &mut self,
 2959        f: impl 'static
 2960        + Fn(
 2961            &mut Self,
 2962            DisplayPoint,
 2963            &mut Window,
 2964            &mut Context<Self>,
 2965        ) -> Option<Entity<ui::ContextMenu>>,
 2966    ) {
 2967        self.custom_context_menu = Some(Box::new(f))
 2968    }
 2969
 2970    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2971        self.completion_provider = provider;
 2972    }
 2973
 2974    #[cfg(any(test, feature = "test-support"))]
 2975    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2976        self.completion_provider.clone()
 2977    }
 2978
 2979    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2980        self.semantics_provider.clone()
 2981    }
 2982
 2983    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2984        self.semantics_provider = provider;
 2985    }
 2986
 2987    pub fn set_edit_prediction_provider<T>(
 2988        &mut self,
 2989        provider: Option<Entity<T>>,
 2990        window: &mut Window,
 2991        cx: &mut Context<Self>,
 2992    ) where
 2993        T: EditPredictionDelegate,
 2994    {
 2995        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 2996            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2997                if this.focus_handle.is_focused(window) {
 2998                    this.update_visible_edit_prediction(window, cx);
 2999                }
 3000            }),
 3001            provider: Arc::new(provider),
 3002        });
 3003        self.update_edit_prediction_settings(cx);
 3004        self.refresh_edit_prediction(false, false, window, cx);
 3005    }
 3006
 3007    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3008        self.placeholder_display_map
 3009            .as_ref()
 3010            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3011    }
 3012
 3013    pub fn set_placeholder_text(
 3014        &mut self,
 3015        placeholder_text: &str,
 3016        window: &mut Window,
 3017        cx: &mut Context<Self>,
 3018    ) {
 3019        let multibuffer = cx
 3020            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3021
 3022        let style = window.text_style();
 3023
 3024        self.placeholder_display_map = Some(cx.new(|cx| {
 3025            DisplayMap::new(
 3026                multibuffer,
 3027                style.font(),
 3028                style.font_size.to_pixels(window.rem_size()),
 3029                None,
 3030                FILE_HEADER_HEIGHT,
 3031                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3032                Default::default(),
 3033                DiagnosticSeverity::Off,
 3034                cx,
 3035            )
 3036        }));
 3037        cx.notify();
 3038    }
 3039
 3040    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3041        self.cursor_shape = cursor_shape;
 3042
 3043        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3044        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3045
 3046        cx.notify();
 3047    }
 3048
 3049    pub fn cursor_shape(&self) -> CursorShape {
 3050        self.cursor_shape
 3051    }
 3052
 3053    pub fn set_current_line_highlight(
 3054        &mut self,
 3055        current_line_highlight: Option<CurrentLineHighlight>,
 3056    ) {
 3057        self.current_line_highlight = current_line_highlight;
 3058    }
 3059
 3060    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3061        self.collapse_matches = collapse_matches;
 3062    }
 3063
 3064    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3065        if self.collapse_matches {
 3066            return range.start..range.start;
 3067        }
 3068        range.clone()
 3069    }
 3070
 3071    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3072        self.display_map.read(cx).clip_at_line_ends
 3073    }
 3074
 3075    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3076        if self.display_map.read(cx).clip_at_line_ends != clip {
 3077            self.display_map
 3078                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3079        }
 3080    }
 3081
 3082    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3083        self.input_enabled = input_enabled;
 3084    }
 3085
 3086    pub fn set_edit_predictions_hidden_for_vim_mode(
 3087        &mut self,
 3088        hidden: bool,
 3089        window: &mut Window,
 3090        cx: &mut Context<Self>,
 3091    ) {
 3092        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3093            self.edit_predictions_hidden_for_vim_mode = hidden;
 3094            if hidden {
 3095                self.update_visible_edit_prediction(window, cx);
 3096            } else {
 3097                self.refresh_edit_prediction(true, false, window, cx);
 3098            }
 3099        }
 3100    }
 3101
 3102    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3103        self.menu_edit_predictions_policy = value;
 3104    }
 3105
 3106    pub fn set_autoindent(&mut self, autoindent: bool) {
 3107        if autoindent {
 3108            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3109        } else {
 3110            self.autoindent_mode = None;
 3111        }
 3112    }
 3113
 3114    pub fn read_only(&self, cx: &App) -> bool {
 3115        self.read_only || self.buffer.read(cx).read_only()
 3116    }
 3117
 3118    pub fn set_read_only(&mut self, read_only: bool) {
 3119        self.read_only = read_only;
 3120    }
 3121
 3122    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3123        self.use_autoclose = autoclose;
 3124    }
 3125
 3126    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3127        self.use_auto_surround = auto_surround;
 3128    }
 3129
 3130    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3131        self.auto_replace_emoji_shortcode = auto_replace;
 3132    }
 3133
 3134    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3135        self.buffer_serialization = should_serialize.then(|| {
 3136            BufferSerialization::new(
 3137                ProjectSettings::get_global(cx)
 3138                    .session
 3139                    .restore_unsaved_buffers,
 3140            )
 3141        })
 3142    }
 3143
 3144    fn should_serialize_buffer(&self) -> bool {
 3145        self.buffer_serialization.is_some()
 3146    }
 3147
 3148    pub fn toggle_edit_predictions(
 3149        &mut self,
 3150        _: &ToggleEditPrediction,
 3151        window: &mut Window,
 3152        cx: &mut Context<Self>,
 3153    ) {
 3154        if self.show_edit_predictions_override.is_some() {
 3155            self.set_show_edit_predictions(None, window, cx);
 3156        } else {
 3157            let show_edit_predictions = !self.edit_predictions_enabled();
 3158            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3159        }
 3160    }
 3161
 3162    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3163        self.show_completions_on_input_override = show_completions_on_input;
 3164    }
 3165
 3166    pub fn set_show_edit_predictions(
 3167        &mut self,
 3168        show_edit_predictions: Option<bool>,
 3169        window: &mut Window,
 3170        cx: &mut Context<Self>,
 3171    ) {
 3172        self.show_edit_predictions_override = show_edit_predictions;
 3173        self.update_edit_prediction_settings(cx);
 3174
 3175        if let Some(false) = show_edit_predictions {
 3176            self.discard_edit_prediction(false, cx);
 3177        } else {
 3178            self.refresh_edit_prediction(false, true, window, cx);
 3179        }
 3180    }
 3181
 3182    fn edit_predictions_disabled_in_scope(
 3183        &self,
 3184        buffer: &Entity<Buffer>,
 3185        buffer_position: language::Anchor,
 3186        cx: &App,
 3187    ) -> bool {
 3188        let snapshot = buffer.read(cx).snapshot();
 3189        let settings = snapshot.settings_at(buffer_position, cx);
 3190
 3191        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3192            return false;
 3193        };
 3194
 3195        scope.override_name().is_some_and(|scope_name| {
 3196            settings
 3197                .edit_predictions_disabled_in
 3198                .iter()
 3199                .any(|s| s == scope_name)
 3200        })
 3201    }
 3202
 3203    pub fn set_use_modal_editing(&mut self, to: bool) {
 3204        self.use_modal_editing = to;
 3205    }
 3206
 3207    pub fn use_modal_editing(&self) -> bool {
 3208        self.use_modal_editing
 3209    }
 3210
 3211    fn selections_did_change(
 3212        &mut self,
 3213        local: bool,
 3214        old_cursor_position: &Anchor,
 3215        effects: SelectionEffects,
 3216        window: &mut Window,
 3217        cx: &mut Context<Self>,
 3218    ) {
 3219        window.invalidate_character_coordinates();
 3220
 3221        // Copy selections to primary selection buffer
 3222        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3223        if local {
 3224            let selections = self
 3225                .selections
 3226                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3227            let buffer_handle = self.buffer.read(cx).read(cx);
 3228
 3229            let mut text = String::new();
 3230            for (index, selection) in selections.iter().enumerate() {
 3231                let text_for_selection = buffer_handle
 3232                    .text_for_range(selection.start..selection.end)
 3233                    .collect::<String>();
 3234
 3235                text.push_str(&text_for_selection);
 3236                if index != selections.len() - 1 {
 3237                    text.push('\n');
 3238                }
 3239            }
 3240
 3241            if !text.is_empty() {
 3242                cx.write_to_primary(ClipboardItem::new_string(text));
 3243            }
 3244        }
 3245
 3246        let selection_anchors = self.selections.disjoint_anchors_arc();
 3247
 3248        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3249            self.buffer.update(cx, |buffer, cx| {
 3250                buffer.set_active_selections(
 3251                    &selection_anchors,
 3252                    self.selections.line_mode(),
 3253                    self.cursor_shape,
 3254                    cx,
 3255                )
 3256            });
 3257        }
 3258        let display_map = self
 3259            .display_map
 3260            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3261        let buffer = display_map.buffer_snapshot();
 3262        if self.selections.count() == 1 {
 3263            self.add_selections_state = None;
 3264        }
 3265        self.select_next_state = None;
 3266        self.select_prev_state = None;
 3267        self.select_syntax_node_history.try_clear();
 3268        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3269        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3270        self.take_rename(false, window, cx);
 3271
 3272        let newest_selection = self.selections.newest_anchor();
 3273        let new_cursor_position = newest_selection.head();
 3274        let selection_start = newest_selection.start;
 3275
 3276        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3277            self.push_to_nav_history(
 3278                *old_cursor_position,
 3279                Some(new_cursor_position.to_point(buffer)),
 3280                false,
 3281                effects.nav_history == Some(true),
 3282                cx,
 3283            );
 3284        }
 3285
 3286        if local {
 3287            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3288                self.register_buffer(buffer_id, cx);
 3289            }
 3290
 3291            let mut context_menu = self.context_menu.borrow_mut();
 3292            let completion_menu = match context_menu.as_ref() {
 3293                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3294                Some(CodeContextMenu::CodeActions(_)) => {
 3295                    *context_menu = None;
 3296                    None
 3297                }
 3298                None => None,
 3299            };
 3300            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3301            drop(context_menu);
 3302
 3303            if effects.completions
 3304                && let Some(completion_position) = completion_position
 3305            {
 3306                let start_offset = selection_start.to_offset(buffer);
 3307                let position_matches = start_offset == completion_position.to_offset(buffer);
 3308                let continue_showing = if position_matches {
 3309                    if self.snippet_stack.is_empty() {
 3310                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3311                            == Some(CharKind::Word)
 3312                    } else {
 3313                        // Snippet choices can be shown even when the cursor is in whitespace.
 3314                        // Dismissing the menu with actions like backspace is handled by
 3315                        // invalidation regions.
 3316                        true
 3317                    }
 3318                } else {
 3319                    false
 3320                };
 3321
 3322                if continue_showing {
 3323                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3324                } else {
 3325                    self.hide_context_menu(window, cx);
 3326                }
 3327            }
 3328
 3329            hide_hover(self, cx);
 3330
 3331            if old_cursor_position.to_display_point(&display_map).row()
 3332                != new_cursor_position.to_display_point(&display_map).row()
 3333            {
 3334                self.available_code_actions.take();
 3335            }
 3336            self.refresh_code_actions(window, cx);
 3337            self.refresh_document_highlights(cx);
 3338            refresh_linked_ranges(self, window, cx);
 3339
 3340            self.refresh_selected_text_highlights(false, window, cx);
 3341            self.refresh_matching_bracket_highlights(window, cx);
 3342            self.update_visible_edit_prediction(window, cx);
 3343            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3344            self.inline_blame_popover.take();
 3345            if self.git_blame_inline_enabled {
 3346                self.start_inline_blame_timer(window, cx);
 3347            }
 3348        }
 3349
 3350        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3351        cx.emit(EditorEvent::SelectionsChanged { local });
 3352
 3353        let selections = &self.selections.disjoint_anchors_arc();
 3354        if selections.len() == 1 {
 3355            cx.emit(SearchEvent::ActiveMatchChanged)
 3356        }
 3357        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3358            let inmemory_selections = selections
 3359                .iter()
 3360                .map(|s| {
 3361                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3362                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3363                })
 3364                .collect();
 3365            self.update_restoration_data(cx, |data| {
 3366                data.selections = inmemory_selections;
 3367            });
 3368
 3369            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3370                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3371            {
 3372                let snapshot = self.buffer().read(cx).snapshot(cx);
 3373                let selections = selections.clone();
 3374                let background_executor = cx.background_executor().clone();
 3375                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3376                self.serialize_selections = cx.background_spawn(async move {
 3377                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3378                    let db_selections = selections
 3379                        .iter()
 3380                        .map(|selection| {
 3381                            (
 3382                                selection.start.to_offset(&snapshot).0,
 3383                                selection.end.to_offset(&snapshot).0,
 3384                            )
 3385                        })
 3386                        .collect();
 3387
 3388                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3389                        .await
 3390                        .with_context(|| {
 3391                            format!(
 3392                                "persisting editor selections for editor {editor_id}, \
 3393                                workspace {workspace_id:?}"
 3394                            )
 3395                        })
 3396                        .log_err();
 3397                });
 3398            }
 3399        }
 3400
 3401        cx.notify();
 3402    }
 3403
 3404    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3405        use text::ToOffset as _;
 3406        use text::ToPoint as _;
 3407
 3408        if self.mode.is_minimap()
 3409            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3410        {
 3411            return;
 3412        }
 3413
 3414        if !self.buffer().read(cx).is_singleton() {
 3415            return;
 3416        }
 3417
 3418        let display_snapshot = self
 3419            .display_map
 3420            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3421        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3422            return;
 3423        };
 3424        let inmemory_folds = display_snapshot
 3425            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3426            .map(|fold| {
 3427                fold.range.start.text_anchor.to_point(&snapshot)
 3428                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3429            })
 3430            .collect();
 3431        self.update_restoration_data(cx, |data| {
 3432            data.folds = inmemory_folds;
 3433        });
 3434
 3435        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3436            return;
 3437        };
 3438        let background_executor = cx.background_executor().clone();
 3439        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3440        let db_folds = display_snapshot
 3441            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3442            .map(|fold| {
 3443                (
 3444                    fold.range.start.text_anchor.to_offset(&snapshot),
 3445                    fold.range.end.text_anchor.to_offset(&snapshot),
 3446                )
 3447            })
 3448            .collect();
 3449        self.serialize_folds = cx.background_spawn(async move {
 3450            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3451            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3452                .await
 3453                .with_context(|| {
 3454                    format!(
 3455                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3456                    )
 3457                })
 3458                .log_err();
 3459        });
 3460    }
 3461
 3462    pub fn sync_selections(
 3463        &mut self,
 3464        other: Entity<Editor>,
 3465        cx: &mut Context<Self>,
 3466    ) -> gpui::Subscription {
 3467        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3468        if !other_selections.is_empty() {
 3469            self.selections
 3470                .change_with(&self.display_snapshot(cx), |selections| {
 3471                    selections.select_anchors(other_selections);
 3472                });
 3473        }
 3474
 3475        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3476            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3477                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3478                if other_selections.is_empty() {
 3479                    return;
 3480                }
 3481                let snapshot = this.display_snapshot(cx);
 3482                this.selections.change_with(&snapshot, |selections| {
 3483                    selections.select_anchors(other_selections);
 3484                });
 3485            }
 3486        });
 3487
 3488        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3489            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3490                let these_selections = this.selections.disjoint_anchors().to_vec();
 3491                if these_selections.is_empty() {
 3492                    return;
 3493                }
 3494                other.update(cx, |other_editor, cx| {
 3495                    let snapshot = other_editor.display_snapshot(cx);
 3496                    other_editor
 3497                        .selections
 3498                        .change_with(&snapshot, |selections| {
 3499                            selections.select_anchors(these_selections);
 3500                        })
 3501                });
 3502            }
 3503        });
 3504
 3505        Subscription::join(other_subscription, this_subscription)
 3506    }
 3507
 3508    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3509        if self.buffer().read(cx).is_singleton() {
 3510            return;
 3511        }
 3512        let snapshot = self.buffer.read(cx).snapshot(cx);
 3513        let buffer_ids: HashSet<BufferId> = self
 3514            .selections
 3515            .disjoint_anchor_ranges()
 3516            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3517            .collect();
 3518        for buffer_id in buffer_ids {
 3519            self.unfold_buffer(buffer_id, cx);
 3520        }
 3521    }
 3522
 3523    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3524    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3525    /// effects of selection change occur at the end of the transaction.
 3526    pub fn change_selections<R>(
 3527        &mut self,
 3528        effects: SelectionEffects,
 3529        window: &mut Window,
 3530        cx: &mut Context<Self>,
 3531        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3532    ) -> R {
 3533        let snapshot = self.display_snapshot(cx);
 3534        if let Some(state) = &mut self.deferred_selection_effects_state {
 3535            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3536            state.effects.completions = effects.completions;
 3537            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3538            let (changed, result) = self.selections.change_with(&snapshot, change);
 3539            state.changed |= changed;
 3540            return result;
 3541        }
 3542        let mut state = DeferredSelectionEffectsState {
 3543            changed: false,
 3544            effects,
 3545            old_cursor_position: self.selections.newest_anchor().head(),
 3546            history_entry: SelectionHistoryEntry {
 3547                selections: self.selections.disjoint_anchors_arc(),
 3548                select_next_state: self.select_next_state.clone(),
 3549                select_prev_state: self.select_prev_state.clone(),
 3550                add_selections_state: self.add_selections_state.clone(),
 3551            },
 3552        };
 3553        let (changed, result) = self.selections.change_with(&snapshot, change);
 3554        state.changed = state.changed || changed;
 3555        if self.defer_selection_effects {
 3556            self.deferred_selection_effects_state = Some(state);
 3557        } else {
 3558            self.apply_selection_effects(state, window, cx);
 3559        }
 3560        result
 3561    }
 3562
 3563    /// Defers the effects of selection change, so that the effects of multiple calls to
 3564    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3565    /// to selection history and the state of popovers based on selection position aren't
 3566    /// erroneously updated.
 3567    pub fn with_selection_effects_deferred<R>(
 3568        &mut self,
 3569        window: &mut Window,
 3570        cx: &mut Context<Self>,
 3571        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3572    ) -> R {
 3573        let already_deferred = self.defer_selection_effects;
 3574        self.defer_selection_effects = true;
 3575        let result = update(self, window, cx);
 3576        if !already_deferred {
 3577            self.defer_selection_effects = false;
 3578            if let Some(state) = self.deferred_selection_effects_state.take() {
 3579                self.apply_selection_effects(state, window, cx);
 3580            }
 3581        }
 3582        result
 3583    }
 3584
 3585    fn apply_selection_effects(
 3586        &mut self,
 3587        state: DeferredSelectionEffectsState,
 3588        window: &mut Window,
 3589        cx: &mut Context<Self>,
 3590    ) {
 3591        if state.changed {
 3592            self.selection_history.push(state.history_entry);
 3593
 3594            if let Some(autoscroll) = state.effects.scroll {
 3595                self.request_autoscroll(autoscroll, cx);
 3596            }
 3597
 3598            let old_cursor_position = &state.old_cursor_position;
 3599
 3600            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3601
 3602            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3603                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3604            }
 3605        }
 3606    }
 3607
 3608    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3609    where
 3610        I: IntoIterator<Item = (Range<S>, T)>,
 3611        S: ToOffset,
 3612        T: Into<Arc<str>>,
 3613    {
 3614        if self.read_only(cx) {
 3615            return;
 3616        }
 3617
 3618        self.buffer
 3619            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3620    }
 3621
 3622    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3623    where
 3624        I: IntoIterator<Item = (Range<S>, T)>,
 3625        S: ToOffset,
 3626        T: Into<Arc<str>>,
 3627    {
 3628        if self.read_only(cx) {
 3629            return;
 3630        }
 3631
 3632        self.buffer.update(cx, |buffer, cx| {
 3633            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3634        });
 3635    }
 3636
 3637    pub fn edit_with_block_indent<I, S, T>(
 3638        &mut self,
 3639        edits: I,
 3640        original_indent_columns: Vec<Option<u32>>,
 3641        cx: &mut Context<Self>,
 3642    ) where
 3643        I: IntoIterator<Item = (Range<S>, T)>,
 3644        S: ToOffset,
 3645        T: Into<Arc<str>>,
 3646    {
 3647        if self.read_only(cx) {
 3648            return;
 3649        }
 3650
 3651        self.buffer.update(cx, |buffer, cx| {
 3652            buffer.edit(
 3653                edits,
 3654                Some(AutoindentMode::Block {
 3655                    original_indent_columns,
 3656                }),
 3657                cx,
 3658            )
 3659        });
 3660    }
 3661
 3662    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3663        self.hide_context_menu(window, cx);
 3664
 3665        match phase {
 3666            SelectPhase::Begin {
 3667                position,
 3668                add,
 3669                click_count,
 3670            } => self.begin_selection(position, add, click_count, window, cx),
 3671            SelectPhase::BeginColumnar {
 3672                position,
 3673                goal_column,
 3674                reset,
 3675                mode,
 3676            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3677            SelectPhase::Extend {
 3678                position,
 3679                click_count,
 3680            } => self.extend_selection(position, click_count, window, cx),
 3681            SelectPhase::Update {
 3682                position,
 3683                goal_column,
 3684                scroll_delta,
 3685            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3686            SelectPhase::End => self.end_selection(window, cx),
 3687        }
 3688    }
 3689
 3690    fn extend_selection(
 3691        &mut self,
 3692        position: DisplayPoint,
 3693        click_count: usize,
 3694        window: &mut Window,
 3695        cx: &mut Context<Self>,
 3696    ) {
 3697        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3698        let tail = self
 3699            .selections
 3700            .newest::<MultiBufferOffset>(&display_map)
 3701            .tail();
 3702        let click_count = click_count.max(match self.selections.select_mode() {
 3703            SelectMode::Character => 1,
 3704            SelectMode::Word(_) => 2,
 3705            SelectMode::Line(_) => 3,
 3706            SelectMode::All => 4,
 3707        });
 3708        self.begin_selection(position, false, click_count, window, cx);
 3709
 3710        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3711
 3712        let current_selection = match self.selections.select_mode() {
 3713            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3714            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3715        };
 3716
 3717        let mut pending_selection = self
 3718            .selections
 3719            .pending_anchor()
 3720            .cloned()
 3721            .expect("extend_selection not called with pending selection");
 3722
 3723        if pending_selection
 3724            .start
 3725            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3726            == Ordering::Greater
 3727        {
 3728            pending_selection.start = current_selection.start;
 3729        }
 3730        if pending_selection
 3731            .end
 3732            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3733            == Ordering::Less
 3734        {
 3735            pending_selection.end = current_selection.end;
 3736            pending_selection.reversed = true;
 3737        }
 3738
 3739        let mut pending_mode = self.selections.pending_mode().unwrap();
 3740        match &mut pending_mode {
 3741            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3742            _ => {}
 3743        }
 3744
 3745        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3746            SelectionEffects::scroll(Autoscroll::fit())
 3747        } else {
 3748            SelectionEffects::no_scroll()
 3749        };
 3750
 3751        self.change_selections(effects, window, cx, |s| {
 3752            s.set_pending(pending_selection.clone(), pending_mode);
 3753            s.set_is_extending(true);
 3754        });
 3755    }
 3756
 3757    fn begin_selection(
 3758        &mut self,
 3759        position: DisplayPoint,
 3760        add: bool,
 3761        click_count: usize,
 3762        window: &mut Window,
 3763        cx: &mut Context<Self>,
 3764    ) {
 3765        if !self.focus_handle.is_focused(window) {
 3766            self.last_focused_descendant = None;
 3767            window.focus(&self.focus_handle);
 3768        }
 3769
 3770        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3771        let buffer = display_map.buffer_snapshot();
 3772        let position = display_map.clip_point(position, Bias::Left);
 3773
 3774        let start;
 3775        let end;
 3776        let mode;
 3777        let mut auto_scroll;
 3778        match click_count {
 3779            1 => {
 3780                start = buffer.anchor_before(position.to_point(&display_map));
 3781                end = start;
 3782                mode = SelectMode::Character;
 3783                auto_scroll = true;
 3784            }
 3785            2 => {
 3786                let position = display_map
 3787                    .clip_point(position, Bias::Left)
 3788                    .to_offset(&display_map, Bias::Left);
 3789                let (range, _) = buffer.surrounding_word(position, None);
 3790                start = buffer.anchor_before(range.start);
 3791                end = buffer.anchor_before(range.end);
 3792                mode = SelectMode::Word(start..end);
 3793                auto_scroll = true;
 3794            }
 3795            3 => {
 3796                let position = display_map
 3797                    .clip_point(position, Bias::Left)
 3798                    .to_point(&display_map);
 3799                let line_start = display_map.prev_line_boundary(position).0;
 3800                let next_line_start = buffer.clip_point(
 3801                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3802                    Bias::Left,
 3803                );
 3804                start = buffer.anchor_before(line_start);
 3805                end = buffer.anchor_before(next_line_start);
 3806                mode = SelectMode::Line(start..end);
 3807                auto_scroll = true;
 3808            }
 3809            _ => {
 3810                start = buffer.anchor_before(MultiBufferOffset(0));
 3811                end = buffer.anchor_before(buffer.len());
 3812                mode = SelectMode::All;
 3813                auto_scroll = false;
 3814            }
 3815        }
 3816        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3817
 3818        let point_to_delete: Option<usize> = {
 3819            let selected_points: Vec<Selection<Point>> =
 3820                self.selections.disjoint_in_range(start..end, &display_map);
 3821
 3822            if !add || click_count > 1 {
 3823                None
 3824            } else if !selected_points.is_empty() {
 3825                Some(selected_points[0].id)
 3826            } else {
 3827                let clicked_point_already_selected =
 3828                    self.selections.disjoint_anchors().iter().find(|selection| {
 3829                        selection.start.to_point(buffer) == start.to_point(buffer)
 3830                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3831                    });
 3832
 3833                clicked_point_already_selected.map(|selection| selection.id)
 3834            }
 3835        };
 3836
 3837        let selections_count = self.selections.count();
 3838        let effects = if auto_scroll {
 3839            SelectionEffects::default()
 3840        } else {
 3841            SelectionEffects::no_scroll()
 3842        };
 3843
 3844        self.change_selections(effects, window, cx, |s| {
 3845            if let Some(point_to_delete) = point_to_delete {
 3846                s.delete(point_to_delete);
 3847
 3848                if selections_count == 1 {
 3849                    s.set_pending_anchor_range(start..end, mode);
 3850                }
 3851            } else {
 3852                if !add {
 3853                    s.clear_disjoint();
 3854                }
 3855
 3856                s.set_pending_anchor_range(start..end, mode);
 3857            }
 3858        });
 3859    }
 3860
 3861    fn begin_columnar_selection(
 3862        &mut self,
 3863        position: DisplayPoint,
 3864        goal_column: u32,
 3865        reset: bool,
 3866        mode: ColumnarMode,
 3867        window: &mut Window,
 3868        cx: &mut Context<Self>,
 3869    ) {
 3870        if !self.focus_handle.is_focused(window) {
 3871            self.last_focused_descendant = None;
 3872            window.focus(&self.focus_handle);
 3873        }
 3874
 3875        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3876
 3877        if reset {
 3878            let pointer_position = display_map
 3879                .buffer_snapshot()
 3880                .anchor_before(position.to_point(&display_map));
 3881
 3882            self.change_selections(
 3883                SelectionEffects::scroll(Autoscroll::newest()),
 3884                window,
 3885                cx,
 3886                |s| {
 3887                    s.clear_disjoint();
 3888                    s.set_pending_anchor_range(
 3889                        pointer_position..pointer_position,
 3890                        SelectMode::Character,
 3891                    );
 3892                },
 3893            );
 3894        };
 3895
 3896        let tail = self.selections.newest::<Point>(&display_map).tail();
 3897        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3898        self.columnar_selection_state = match mode {
 3899            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3900                selection_tail: selection_anchor,
 3901                display_point: if reset {
 3902                    if position.column() != goal_column {
 3903                        Some(DisplayPoint::new(position.row(), goal_column))
 3904                    } else {
 3905                        None
 3906                    }
 3907                } else {
 3908                    None
 3909                },
 3910            }),
 3911            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3912                selection_tail: selection_anchor,
 3913            }),
 3914        };
 3915
 3916        if !reset {
 3917            self.select_columns(position, goal_column, &display_map, window, cx);
 3918        }
 3919    }
 3920
 3921    fn update_selection(
 3922        &mut self,
 3923        position: DisplayPoint,
 3924        goal_column: u32,
 3925        scroll_delta: gpui::Point<f32>,
 3926        window: &mut Window,
 3927        cx: &mut Context<Self>,
 3928    ) {
 3929        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3930
 3931        if self.columnar_selection_state.is_some() {
 3932            self.select_columns(position, goal_column, &display_map, window, cx);
 3933        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3934            let buffer = display_map.buffer_snapshot();
 3935            let head;
 3936            let tail;
 3937            let mode = self.selections.pending_mode().unwrap();
 3938            match &mode {
 3939                SelectMode::Character => {
 3940                    head = position.to_point(&display_map);
 3941                    tail = pending.tail().to_point(buffer);
 3942                }
 3943                SelectMode::Word(original_range) => {
 3944                    let offset = display_map
 3945                        .clip_point(position, Bias::Left)
 3946                        .to_offset(&display_map, Bias::Left);
 3947                    let original_range = original_range.to_offset(buffer);
 3948
 3949                    let head_offset = if buffer.is_inside_word(offset, None)
 3950                        || original_range.contains(&offset)
 3951                    {
 3952                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3953                        if word_range.start < original_range.start {
 3954                            word_range.start
 3955                        } else {
 3956                            word_range.end
 3957                        }
 3958                    } else {
 3959                        offset
 3960                    };
 3961
 3962                    head = head_offset.to_point(buffer);
 3963                    if head_offset <= original_range.start {
 3964                        tail = original_range.end.to_point(buffer);
 3965                    } else {
 3966                        tail = original_range.start.to_point(buffer);
 3967                    }
 3968                }
 3969                SelectMode::Line(original_range) => {
 3970                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3971
 3972                    let position = display_map
 3973                        .clip_point(position, Bias::Left)
 3974                        .to_point(&display_map);
 3975                    let line_start = display_map.prev_line_boundary(position).0;
 3976                    let next_line_start = buffer.clip_point(
 3977                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3978                        Bias::Left,
 3979                    );
 3980
 3981                    if line_start < original_range.start {
 3982                        head = line_start
 3983                    } else {
 3984                        head = next_line_start
 3985                    }
 3986
 3987                    if head <= original_range.start {
 3988                        tail = original_range.end;
 3989                    } else {
 3990                        tail = original_range.start;
 3991                    }
 3992                }
 3993                SelectMode::All => {
 3994                    return;
 3995                }
 3996            };
 3997
 3998            if head < tail {
 3999                pending.start = buffer.anchor_before(head);
 4000                pending.end = buffer.anchor_before(tail);
 4001                pending.reversed = true;
 4002            } else {
 4003                pending.start = buffer.anchor_before(tail);
 4004                pending.end = buffer.anchor_before(head);
 4005                pending.reversed = false;
 4006            }
 4007
 4008            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4009                s.set_pending(pending.clone(), mode);
 4010            });
 4011        } else {
 4012            log::error!("update_selection dispatched with no pending selection");
 4013            return;
 4014        }
 4015
 4016        self.apply_scroll_delta(scroll_delta, window, cx);
 4017        cx.notify();
 4018    }
 4019
 4020    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4021        self.columnar_selection_state.take();
 4022        if let Some(pending_mode) = self.selections.pending_mode() {
 4023            let selections = self
 4024                .selections
 4025                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4026            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4027                s.select(selections);
 4028                s.clear_pending();
 4029                if s.is_extending() {
 4030                    s.set_is_extending(false);
 4031                } else {
 4032                    s.set_select_mode(pending_mode);
 4033                }
 4034            });
 4035        }
 4036    }
 4037
 4038    fn select_columns(
 4039        &mut self,
 4040        head: DisplayPoint,
 4041        goal_column: u32,
 4042        display_map: &DisplaySnapshot,
 4043        window: &mut Window,
 4044        cx: &mut Context<Self>,
 4045    ) {
 4046        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4047            return;
 4048        };
 4049
 4050        let tail = match columnar_state {
 4051            ColumnarSelectionState::FromMouse {
 4052                selection_tail,
 4053                display_point,
 4054            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4055            ColumnarSelectionState::FromSelection { selection_tail } => {
 4056                selection_tail.to_display_point(display_map)
 4057            }
 4058        };
 4059
 4060        let start_row = cmp::min(tail.row(), head.row());
 4061        let end_row = cmp::max(tail.row(), head.row());
 4062        let start_column = cmp::min(tail.column(), goal_column);
 4063        let end_column = cmp::max(tail.column(), goal_column);
 4064        let reversed = start_column < tail.column();
 4065
 4066        let selection_ranges = (start_row.0..=end_row.0)
 4067            .map(DisplayRow)
 4068            .filter_map(|row| {
 4069                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4070                    || start_column <= display_map.line_len(row))
 4071                    && !display_map.is_block_line(row)
 4072                {
 4073                    let start = display_map
 4074                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4075                        .to_point(display_map);
 4076                    let end = display_map
 4077                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4078                        .to_point(display_map);
 4079                    if reversed {
 4080                        Some(end..start)
 4081                    } else {
 4082                        Some(start..end)
 4083                    }
 4084                } else {
 4085                    None
 4086                }
 4087            })
 4088            .collect::<Vec<_>>();
 4089        if selection_ranges.is_empty() {
 4090            return;
 4091        }
 4092
 4093        let ranges = match columnar_state {
 4094            ColumnarSelectionState::FromMouse { .. } => {
 4095                let mut non_empty_ranges = selection_ranges
 4096                    .iter()
 4097                    .filter(|selection_range| selection_range.start != selection_range.end)
 4098                    .peekable();
 4099                if non_empty_ranges.peek().is_some() {
 4100                    non_empty_ranges.cloned().collect()
 4101                } else {
 4102                    selection_ranges
 4103                }
 4104            }
 4105            _ => selection_ranges,
 4106        };
 4107
 4108        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4109            s.select_ranges(ranges);
 4110        });
 4111        cx.notify();
 4112    }
 4113
 4114    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4115        self.selections
 4116            .all_adjusted(snapshot)
 4117            .iter()
 4118            .any(|selection| !selection.is_empty())
 4119    }
 4120
 4121    pub fn has_pending_nonempty_selection(&self) -> bool {
 4122        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4123            Some(Selection { start, end, .. }) => start != end,
 4124            None => false,
 4125        };
 4126
 4127        pending_nonempty_selection
 4128            || (self.columnar_selection_state.is_some()
 4129                && self.selections.disjoint_anchors().len() > 1)
 4130    }
 4131
 4132    pub fn has_pending_selection(&self) -> bool {
 4133        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4134    }
 4135
 4136    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4137        self.selection_mark_mode = false;
 4138        self.selection_drag_state = SelectionDragState::None;
 4139
 4140        if self.dismiss_menus_and_popups(true, window, cx) {
 4141            cx.notify();
 4142            return;
 4143        }
 4144        if self.clear_expanded_diff_hunks(cx) {
 4145            cx.notify();
 4146            return;
 4147        }
 4148        if self.show_git_blame_gutter {
 4149            self.show_git_blame_gutter = false;
 4150            cx.notify();
 4151            return;
 4152        }
 4153
 4154        if self.mode.is_full()
 4155            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4156        {
 4157            cx.notify();
 4158            return;
 4159        }
 4160
 4161        cx.propagate();
 4162    }
 4163
 4164    pub fn dismiss_menus_and_popups(
 4165        &mut self,
 4166        is_user_requested: bool,
 4167        window: &mut Window,
 4168        cx: &mut Context<Self>,
 4169    ) -> bool {
 4170        let mut dismissed = false;
 4171
 4172        dismissed |= self.take_rename(false, window, cx).is_some();
 4173        dismissed |= self.hide_blame_popover(true, cx);
 4174        dismissed |= hide_hover(self, cx);
 4175        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4176        dismissed |= self.hide_context_menu(window, cx).is_some();
 4177        dismissed |= self.mouse_context_menu.take().is_some();
 4178        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4179        dismissed |= self.snippet_stack.pop().is_some();
 4180
 4181        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4182            self.dismiss_diagnostics(cx);
 4183            dismissed = true;
 4184        }
 4185
 4186        dismissed
 4187    }
 4188
 4189    fn linked_editing_ranges_for(
 4190        &self,
 4191        selection: Range<text::Anchor>,
 4192        cx: &App,
 4193    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4194        if self.linked_edit_ranges.is_empty() {
 4195            return None;
 4196        }
 4197        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4198            selection.end.buffer_id.and_then(|end_buffer_id| {
 4199                if selection.start.buffer_id != Some(end_buffer_id) {
 4200                    return None;
 4201                }
 4202                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4203                let snapshot = buffer.read(cx).snapshot();
 4204                self.linked_edit_ranges
 4205                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4206                    .map(|ranges| (ranges, snapshot, buffer))
 4207            })?;
 4208        use text::ToOffset as TO;
 4209        // find offset from the start of current range to current cursor position
 4210        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4211
 4212        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4213        let start_difference = start_offset - start_byte_offset;
 4214        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4215        let end_difference = end_offset - start_byte_offset;
 4216        // Current range has associated linked ranges.
 4217        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4218        for range in linked_ranges.iter() {
 4219            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4220            let end_offset = start_offset + end_difference;
 4221            let start_offset = start_offset + start_difference;
 4222            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4223                continue;
 4224            }
 4225            if self.selections.disjoint_anchor_ranges().any(|s| {
 4226                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4227                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4228                {
 4229                    return false;
 4230                }
 4231                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4232                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4233            }) {
 4234                continue;
 4235            }
 4236            let start = buffer_snapshot.anchor_after(start_offset);
 4237            let end = buffer_snapshot.anchor_after(end_offset);
 4238            linked_edits
 4239                .entry(buffer.clone())
 4240                .or_default()
 4241                .push(start..end);
 4242        }
 4243        Some(linked_edits)
 4244    }
 4245
 4246    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4247        let text: Arc<str> = text.into();
 4248
 4249        if self.read_only(cx) {
 4250            return;
 4251        }
 4252
 4253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4254
 4255        self.unfold_buffers_with_selections(cx);
 4256
 4257        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4258        let mut bracket_inserted = false;
 4259        let mut edits = Vec::new();
 4260        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4261        let mut new_selections = Vec::with_capacity(selections.len());
 4262        let mut new_autoclose_regions = Vec::new();
 4263        let snapshot = self.buffer.read(cx).read(cx);
 4264        let mut clear_linked_edit_ranges = false;
 4265
 4266        for (selection, autoclose_region) in
 4267            self.selections_with_autoclose_regions(selections, &snapshot)
 4268        {
 4269            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4270                // Determine if the inserted text matches the opening or closing
 4271                // bracket of any of this language's bracket pairs.
 4272                let mut bracket_pair = None;
 4273                let mut is_bracket_pair_start = false;
 4274                let mut is_bracket_pair_end = false;
 4275                if !text.is_empty() {
 4276                    let mut bracket_pair_matching_end = None;
 4277                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4278                    //  and they are removing the character that triggered IME popup.
 4279                    for (pair, enabled) in scope.brackets() {
 4280                        if !pair.close && !pair.surround {
 4281                            continue;
 4282                        }
 4283
 4284                        if enabled && pair.start.ends_with(text.as_ref()) {
 4285                            let prefix_len = pair.start.len() - text.len();
 4286                            let preceding_text_matches_prefix = prefix_len == 0
 4287                                || (selection.start.column >= (prefix_len as u32)
 4288                                    && snapshot.contains_str_at(
 4289                                        Point::new(
 4290                                            selection.start.row,
 4291                                            selection.start.column - (prefix_len as u32),
 4292                                        ),
 4293                                        &pair.start[..prefix_len],
 4294                                    ));
 4295                            if preceding_text_matches_prefix {
 4296                                bracket_pair = Some(pair.clone());
 4297                                is_bracket_pair_start = true;
 4298                                break;
 4299                            }
 4300                        }
 4301                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4302                        {
 4303                            // take first bracket pair matching end, but don't break in case a later bracket
 4304                            // pair matches start
 4305                            bracket_pair_matching_end = Some(pair.clone());
 4306                        }
 4307                    }
 4308                    if let Some(end) = bracket_pair_matching_end
 4309                        && bracket_pair.is_none()
 4310                    {
 4311                        bracket_pair = Some(end);
 4312                        is_bracket_pair_end = true;
 4313                    }
 4314                }
 4315
 4316                if let Some(bracket_pair) = bracket_pair {
 4317                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4318                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4319                    let auto_surround =
 4320                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4321                    if selection.is_empty() {
 4322                        if is_bracket_pair_start {
 4323                            // If the inserted text is a suffix of an opening bracket and the
 4324                            // selection is preceded by the rest of the opening bracket, then
 4325                            // insert the closing bracket.
 4326                            let following_text_allows_autoclose = snapshot
 4327                                .chars_at(selection.start)
 4328                                .next()
 4329                                .is_none_or(|c| scope.should_autoclose_before(c));
 4330
 4331                            let preceding_text_allows_autoclose = selection.start.column == 0
 4332                                || snapshot
 4333                                    .reversed_chars_at(selection.start)
 4334                                    .next()
 4335                                    .is_none_or(|c| {
 4336                                        bracket_pair.start != bracket_pair.end
 4337                                            || !snapshot
 4338                                                .char_classifier_at(selection.start)
 4339                                                .is_word(c)
 4340                                    });
 4341
 4342                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4343                                && bracket_pair.start.len() == 1
 4344                            {
 4345                                let target = bracket_pair.start.chars().next().unwrap();
 4346                                let current_line_count = snapshot
 4347                                    .reversed_chars_at(selection.start)
 4348                                    .take_while(|&c| c != '\n')
 4349                                    .filter(|&c| c == target)
 4350                                    .count();
 4351                                current_line_count % 2 == 1
 4352                            } else {
 4353                                false
 4354                            };
 4355
 4356                            if autoclose
 4357                                && bracket_pair.close
 4358                                && following_text_allows_autoclose
 4359                                && preceding_text_allows_autoclose
 4360                                && !is_closing_quote
 4361                            {
 4362                                let anchor = snapshot.anchor_before(selection.end);
 4363                                new_selections.push((selection.map(|_| anchor), text.len()));
 4364                                new_autoclose_regions.push((
 4365                                    anchor,
 4366                                    text.len(),
 4367                                    selection.id,
 4368                                    bracket_pair.clone(),
 4369                                ));
 4370                                edits.push((
 4371                                    selection.range(),
 4372                                    format!("{}{}", text, bracket_pair.end).into(),
 4373                                ));
 4374                                bracket_inserted = true;
 4375                                continue;
 4376                            }
 4377                        }
 4378
 4379                        if let Some(region) = autoclose_region {
 4380                            // If the selection is followed by an auto-inserted closing bracket,
 4381                            // then don't insert that closing bracket again; just move the selection
 4382                            // past the closing bracket.
 4383                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4384                                && text.as_ref() == region.pair.end.as_str()
 4385                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4386                            if should_skip {
 4387                                let anchor = snapshot.anchor_after(selection.end);
 4388                                new_selections
 4389                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4390                                continue;
 4391                            }
 4392                        }
 4393
 4394                        let always_treat_brackets_as_autoclosed = snapshot
 4395                            .language_settings_at(selection.start, cx)
 4396                            .always_treat_brackets_as_autoclosed;
 4397                        if always_treat_brackets_as_autoclosed
 4398                            && is_bracket_pair_end
 4399                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4400                        {
 4401                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4402                            // and the inserted text is a closing bracket and the selection is followed
 4403                            // by the closing bracket then move the selection past the closing bracket.
 4404                            let anchor = snapshot.anchor_after(selection.end);
 4405                            new_selections.push((selection.map(|_| anchor), text.len()));
 4406                            continue;
 4407                        }
 4408                    }
 4409                    // If an opening bracket is 1 character long and is typed while
 4410                    // text is selected, then surround that text with the bracket pair.
 4411                    else if auto_surround
 4412                        && bracket_pair.surround
 4413                        && is_bracket_pair_start
 4414                        && bracket_pair.start.chars().count() == 1
 4415                    {
 4416                        edits.push((selection.start..selection.start, text.clone()));
 4417                        edits.push((
 4418                            selection.end..selection.end,
 4419                            bracket_pair.end.as_str().into(),
 4420                        ));
 4421                        bracket_inserted = true;
 4422                        new_selections.push((
 4423                            Selection {
 4424                                id: selection.id,
 4425                                start: snapshot.anchor_after(selection.start),
 4426                                end: snapshot.anchor_before(selection.end),
 4427                                reversed: selection.reversed,
 4428                                goal: selection.goal,
 4429                            },
 4430                            0,
 4431                        ));
 4432                        continue;
 4433                    }
 4434                }
 4435            }
 4436
 4437            if self.auto_replace_emoji_shortcode
 4438                && selection.is_empty()
 4439                && text.as_ref().ends_with(':')
 4440                && let Some(possible_emoji_short_code) =
 4441                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4442                && !possible_emoji_short_code.is_empty()
 4443                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4444            {
 4445                let emoji_shortcode_start = Point::new(
 4446                    selection.start.row,
 4447                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4448                );
 4449
 4450                // Remove shortcode from buffer
 4451                edits.push((
 4452                    emoji_shortcode_start..selection.start,
 4453                    "".to_string().into(),
 4454                ));
 4455                new_selections.push((
 4456                    Selection {
 4457                        id: selection.id,
 4458                        start: snapshot.anchor_after(emoji_shortcode_start),
 4459                        end: snapshot.anchor_before(selection.start),
 4460                        reversed: selection.reversed,
 4461                        goal: selection.goal,
 4462                    },
 4463                    0,
 4464                ));
 4465
 4466                // Insert emoji
 4467                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4468                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4469                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4470
 4471                continue;
 4472            }
 4473
 4474            // If not handling any auto-close operation, then just replace the selected
 4475            // text with the given input and move the selection to the end of the
 4476            // newly inserted text.
 4477            let anchor = snapshot.anchor_after(selection.end);
 4478            if !self.linked_edit_ranges.is_empty() {
 4479                let start_anchor = snapshot.anchor_before(selection.start);
 4480
 4481                let is_word_char = text.chars().next().is_none_or(|char| {
 4482                    let classifier = snapshot
 4483                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4484                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4485                    classifier.is_word(char)
 4486                });
 4487
 4488                if is_word_char {
 4489                    if let Some(ranges) = self
 4490                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4491                    {
 4492                        for (buffer, edits) in ranges {
 4493                            linked_edits
 4494                                .entry(buffer.clone())
 4495                                .or_default()
 4496                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4497                        }
 4498                    }
 4499                } else {
 4500                    clear_linked_edit_ranges = true;
 4501                }
 4502            }
 4503
 4504            new_selections.push((selection.map(|_| anchor), 0));
 4505            edits.push((selection.start..selection.end, text.clone()));
 4506        }
 4507
 4508        drop(snapshot);
 4509
 4510        self.transact(window, cx, |this, window, cx| {
 4511            if clear_linked_edit_ranges {
 4512                this.linked_edit_ranges.clear();
 4513            }
 4514            let initial_buffer_versions =
 4515                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4516
 4517            this.buffer.update(cx, |buffer, cx| {
 4518                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4519            });
 4520            for (buffer, edits) in linked_edits {
 4521                buffer.update(cx, |buffer, cx| {
 4522                    let snapshot = buffer.snapshot();
 4523                    let edits = edits
 4524                        .into_iter()
 4525                        .map(|(range, text)| {
 4526                            use text::ToPoint as TP;
 4527                            let end_point = TP::to_point(&range.end, &snapshot);
 4528                            let start_point = TP::to_point(&range.start, &snapshot);
 4529                            (start_point..end_point, text)
 4530                        })
 4531                        .sorted_by_key(|(range, _)| range.start);
 4532                    buffer.edit(edits, None, cx);
 4533                })
 4534            }
 4535            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4536            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4537            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4538            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4539                new_anchor_selections,
 4540                &map,
 4541            )
 4542            .zip(new_selection_deltas)
 4543            .map(|(selection, delta)| Selection {
 4544                id: selection.id,
 4545                start: selection.start + delta,
 4546                end: selection.end + delta,
 4547                reversed: selection.reversed,
 4548                goal: SelectionGoal::None,
 4549            })
 4550            .collect::<Vec<_>>();
 4551
 4552            let mut i = 0;
 4553            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4554                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4555                let start = map.buffer_snapshot().anchor_before(position);
 4556                let end = map.buffer_snapshot().anchor_after(position);
 4557                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4558                    match existing_state
 4559                        .range
 4560                        .start
 4561                        .cmp(&start, map.buffer_snapshot())
 4562                    {
 4563                        Ordering::Less => i += 1,
 4564                        Ordering::Greater => break,
 4565                        Ordering::Equal => {
 4566                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4567                                Ordering::Less => i += 1,
 4568                                Ordering::Equal => break,
 4569                                Ordering::Greater => break,
 4570                            }
 4571                        }
 4572                    }
 4573                }
 4574                this.autoclose_regions.insert(
 4575                    i,
 4576                    AutocloseRegion {
 4577                        selection_id,
 4578                        range: start..end,
 4579                        pair,
 4580                    },
 4581                );
 4582            }
 4583
 4584            let had_active_edit_prediction = this.has_active_edit_prediction();
 4585            this.change_selections(
 4586                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4587                window,
 4588                cx,
 4589                |s| s.select(new_selections),
 4590            );
 4591
 4592            if !bracket_inserted
 4593                && let Some(on_type_format_task) =
 4594                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4595            {
 4596                on_type_format_task.detach_and_log_err(cx);
 4597            }
 4598
 4599            let editor_settings = EditorSettings::get_global(cx);
 4600            if bracket_inserted
 4601                && (editor_settings.auto_signature_help
 4602                    || editor_settings.show_signature_help_after_edits)
 4603            {
 4604                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4605            }
 4606
 4607            let trigger_in_words =
 4608                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4609            if this.hard_wrap.is_some() {
 4610                let latest: Range<Point> = this.selections.newest(&map).range();
 4611                if latest.is_empty()
 4612                    && this
 4613                        .buffer()
 4614                        .read(cx)
 4615                        .snapshot(cx)
 4616                        .line_len(MultiBufferRow(latest.start.row))
 4617                        == latest.start.column
 4618                {
 4619                    this.rewrap_impl(
 4620                        RewrapOptions {
 4621                            override_language_settings: true,
 4622                            preserve_existing_whitespace: true,
 4623                        },
 4624                        cx,
 4625                    )
 4626                }
 4627            }
 4628            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4629            refresh_linked_ranges(this, window, cx);
 4630            this.refresh_edit_prediction(true, false, window, cx);
 4631            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4632        });
 4633    }
 4634
 4635    fn find_possible_emoji_shortcode_at_position(
 4636        snapshot: &MultiBufferSnapshot,
 4637        position: Point,
 4638    ) -> Option<String> {
 4639        let mut chars = Vec::new();
 4640        let mut found_colon = false;
 4641        for char in snapshot.reversed_chars_at(position).take(100) {
 4642            // Found a possible emoji shortcode in the middle of the buffer
 4643            if found_colon {
 4644                if char.is_whitespace() {
 4645                    chars.reverse();
 4646                    return Some(chars.iter().collect());
 4647                }
 4648                // If the previous character is not a whitespace, we are in the middle of a word
 4649                // and we only want to complete the shortcode if the word is made up of other emojis
 4650                let mut containing_word = String::new();
 4651                for ch in snapshot
 4652                    .reversed_chars_at(position)
 4653                    .skip(chars.len() + 1)
 4654                    .take(100)
 4655                {
 4656                    if ch.is_whitespace() {
 4657                        break;
 4658                    }
 4659                    containing_word.push(ch);
 4660                }
 4661                let containing_word = containing_word.chars().rev().collect::<String>();
 4662                if util::word_consists_of_emojis(containing_word.as_str()) {
 4663                    chars.reverse();
 4664                    return Some(chars.iter().collect());
 4665                }
 4666            }
 4667
 4668            if char.is_whitespace() || !char.is_ascii() {
 4669                return None;
 4670            }
 4671            if char == ':' {
 4672                found_colon = true;
 4673            } else {
 4674                chars.push(char);
 4675            }
 4676        }
 4677        // Found a possible emoji shortcode at the beginning of the buffer
 4678        chars.reverse();
 4679        Some(chars.iter().collect())
 4680    }
 4681
 4682    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4684        self.transact(window, cx, |this, window, cx| {
 4685            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4686                let selections = this
 4687                    .selections
 4688                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4689                let multi_buffer = this.buffer.read(cx);
 4690                let buffer = multi_buffer.snapshot(cx);
 4691                selections
 4692                    .iter()
 4693                    .map(|selection| {
 4694                        let start_point = selection.start.to_point(&buffer);
 4695                        let mut existing_indent =
 4696                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4697                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4698                        let start = selection.start;
 4699                        let end = selection.end;
 4700                        let selection_is_empty = start == end;
 4701                        let language_scope = buffer.language_scope_at(start);
 4702                        let (
 4703                            comment_delimiter,
 4704                            doc_delimiter,
 4705                            insert_extra_newline,
 4706                            indent_on_newline,
 4707                            indent_on_extra_newline,
 4708                        ) = if let Some(language) = &language_scope {
 4709                            let mut insert_extra_newline =
 4710                                insert_extra_newline_brackets(&buffer, start..end, language)
 4711                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4712
 4713                            // Comment extension on newline is allowed only for cursor selections
 4714                            let comment_delimiter = maybe!({
 4715                                if !selection_is_empty {
 4716                                    return None;
 4717                                }
 4718
 4719                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4720                                    return None;
 4721                                }
 4722
 4723                                let delimiters = language.line_comment_prefixes();
 4724                                let max_len_of_delimiter =
 4725                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4726                                let (snapshot, range) =
 4727                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4728
 4729                                let num_of_whitespaces = snapshot
 4730                                    .chars_for_range(range.clone())
 4731                                    .take_while(|c| c.is_whitespace())
 4732                                    .count();
 4733                                let comment_candidate = snapshot
 4734                                    .chars_for_range(range.clone())
 4735                                    .skip(num_of_whitespaces)
 4736                                    .take(max_len_of_delimiter)
 4737                                    .collect::<String>();
 4738                                let (delimiter, trimmed_len) = delimiters
 4739                                    .iter()
 4740                                    .filter_map(|delimiter| {
 4741                                        let prefix = delimiter.trim_end();
 4742                                        if comment_candidate.starts_with(prefix) {
 4743                                            Some((delimiter, prefix.len()))
 4744                                        } else {
 4745                                            None
 4746                                        }
 4747                                    })
 4748                                    .max_by_key(|(_, len)| *len)?;
 4749
 4750                                if let Some(BlockCommentConfig {
 4751                                    start: block_start, ..
 4752                                }) = language.block_comment()
 4753                                {
 4754                                    let block_start_trimmed = block_start.trim_end();
 4755                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4756                                        let line_content = snapshot
 4757                                            .chars_for_range(range)
 4758                                            .skip(num_of_whitespaces)
 4759                                            .take(block_start_trimmed.len())
 4760                                            .collect::<String>();
 4761
 4762                                        if line_content.starts_with(block_start_trimmed) {
 4763                                            return None;
 4764                                        }
 4765                                    }
 4766                                }
 4767
 4768                                let cursor_is_placed_after_comment_marker =
 4769                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4770                                if cursor_is_placed_after_comment_marker {
 4771                                    Some(delimiter.clone())
 4772                                } else {
 4773                                    None
 4774                                }
 4775                            });
 4776
 4777                            let mut indent_on_newline = IndentSize::spaces(0);
 4778                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4779
 4780                            let doc_delimiter = maybe!({
 4781                                if !selection_is_empty {
 4782                                    return None;
 4783                                }
 4784
 4785                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4786                                    return None;
 4787                                }
 4788
 4789                                let BlockCommentConfig {
 4790                                    start: start_tag,
 4791                                    end: end_tag,
 4792                                    prefix: delimiter,
 4793                                    tab_size: len,
 4794                                } = language.documentation_comment()?;
 4795                                let is_within_block_comment = buffer
 4796                                    .language_scope_at(start_point)
 4797                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4798                                if !is_within_block_comment {
 4799                                    return None;
 4800                                }
 4801
 4802                                let (snapshot, range) =
 4803                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4804
 4805                                let num_of_whitespaces = snapshot
 4806                                    .chars_for_range(range.clone())
 4807                                    .take_while(|c| c.is_whitespace())
 4808                                    .count();
 4809
 4810                                // 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.
 4811                                let column = start_point.column;
 4812                                let cursor_is_after_start_tag = {
 4813                                    let start_tag_len = start_tag.len();
 4814                                    let start_tag_line = snapshot
 4815                                        .chars_for_range(range.clone())
 4816                                        .skip(num_of_whitespaces)
 4817                                        .take(start_tag_len)
 4818                                        .collect::<String>();
 4819                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4820                                        num_of_whitespaces + start_tag_len <= column as usize
 4821                                    } else {
 4822                                        false
 4823                                    }
 4824                                };
 4825
 4826                                let cursor_is_after_delimiter = {
 4827                                    let delimiter_trim = delimiter.trim_end();
 4828                                    let delimiter_line = snapshot
 4829                                        .chars_for_range(range.clone())
 4830                                        .skip(num_of_whitespaces)
 4831                                        .take(delimiter_trim.len())
 4832                                        .collect::<String>();
 4833                                    if delimiter_line.starts_with(delimiter_trim) {
 4834                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4835                                    } else {
 4836                                        false
 4837                                    }
 4838                                };
 4839
 4840                                let cursor_is_before_end_tag_if_exists = {
 4841                                    let mut char_position = 0u32;
 4842                                    let mut end_tag_offset = None;
 4843
 4844                                    'outer: for chunk in snapshot.text_for_range(range) {
 4845                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4846                                            let chars_before_match =
 4847                                                chunk[..byte_pos].chars().count() as u32;
 4848                                            end_tag_offset =
 4849                                                Some(char_position + chars_before_match);
 4850                                            break 'outer;
 4851                                        }
 4852                                        char_position += chunk.chars().count() as u32;
 4853                                    }
 4854
 4855                                    if let Some(end_tag_offset) = end_tag_offset {
 4856                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4857                                        if cursor_is_after_start_tag {
 4858                                            if cursor_is_before_end_tag {
 4859                                                insert_extra_newline = true;
 4860                                            }
 4861                                            let cursor_is_at_start_of_end_tag =
 4862                                                column == end_tag_offset;
 4863                                            if cursor_is_at_start_of_end_tag {
 4864                                                indent_on_extra_newline.len = *len;
 4865                                            }
 4866                                        }
 4867                                        cursor_is_before_end_tag
 4868                                    } else {
 4869                                        true
 4870                                    }
 4871                                };
 4872
 4873                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4874                                    && cursor_is_before_end_tag_if_exists
 4875                                {
 4876                                    if cursor_is_after_start_tag {
 4877                                        indent_on_newline.len = *len;
 4878                                    }
 4879                                    Some(delimiter.clone())
 4880                                } else {
 4881                                    None
 4882                                }
 4883                            });
 4884
 4885                            (
 4886                                comment_delimiter,
 4887                                doc_delimiter,
 4888                                insert_extra_newline,
 4889                                indent_on_newline,
 4890                                indent_on_extra_newline,
 4891                            )
 4892                        } else {
 4893                            (
 4894                                None,
 4895                                None,
 4896                                false,
 4897                                IndentSize::default(),
 4898                                IndentSize::default(),
 4899                            )
 4900                        };
 4901
 4902                        let prevent_auto_indent = doc_delimiter.is_some();
 4903                        let delimiter = comment_delimiter.or(doc_delimiter);
 4904
 4905                        let capacity_for_delimiter =
 4906                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4907                        let mut new_text = String::with_capacity(
 4908                            1 + capacity_for_delimiter
 4909                                + existing_indent.len as usize
 4910                                + indent_on_newline.len as usize
 4911                                + indent_on_extra_newline.len as usize,
 4912                        );
 4913                        new_text.push('\n');
 4914                        new_text.extend(existing_indent.chars());
 4915                        new_text.extend(indent_on_newline.chars());
 4916
 4917                        if let Some(delimiter) = &delimiter {
 4918                            new_text.push_str(delimiter);
 4919                        }
 4920
 4921                        if insert_extra_newline {
 4922                            new_text.push('\n');
 4923                            new_text.extend(existing_indent.chars());
 4924                            new_text.extend(indent_on_extra_newline.chars());
 4925                        }
 4926
 4927                        let anchor = buffer.anchor_after(end);
 4928                        let new_selection = selection.map(|_| anchor);
 4929                        (
 4930                            ((start..end, new_text), prevent_auto_indent),
 4931                            (insert_extra_newline, new_selection),
 4932                        )
 4933                    })
 4934                    .unzip()
 4935            };
 4936
 4937            let mut auto_indent_edits = Vec::new();
 4938            let mut edits = Vec::new();
 4939            for (edit, prevent_auto_indent) in edits_with_flags {
 4940                if prevent_auto_indent {
 4941                    edits.push(edit);
 4942                } else {
 4943                    auto_indent_edits.push(edit);
 4944                }
 4945            }
 4946            if !edits.is_empty() {
 4947                this.edit(edits, cx);
 4948            }
 4949            if !auto_indent_edits.is_empty() {
 4950                this.edit_with_autoindent(auto_indent_edits, cx);
 4951            }
 4952
 4953            let buffer = this.buffer.read(cx).snapshot(cx);
 4954            let new_selections = selection_info
 4955                .into_iter()
 4956                .map(|(extra_newline_inserted, new_selection)| {
 4957                    let mut cursor = new_selection.end.to_point(&buffer);
 4958                    if extra_newline_inserted {
 4959                        cursor.row -= 1;
 4960                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4961                    }
 4962                    new_selection.map(|_| cursor)
 4963                })
 4964                .collect();
 4965
 4966            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4967            this.refresh_edit_prediction(true, false, window, cx);
 4968        });
 4969    }
 4970
 4971    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4973
 4974        let buffer = self.buffer.read(cx);
 4975        let snapshot = buffer.snapshot(cx);
 4976
 4977        let mut edits = Vec::new();
 4978        let mut rows = Vec::new();
 4979
 4980        for (rows_inserted, selection) in self
 4981            .selections
 4982            .all_adjusted(&self.display_snapshot(cx))
 4983            .into_iter()
 4984            .enumerate()
 4985        {
 4986            let cursor = selection.head();
 4987            let row = cursor.row;
 4988
 4989            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4990
 4991            let newline = "\n".to_string();
 4992            edits.push((start_of_line..start_of_line, newline));
 4993
 4994            rows.push(row + rows_inserted as u32);
 4995        }
 4996
 4997        self.transact(window, cx, |editor, window, cx| {
 4998            editor.edit(edits, cx);
 4999
 5000            editor.change_selections(Default::default(), window, cx, |s| {
 5001                let mut index = 0;
 5002                s.move_cursors_with(|map, _, _| {
 5003                    let row = rows[index];
 5004                    index += 1;
 5005
 5006                    let point = Point::new(row, 0);
 5007                    let boundary = map.next_line_boundary(point).1;
 5008                    let clipped = map.clip_point(boundary, Bias::Left);
 5009
 5010                    (clipped, SelectionGoal::None)
 5011                });
 5012            });
 5013
 5014            let mut indent_edits = Vec::new();
 5015            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5016            for row in rows {
 5017                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5018                for (row, indent) in indents {
 5019                    if indent.len == 0 {
 5020                        continue;
 5021                    }
 5022
 5023                    let text = match indent.kind {
 5024                        IndentKind::Space => " ".repeat(indent.len as usize),
 5025                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5026                    };
 5027                    let point = Point::new(row.0, 0);
 5028                    indent_edits.push((point..point, text));
 5029                }
 5030            }
 5031            editor.edit(indent_edits, cx);
 5032        });
 5033    }
 5034
 5035    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5037
 5038        let buffer = self.buffer.read(cx);
 5039        let snapshot = buffer.snapshot(cx);
 5040
 5041        let mut edits = Vec::new();
 5042        let mut rows = Vec::new();
 5043        let mut rows_inserted = 0;
 5044
 5045        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5046            let cursor = selection.head();
 5047            let row = cursor.row;
 5048
 5049            let point = Point::new(row + 1, 0);
 5050            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5051
 5052            let newline = "\n".to_string();
 5053            edits.push((start_of_line..start_of_line, newline));
 5054
 5055            rows_inserted += 1;
 5056            rows.push(row + rows_inserted);
 5057        }
 5058
 5059        self.transact(window, cx, |editor, window, cx| {
 5060            editor.edit(edits, cx);
 5061
 5062            editor.change_selections(Default::default(), window, cx, |s| {
 5063                let mut index = 0;
 5064                s.move_cursors_with(|map, _, _| {
 5065                    let row = rows[index];
 5066                    index += 1;
 5067
 5068                    let point = Point::new(row, 0);
 5069                    let boundary = map.next_line_boundary(point).1;
 5070                    let clipped = map.clip_point(boundary, Bias::Left);
 5071
 5072                    (clipped, SelectionGoal::None)
 5073                });
 5074            });
 5075
 5076            let mut indent_edits = Vec::new();
 5077            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5078            for row in rows {
 5079                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5080                for (row, indent) in indents {
 5081                    if indent.len == 0 {
 5082                        continue;
 5083                    }
 5084
 5085                    let text = match indent.kind {
 5086                        IndentKind::Space => " ".repeat(indent.len as usize),
 5087                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5088                    };
 5089                    let point = Point::new(row.0, 0);
 5090                    indent_edits.push((point..point, text));
 5091                }
 5092            }
 5093            editor.edit(indent_edits, cx);
 5094        });
 5095    }
 5096
 5097    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5098        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5099            original_indent_columns: Vec::new(),
 5100        });
 5101        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5102    }
 5103
 5104    fn insert_with_autoindent_mode(
 5105        &mut self,
 5106        text: &str,
 5107        autoindent_mode: Option<AutoindentMode>,
 5108        window: &mut Window,
 5109        cx: &mut Context<Self>,
 5110    ) {
 5111        if self.read_only(cx) {
 5112            return;
 5113        }
 5114
 5115        let text: Arc<str> = text.into();
 5116        self.transact(window, cx, |this, window, cx| {
 5117            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5118            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5119                let anchors = {
 5120                    let snapshot = buffer.read(cx);
 5121                    old_selections
 5122                        .iter()
 5123                        .map(|s| {
 5124                            let anchor = snapshot.anchor_after(s.head());
 5125                            s.map(|_| anchor)
 5126                        })
 5127                        .collect::<Vec<_>>()
 5128                };
 5129                buffer.edit(
 5130                    old_selections
 5131                        .iter()
 5132                        .map(|s| (s.start..s.end, text.clone())),
 5133                    autoindent_mode,
 5134                    cx,
 5135                );
 5136                anchors
 5137            });
 5138
 5139            this.change_selections(Default::default(), window, cx, |s| {
 5140                s.select_anchors(selection_anchors);
 5141            });
 5142
 5143            cx.notify();
 5144        });
 5145    }
 5146
 5147    fn trigger_completion_on_input(
 5148        &mut self,
 5149        text: &str,
 5150        trigger_in_words: bool,
 5151        window: &mut Window,
 5152        cx: &mut Context<Self>,
 5153    ) {
 5154        let completions_source = self
 5155            .context_menu
 5156            .borrow()
 5157            .as_ref()
 5158            .and_then(|menu| match menu {
 5159                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5160                CodeContextMenu::CodeActions(_) => None,
 5161            });
 5162
 5163        match completions_source {
 5164            Some(CompletionsMenuSource::Words { .. }) => {
 5165                self.open_or_update_completions_menu(
 5166                    Some(CompletionsMenuSource::Words {
 5167                        ignore_threshold: false,
 5168                    }),
 5169                    None,
 5170                    trigger_in_words,
 5171                    window,
 5172                    cx,
 5173                );
 5174            }
 5175            _ => self.open_or_update_completions_menu(
 5176                None,
 5177                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5178                true,
 5179                window,
 5180                cx,
 5181            ),
 5182        }
 5183    }
 5184
 5185    /// If any empty selections is touching the start of its innermost containing autoclose
 5186    /// region, expand it to select the brackets.
 5187    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5188        let selections = self
 5189            .selections
 5190            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5191        let buffer = self.buffer.read(cx).read(cx);
 5192        let new_selections = self
 5193            .selections_with_autoclose_regions(selections, &buffer)
 5194            .map(|(mut selection, region)| {
 5195                if !selection.is_empty() {
 5196                    return selection;
 5197                }
 5198
 5199                if let Some(region) = region {
 5200                    let mut range = region.range.to_offset(&buffer);
 5201                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5202                        range.start -= region.pair.start.len();
 5203                        if buffer.contains_str_at(range.start, &region.pair.start)
 5204                            && buffer.contains_str_at(range.end, &region.pair.end)
 5205                        {
 5206                            range.end += region.pair.end.len();
 5207                            selection.start = range.start;
 5208                            selection.end = range.end;
 5209
 5210                            return selection;
 5211                        }
 5212                    }
 5213                }
 5214
 5215                let always_treat_brackets_as_autoclosed = buffer
 5216                    .language_settings_at(selection.start, cx)
 5217                    .always_treat_brackets_as_autoclosed;
 5218
 5219                if !always_treat_brackets_as_autoclosed {
 5220                    return selection;
 5221                }
 5222
 5223                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5224                    for (pair, enabled) in scope.brackets() {
 5225                        if !enabled || !pair.close {
 5226                            continue;
 5227                        }
 5228
 5229                        if buffer.contains_str_at(selection.start, &pair.end) {
 5230                            let pair_start_len = pair.start.len();
 5231                            if buffer.contains_str_at(
 5232                                selection.start.saturating_sub_usize(pair_start_len),
 5233                                &pair.start,
 5234                            ) {
 5235                                selection.start -= pair_start_len;
 5236                                selection.end += pair.end.len();
 5237
 5238                                return selection;
 5239                            }
 5240                        }
 5241                    }
 5242                }
 5243
 5244                selection
 5245            })
 5246            .collect();
 5247
 5248        drop(buffer);
 5249        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5250            selections.select(new_selections)
 5251        });
 5252    }
 5253
 5254    /// Iterate the given selections, and for each one, find the smallest surrounding
 5255    /// autoclose region. This uses the ordering of the selections and the autoclose
 5256    /// regions to avoid repeated comparisons.
 5257    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5258        &'a self,
 5259        selections: impl IntoIterator<Item = Selection<D>>,
 5260        buffer: &'a MultiBufferSnapshot,
 5261    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5262        let mut i = 0;
 5263        let mut regions = self.autoclose_regions.as_slice();
 5264        selections.into_iter().map(move |selection| {
 5265            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5266
 5267            let mut enclosing = None;
 5268            while let Some(pair_state) = regions.get(i) {
 5269                if pair_state.range.end.to_offset(buffer) < range.start {
 5270                    regions = &regions[i + 1..];
 5271                    i = 0;
 5272                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5273                    break;
 5274                } else {
 5275                    if pair_state.selection_id == selection.id {
 5276                        enclosing = Some(pair_state);
 5277                    }
 5278                    i += 1;
 5279                }
 5280            }
 5281
 5282            (selection, enclosing)
 5283        })
 5284    }
 5285
 5286    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5287    fn invalidate_autoclose_regions(
 5288        &mut self,
 5289        mut selections: &[Selection<Anchor>],
 5290        buffer: &MultiBufferSnapshot,
 5291    ) {
 5292        self.autoclose_regions.retain(|state| {
 5293            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5294                return false;
 5295            }
 5296
 5297            let mut i = 0;
 5298            while let Some(selection) = selections.get(i) {
 5299                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5300                    selections = &selections[1..];
 5301                    continue;
 5302                }
 5303                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5304                    break;
 5305                }
 5306                if selection.id == state.selection_id {
 5307                    return true;
 5308                } else {
 5309                    i += 1;
 5310                }
 5311            }
 5312            false
 5313        });
 5314    }
 5315
 5316    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5317        let offset = position.to_offset(buffer);
 5318        let (word_range, kind) =
 5319            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5320        if offset > word_range.start && kind == Some(CharKind::Word) {
 5321            Some(
 5322                buffer
 5323                    .text_for_range(word_range.start..offset)
 5324                    .collect::<String>(),
 5325            )
 5326        } else {
 5327            None
 5328        }
 5329    }
 5330
 5331    pub fn visible_excerpts(
 5332        &self,
 5333        lsp_related_only: bool,
 5334        cx: &mut Context<Editor>,
 5335    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5336        let project = self.project().cloned();
 5337        let multi_buffer = self.buffer().read(cx);
 5338        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5339        let multi_buffer_visible_start = self
 5340            .scroll_manager
 5341            .anchor()
 5342            .anchor
 5343            .to_point(&multi_buffer_snapshot);
 5344        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5345            multi_buffer_visible_start
 5346                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5347            Bias::Left,
 5348        );
 5349        multi_buffer_snapshot
 5350            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5351            .into_iter()
 5352            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5353            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5354                if !lsp_related_only {
 5355                    return Some((
 5356                        excerpt_id,
 5357                        (
 5358                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5359                            buffer.version().clone(),
 5360                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5361                        ),
 5362                    ));
 5363                }
 5364
 5365                let project = project.as_ref()?.read(cx);
 5366                let buffer_file = project::File::from_dyn(buffer.file())?;
 5367                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5368                let worktree_entry = buffer_worktree
 5369                    .read(cx)
 5370                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5371                if worktree_entry.is_ignored {
 5372                    None
 5373                } else {
 5374                    Some((
 5375                        excerpt_id,
 5376                        (
 5377                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5378                            buffer.version().clone(),
 5379                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5380                        ),
 5381                    ))
 5382                }
 5383            })
 5384            .collect()
 5385    }
 5386
 5387    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5388        TextLayoutDetails {
 5389            text_system: window.text_system().clone(),
 5390            editor_style: self.style.clone().unwrap(),
 5391            rem_size: window.rem_size(),
 5392            scroll_anchor: self.scroll_manager.anchor(),
 5393            visible_rows: self.visible_line_count(),
 5394            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5395        }
 5396    }
 5397
 5398    fn trigger_on_type_formatting(
 5399        &self,
 5400        input: String,
 5401        window: &mut Window,
 5402        cx: &mut Context<Self>,
 5403    ) -> Option<Task<Result<()>>> {
 5404        if input.len() != 1 {
 5405            return None;
 5406        }
 5407
 5408        let project = self.project()?;
 5409        let position = self.selections.newest_anchor().head();
 5410        let (buffer, buffer_position) = self
 5411            .buffer
 5412            .read(cx)
 5413            .text_anchor_for_position(position, cx)?;
 5414
 5415        let settings = language_settings::language_settings(
 5416            buffer
 5417                .read(cx)
 5418                .language_at(buffer_position)
 5419                .map(|l| l.name()),
 5420            buffer.read(cx).file(),
 5421            cx,
 5422        );
 5423        if !settings.use_on_type_format {
 5424            return None;
 5425        }
 5426
 5427        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5428        // hence we do LSP request & edit on host side only — add formats to host's history.
 5429        let push_to_lsp_host_history = true;
 5430        // If this is not the host, append its history with new edits.
 5431        let push_to_client_history = project.read(cx).is_via_collab();
 5432
 5433        let on_type_formatting = project.update(cx, |project, cx| {
 5434            project.on_type_format(
 5435                buffer.clone(),
 5436                buffer_position,
 5437                input,
 5438                push_to_lsp_host_history,
 5439                cx,
 5440            )
 5441        });
 5442        Some(cx.spawn_in(window, async move |editor, cx| {
 5443            if let Some(transaction) = on_type_formatting.await? {
 5444                if push_to_client_history {
 5445                    buffer
 5446                        .update(cx, |buffer, _| {
 5447                            buffer.push_transaction(transaction, Instant::now());
 5448                            buffer.finalize_last_transaction();
 5449                        })
 5450                        .ok();
 5451                }
 5452                editor.update(cx, |editor, cx| {
 5453                    editor.refresh_document_highlights(cx);
 5454                })?;
 5455            }
 5456            Ok(())
 5457        }))
 5458    }
 5459
 5460    pub fn show_word_completions(
 5461        &mut self,
 5462        _: &ShowWordCompletions,
 5463        window: &mut Window,
 5464        cx: &mut Context<Self>,
 5465    ) {
 5466        self.open_or_update_completions_menu(
 5467            Some(CompletionsMenuSource::Words {
 5468                ignore_threshold: true,
 5469            }),
 5470            None,
 5471            false,
 5472            window,
 5473            cx,
 5474        );
 5475    }
 5476
 5477    pub fn show_completions(
 5478        &mut self,
 5479        _: &ShowCompletions,
 5480        window: &mut Window,
 5481        cx: &mut Context<Self>,
 5482    ) {
 5483        self.open_or_update_completions_menu(None, None, false, window, cx);
 5484    }
 5485
 5486    fn open_or_update_completions_menu(
 5487        &mut self,
 5488        requested_source: Option<CompletionsMenuSource>,
 5489        trigger: Option<String>,
 5490        trigger_in_words: bool,
 5491        window: &mut Window,
 5492        cx: &mut Context<Self>,
 5493    ) {
 5494        if self.pending_rename.is_some() {
 5495            return;
 5496        }
 5497
 5498        let completions_source = self
 5499            .context_menu
 5500            .borrow()
 5501            .as_ref()
 5502            .and_then(|menu| match menu {
 5503                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5504                CodeContextMenu::CodeActions(_) => None,
 5505            });
 5506
 5507        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5508
 5509        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5510        // inserted and selected. To handle that case, the start of the selection is used so that
 5511        // the menu starts with all choices.
 5512        let position = self
 5513            .selections
 5514            .newest_anchor()
 5515            .start
 5516            .bias_right(&multibuffer_snapshot);
 5517        if position.diff_base_anchor.is_some() {
 5518            return;
 5519        }
 5520        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5521        let Some(buffer) = buffer_position
 5522            .text_anchor
 5523            .buffer_id
 5524            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5525        else {
 5526            return;
 5527        };
 5528        let buffer_snapshot = buffer.read(cx).snapshot();
 5529
 5530        let menu_is_open = matches!(
 5531            self.context_menu.borrow().as_ref(),
 5532            Some(CodeContextMenu::Completions(_))
 5533        );
 5534
 5535        let language = buffer_snapshot
 5536            .language_at(buffer_position.text_anchor)
 5537            .map(|language| language.name());
 5538
 5539        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5540        let completion_settings = language_settings.completions.clone();
 5541
 5542        let show_completions_on_input = self
 5543            .show_completions_on_input_override
 5544            .unwrap_or(language_settings.show_completions_on_input);
 5545        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5546            return;
 5547        }
 5548
 5549        let query: Option<Arc<String>> =
 5550            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5551                .map(|query| query.into());
 5552
 5553        drop(multibuffer_snapshot);
 5554
 5555        // Hide the current completions menu when query is empty. Without this, cached
 5556        // completions from before the trigger char may be reused (#32774).
 5557        if query.is_none() && menu_is_open {
 5558            self.hide_context_menu(window, cx);
 5559        }
 5560
 5561        let mut ignore_word_threshold = false;
 5562        let provider = match requested_source {
 5563            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5564            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5565                ignore_word_threshold = ignore_threshold;
 5566                None
 5567            }
 5568            Some(CompletionsMenuSource::SnippetChoices)
 5569            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5570                log::error!("bug: SnippetChoices requested_source is not handled");
 5571                None
 5572            }
 5573        };
 5574
 5575        let sort_completions = provider
 5576            .as_ref()
 5577            .is_some_and(|provider| provider.sort_completions());
 5578
 5579        let filter_completions = provider
 5580            .as_ref()
 5581            .is_none_or(|provider| provider.filter_completions());
 5582
 5583        let was_snippets_only = matches!(
 5584            completions_source,
 5585            Some(CompletionsMenuSource::SnippetsOnly)
 5586        );
 5587
 5588        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5589            if filter_completions {
 5590                menu.filter(
 5591                    query.clone().unwrap_or_default(),
 5592                    buffer_position.text_anchor,
 5593                    &buffer,
 5594                    provider.clone(),
 5595                    window,
 5596                    cx,
 5597                );
 5598            }
 5599            // When `is_incomplete` is false, no need to re-query completions when the current query
 5600            // is a suffix of the initial query.
 5601            let was_complete = !menu.is_incomplete;
 5602            if was_complete && !was_snippets_only {
 5603                // If the new query is a suffix of the old query (typing more characters) and
 5604                // the previous result was complete, the existing completions can be filtered.
 5605                //
 5606                // Note that snippet completions are always complete.
 5607                let query_matches = match (&menu.initial_query, &query) {
 5608                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5609                    (None, _) => true,
 5610                    _ => false,
 5611                };
 5612                if query_matches {
 5613                    let position_matches = if menu.initial_position == position {
 5614                        true
 5615                    } else {
 5616                        let snapshot = self.buffer.read(cx).read(cx);
 5617                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5618                    };
 5619                    if position_matches {
 5620                        return;
 5621                    }
 5622                }
 5623            }
 5624        };
 5625
 5626        let Anchor {
 5627            excerpt_id: buffer_excerpt_id,
 5628            text_anchor: buffer_position,
 5629            ..
 5630        } = buffer_position;
 5631
 5632        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5633            buffer_snapshot.surrounding_word(buffer_position, None)
 5634        {
 5635            let word_to_exclude = buffer_snapshot
 5636                .text_for_range(word_range.clone())
 5637                .collect::<String>();
 5638            (
 5639                buffer_snapshot.anchor_before(word_range.start)
 5640                    ..buffer_snapshot.anchor_after(buffer_position),
 5641                Some(word_to_exclude),
 5642            )
 5643        } else {
 5644            (buffer_position..buffer_position, None)
 5645        };
 5646
 5647        let show_completion_documentation = buffer_snapshot
 5648            .settings_at(buffer_position, cx)
 5649            .show_completion_documentation;
 5650
 5651        // The document can be large, so stay in reasonable bounds when searching for words,
 5652        // otherwise completion pop-up might be slow to appear.
 5653        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5654        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5655        let min_word_search = buffer_snapshot.clip_point(
 5656            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5657            Bias::Left,
 5658        );
 5659        let max_word_search = buffer_snapshot.clip_point(
 5660            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5661            Bias::Right,
 5662        );
 5663        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5664            ..buffer_snapshot.point_to_offset(max_word_search);
 5665
 5666        let skip_digits = query
 5667            .as_ref()
 5668            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5669
 5670        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5671            trigger.as_ref().is_none_or(|trigger| {
 5672                provider.is_completion_trigger(
 5673                    &buffer,
 5674                    position.text_anchor,
 5675                    trigger,
 5676                    trigger_in_words,
 5677                    cx,
 5678                )
 5679            })
 5680        });
 5681
 5682        let provider_responses = if let Some(provider) = &provider
 5683            && load_provider_completions
 5684        {
 5685            let trigger_character =
 5686                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5687            let completion_context = CompletionContext {
 5688                trigger_kind: match &trigger_character {
 5689                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5690                    None => CompletionTriggerKind::INVOKED,
 5691                },
 5692                trigger_character,
 5693            };
 5694
 5695            provider.completions(
 5696                buffer_excerpt_id,
 5697                &buffer,
 5698                buffer_position,
 5699                completion_context,
 5700                window,
 5701                cx,
 5702            )
 5703        } else {
 5704            Task::ready(Ok(Vec::new()))
 5705        };
 5706
 5707        let load_word_completions = if !self.word_completions_enabled {
 5708            false
 5709        } else if requested_source
 5710            == Some(CompletionsMenuSource::Words {
 5711                ignore_threshold: true,
 5712            })
 5713        {
 5714            true
 5715        } else {
 5716            load_provider_completions
 5717                && completion_settings.words != WordsCompletionMode::Disabled
 5718                && (ignore_word_threshold || {
 5719                    let words_min_length = completion_settings.words_min_length;
 5720                    // check whether word has at least `words_min_length` characters
 5721                    let query_chars = query.iter().flat_map(|q| q.chars());
 5722                    query_chars.take(words_min_length).count() == words_min_length
 5723                })
 5724        };
 5725
 5726        let mut words = if load_word_completions {
 5727            cx.background_spawn({
 5728                let buffer_snapshot = buffer_snapshot.clone();
 5729                async move {
 5730                    buffer_snapshot.words_in_range(WordsQuery {
 5731                        fuzzy_contents: None,
 5732                        range: word_search_range,
 5733                        skip_digits,
 5734                    })
 5735                }
 5736            })
 5737        } else {
 5738            Task::ready(BTreeMap::default())
 5739        };
 5740
 5741        let snippets = if let Some(provider) = &provider
 5742            && provider.show_snippets()
 5743            && let Some(project) = self.project()
 5744        {
 5745            let char_classifier = buffer_snapshot
 5746                .char_classifier_at(buffer_position)
 5747                .scope_context(Some(CharScopeContext::Completion));
 5748            project.update(cx, |project, cx| {
 5749                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5750            })
 5751        } else {
 5752            Task::ready(Ok(CompletionResponse {
 5753                completions: Vec::new(),
 5754                display_options: Default::default(),
 5755                is_incomplete: false,
 5756            }))
 5757        };
 5758
 5759        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5760
 5761        let id = post_inc(&mut self.next_completion_id);
 5762        let task = cx.spawn_in(window, async move |editor, cx| {
 5763            let Ok(()) = editor.update(cx, |this, _| {
 5764                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5765            }) else {
 5766                return;
 5767            };
 5768
 5769            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5770            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5771            let mut completions = Vec::new();
 5772            let mut is_incomplete = false;
 5773            let mut display_options: Option<CompletionDisplayOptions> = None;
 5774            if let Some(provider_responses) = provider_responses.await.log_err()
 5775                && !provider_responses.is_empty()
 5776            {
 5777                for response in provider_responses {
 5778                    completions.extend(response.completions);
 5779                    is_incomplete = is_incomplete || response.is_incomplete;
 5780                    match display_options.as_mut() {
 5781                        None => {
 5782                            display_options = Some(response.display_options);
 5783                        }
 5784                        Some(options) => options.merge(&response.display_options),
 5785                    }
 5786                }
 5787                if completion_settings.words == WordsCompletionMode::Fallback {
 5788                    words = Task::ready(BTreeMap::default());
 5789                }
 5790            }
 5791            let display_options = display_options.unwrap_or_default();
 5792
 5793            let mut words = words.await;
 5794            if let Some(word_to_exclude) = &word_to_exclude {
 5795                words.remove(word_to_exclude);
 5796            }
 5797            for lsp_completion in &completions {
 5798                words.remove(&lsp_completion.new_text);
 5799            }
 5800            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5801                replace_range: word_replace_range.clone(),
 5802                new_text: word.clone(),
 5803                label: CodeLabel::plain(word, None),
 5804                match_start: None,
 5805                snippet_deduplication_key: None,
 5806                icon_path: None,
 5807                documentation: None,
 5808                source: CompletionSource::BufferWord {
 5809                    word_range,
 5810                    resolved: false,
 5811                },
 5812                insert_text_mode: Some(InsertTextMode::AS_IS),
 5813                confirm: None,
 5814            }));
 5815
 5816            completions.extend(
 5817                snippets
 5818                    .await
 5819                    .into_iter()
 5820                    .flat_map(|response| response.completions),
 5821            );
 5822
 5823            let menu = if completions.is_empty() {
 5824                None
 5825            } else {
 5826                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5827                    let languages = editor
 5828                        .workspace
 5829                        .as_ref()
 5830                        .and_then(|(workspace, _)| workspace.upgrade())
 5831                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5832                    let menu = CompletionsMenu::new(
 5833                        id,
 5834                        requested_source.unwrap_or(if load_provider_completions {
 5835                            CompletionsMenuSource::Normal
 5836                        } else {
 5837                            CompletionsMenuSource::SnippetsOnly
 5838                        }),
 5839                        sort_completions,
 5840                        show_completion_documentation,
 5841                        position,
 5842                        query.clone(),
 5843                        is_incomplete,
 5844                        buffer.clone(),
 5845                        completions.into(),
 5846                        display_options,
 5847                        snippet_sort_order,
 5848                        languages,
 5849                        language,
 5850                        cx,
 5851                    );
 5852
 5853                    let query = if filter_completions { query } else { None };
 5854                    let matches_task = menu.do_async_filtering(
 5855                        query.unwrap_or_default(),
 5856                        buffer_position,
 5857                        &buffer,
 5858                        cx,
 5859                    );
 5860                    (menu, matches_task)
 5861                }) else {
 5862                    return;
 5863                };
 5864
 5865                let matches = matches_task.await;
 5866
 5867                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5868                    // Newer menu already set, so exit.
 5869                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5870                        editor.context_menu.borrow().as_ref()
 5871                        && prev_menu.id > id
 5872                    {
 5873                        return;
 5874                    };
 5875
 5876                    // Only valid to take prev_menu because either the new menu is immediately set
 5877                    // below, or the menu is hidden.
 5878                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5879                        editor.context_menu.borrow_mut().take()
 5880                    {
 5881                        let position_matches =
 5882                            if prev_menu.initial_position == menu.initial_position {
 5883                                true
 5884                            } else {
 5885                                let snapshot = editor.buffer.read(cx).read(cx);
 5886                                prev_menu.initial_position.to_offset(&snapshot)
 5887                                    == menu.initial_position.to_offset(&snapshot)
 5888                            };
 5889                        if position_matches {
 5890                            // Preserve markdown cache before `set_filter_results` because it will
 5891                            // try to populate the documentation cache.
 5892                            menu.preserve_markdown_cache(prev_menu);
 5893                        }
 5894                    };
 5895
 5896                    menu.set_filter_results(matches, provider, window, cx);
 5897                }) else {
 5898                    return;
 5899                };
 5900
 5901                menu.visible().then_some(menu)
 5902            };
 5903
 5904            editor
 5905                .update_in(cx, |editor, window, cx| {
 5906                    if editor.focus_handle.is_focused(window)
 5907                        && let Some(menu) = menu
 5908                    {
 5909                        *editor.context_menu.borrow_mut() =
 5910                            Some(CodeContextMenu::Completions(menu));
 5911
 5912                        crate::hover_popover::hide_hover(editor, cx);
 5913                        if editor.show_edit_predictions_in_menu() {
 5914                            editor.update_visible_edit_prediction(window, cx);
 5915                        } else {
 5916                            editor.discard_edit_prediction(false, cx);
 5917                        }
 5918
 5919                        cx.notify();
 5920                        return;
 5921                    }
 5922
 5923                    if editor.completion_tasks.len() <= 1 {
 5924                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5925                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5926                        // If it was already hidden and we don't show edit predictions in the menu,
 5927                        // we should also show the edit prediction when available.
 5928                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5929                            editor.update_visible_edit_prediction(window, cx);
 5930                        }
 5931                    }
 5932                })
 5933                .ok();
 5934        });
 5935
 5936        self.completion_tasks.push((id, task));
 5937    }
 5938
 5939    #[cfg(feature = "test-support")]
 5940    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5941        let menu = self.context_menu.borrow();
 5942        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5943            let completions = menu.completions.borrow();
 5944            Some(completions.to_vec())
 5945        } else {
 5946            None
 5947        }
 5948    }
 5949
 5950    pub fn with_completions_menu_matching_id<R>(
 5951        &self,
 5952        id: CompletionId,
 5953        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5954    ) -> R {
 5955        let mut context_menu = self.context_menu.borrow_mut();
 5956        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5957            return f(None);
 5958        };
 5959        if completions_menu.id != id {
 5960            return f(None);
 5961        }
 5962        f(Some(completions_menu))
 5963    }
 5964
 5965    pub fn confirm_completion(
 5966        &mut self,
 5967        action: &ConfirmCompletion,
 5968        window: &mut Window,
 5969        cx: &mut Context<Self>,
 5970    ) -> Option<Task<Result<()>>> {
 5971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5972        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5973    }
 5974
 5975    pub fn confirm_completion_insert(
 5976        &mut self,
 5977        _: &ConfirmCompletionInsert,
 5978        window: &mut Window,
 5979        cx: &mut Context<Self>,
 5980    ) -> Option<Task<Result<()>>> {
 5981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5982        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5983    }
 5984
 5985    pub fn confirm_completion_replace(
 5986        &mut self,
 5987        _: &ConfirmCompletionReplace,
 5988        window: &mut Window,
 5989        cx: &mut Context<Self>,
 5990    ) -> Option<Task<Result<()>>> {
 5991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5992        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5993    }
 5994
 5995    pub fn compose_completion(
 5996        &mut self,
 5997        action: &ComposeCompletion,
 5998        window: &mut Window,
 5999        cx: &mut Context<Self>,
 6000    ) -> Option<Task<Result<()>>> {
 6001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6002        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6003    }
 6004
 6005    fn do_completion(
 6006        &mut self,
 6007        item_ix: Option<usize>,
 6008        intent: CompletionIntent,
 6009        window: &mut Window,
 6010        cx: &mut Context<Editor>,
 6011    ) -> Option<Task<Result<()>>> {
 6012        use language::ToOffset as _;
 6013
 6014        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6015        else {
 6016            return None;
 6017        };
 6018
 6019        let candidate_id = {
 6020            let entries = completions_menu.entries.borrow();
 6021            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6022            if self.show_edit_predictions_in_menu() {
 6023                self.discard_edit_prediction(true, cx);
 6024            }
 6025            mat.candidate_id
 6026        };
 6027
 6028        let completion = completions_menu
 6029            .completions
 6030            .borrow()
 6031            .get(candidate_id)?
 6032            .clone();
 6033        cx.stop_propagation();
 6034
 6035        let buffer_handle = completions_menu.buffer.clone();
 6036
 6037        let CompletionEdit {
 6038            new_text,
 6039            snippet,
 6040            replace_range,
 6041        } = process_completion_for_edit(
 6042            &completion,
 6043            intent,
 6044            &buffer_handle,
 6045            &completions_menu.initial_position.text_anchor,
 6046            cx,
 6047        );
 6048
 6049        let buffer = buffer_handle.read(cx);
 6050        let snapshot = self.buffer.read(cx).snapshot(cx);
 6051        let newest_anchor = self.selections.newest_anchor();
 6052        let replace_range_multibuffer = {
 6053            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6054            excerpt.map_range_from_buffer(replace_range.clone())
 6055        };
 6056        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6057            return None;
 6058        }
 6059
 6060        let old_text = buffer
 6061            .text_for_range(replace_range.clone())
 6062            .collect::<String>();
 6063        let lookbehind = newest_anchor
 6064            .start
 6065            .text_anchor
 6066            .to_offset(buffer)
 6067            .saturating_sub(replace_range.start.0);
 6068        let lookahead = replace_range
 6069            .end
 6070            .0
 6071            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6072        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6073        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6074
 6075        let selections = self
 6076            .selections
 6077            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6078        let mut ranges = Vec::new();
 6079        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6080
 6081        for selection in &selections {
 6082            let range = if selection.id == newest_anchor.id {
 6083                replace_range_multibuffer.clone()
 6084            } else {
 6085                let mut range = selection.range();
 6086
 6087                // if prefix is present, don't duplicate it
 6088                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6089                    range.start = range.start.saturating_sub_usize(lookbehind);
 6090
 6091                    // if suffix is also present, mimic the newest cursor and replace it
 6092                    if selection.id != newest_anchor.id
 6093                        && snapshot.contains_str_at(range.end, suffix)
 6094                    {
 6095                        range.end += lookahead;
 6096                    }
 6097                }
 6098                range
 6099            };
 6100
 6101            ranges.push(range.clone());
 6102
 6103            if !self.linked_edit_ranges.is_empty() {
 6104                let start_anchor = snapshot.anchor_before(range.start);
 6105                let end_anchor = snapshot.anchor_after(range.end);
 6106                if let Some(ranges) = self
 6107                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6108                {
 6109                    for (buffer, edits) in ranges {
 6110                        linked_edits
 6111                            .entry(buffer.clone())
 6112                            .or_default()
 6113                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6114                    }
 6115                }
 6116            }
 6117        }
 6118
 6119        let common_prefix_len = old_text
 6120            .chars()
 6121            .zip(new_text.chars())
 6122            .take_while(|(a, b)| a == b)
 6123            .map(|(a, _)| a.len_utf8())
 6124            .sum::<usize>();
 6125
 6126        cx.emit(EditorEvent::InputHandled {
 6127            utf16_range_to_replace: None,
 6128            text: new_text[common_prefix_len..].into(),
 6129        });
 6130
 6131        self.transact(window, cx, |editor, window, cx| {
 6132            if let Some(mut snippet) = snippet {
 6133                snippet.text = new_text.to_string();
 6134                editor
 6135                    .insert_snippet(&ranges, snippet, window, cx)
 6136                    .log_err();
 6137            } else {
 6138                editor.buffer.update(cx, |multi_buffer, cx| {
 6139                    let auto_indent = match completion.insert_text_mode {
 6140                        Some(InsertTextMode::AS_IS) => None,
 6141                        _ => editor.autoindent_mode.clone(),
 6142                    };
 6143                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6144                    multi_buffer.edit(edits, auto_indent, cx);
 6145                });
 6146            }
 6147            for (buffer, edits) in linked_edits {
 6148                buffer.update(cx, |buffer, cx| {
 6149                    let snapshot = buffer.snapshot();
 6150                    let edits = edits
 6151                        .into_iter()
 6152                        .map(|(range, text)| {
 6153                            use text::ToPoint as TP;
 6154                            let end_point = TP::to_point(&range.end, &snapshot);
 6155                            let start_point = TP::to_point(&range.start, &snapshot);
 6156                            (start_point..end_point, text)
 6157                        })
 6158                        .sorted_by_key(|(range, _)| range.start);
 6159                    buffer.edit(edits, None, cx);
 6160                })
 6161            }
 6162
 6163            editor.refresh_edit_prediction(true, false, window, cx);
 6164        });
 6165        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6166
 6167        let show_new_completions_on_confirm = completion
 6168            .confirm
 6169            .as_ref()
 6170            .is_some_and(|confirm| confirm(intent, window, cx));
 6171        if show_new_completions_on_confirm {
 6172            self.open_or_update_completions_menu(None, None, false, window, cx);
 6173        }
 6174
 6175        let provider = self.completion_provider.as_ref()?;
 6176
 6177        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6178        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6179            let CompletionSource::Lsp {
 6180                lsp_completion,
 6181                server_id,
 6182                ..
 6183            } = &completion.source
 6184            else {
 6185                return None;
 6186            };
 6187            let lsp_command = lsp_completion.command.as_ref()?;
 6188            let available_commands = lsp_store
 6189                .read(cx)
 6190                .lsp_server_capabilities
 6191                .get(server_id)
 6192                .and_then(|server_capabilities| {
 6193                    server_capabilities
 6194                        .execute_command_provider
 6195                        .as_ref()
 6196                        .map(|options| options.commands.as_slice())
 6197                })?;
 6198            if available_commands.contains(&lsp_command.command) {
 6199                Some(CodeAction {
 6200                    server_id: *server_id,
 6201                    range: language::Anchor::MIN..language::Anchor::MIN,
 6202                    lsp_action: LspAction::Command(lsp_command.clone()),
 6203                    resolved: false,
 6204                })
 6205            } else {
 6206                None
 6207            }
 6208        });
 6209
 6210        drop(completion);
 6211        let apply_edits = provider.apply_additional_edits_for_completion(
 6212            buffer_handle.clone(),
 6213            completions_menu.completions.clone(),
 6214            candidate_id,
 6215            true,
 6216            cx,
 6217        );
 6218
 6219        let editor_settings = EditorSettings::get_global(cx);
 6220        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6221            // After the code completion is finished, users often want to know what signatures are needed.
 6222            // so we should automatically call signature_help
 6223            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6224        }
 6225
 6226        Some(cx.spawn_in(window, async move |editor, cx| {
 6227            apply_edits.await?;
 6228
 6229            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6230                let title = command.lsp_action.title().to_owned();
 6231                let project_transaction = lsp_store
 6232                    .update(cx, |lsp_store, cx| {
 6233                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6234                    })?
 6235                    .await
 6236                    .context("applying post-completion command")?;
 6237                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6238                    Self::open_project_transaction(
 6239                        &editor,
 6240                        workspace.downgrade(),
 6241                        project_transaction,
 6242                        title,
 6243                        cx,
 6244                    )
 6245                    .await?;
 6246                }
 6247            }
 6248
 6249            Ok(())
 6250        }))
 6251    }
 6252
 6253    pub fn toggle_code_actions(
 6254        &mut self,
 6255        action: &ToggleCodeActions,
 6256        window: &mut Window,
 6257        cx: &mut Context<Self>,
 6258    ) {
 6259        let quick_launch = action.quick_launch;
 6260        let mut context_menu = self.context_menu.borrow_mut();
 6261        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6262            if code_actions.deployed_from == action.deployed_from {
 6263                // Toggle if we're selecting the same one
 6264                *context_menu = None;
 6265                cx.notify();
 6266                return;
 6267            } else {
 6268                // Otherwise, clear it and start a new one
 6269                *context_menu = None;
 6270                cx.notify();
 6271            }
 6272        }
 6273        drop(context_menu);
 6274        let snapshot = self.snapshot(window, cx);
 6275        let deployed_from = action.deployed_from.clone();
 6276        let action = action.clone();
 6277        self.completion_tasks.clear();
 6278        self.discard_edit_prediction(false, cx);
 6279
 6280        let multibuffer_point = match &action.deployed_from {
 6281            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6282                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6283            }
 6284            _ => self
 6285                .selections
 6286                .newest::<Point>(&snapshot.display_snapshot)
 6287                .head(),
 6288        };
 6289        let Some((buffer, buffer_row)) = snapshot
 6290            .buffer_snapshot()
 6291            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6292            .and_then(|(buffer_snapshot, range)| {
 6293                self.buffer()
 6294                    .read(cx)
 6295                    .buffer(buffer_snapshot.remote_id())
 6296                    .map(|buffer| (buffer, range.start.row))
 6297            })
 6298        else {
 6299            return;
 6300        };
 6301        let buffer_id = buffer.read(cx).remote_id();
 6302        let tasks = self
 6303            .tasks
 6304            .get(&(buffer_id, buffer_row))
 6305            .map(|t| Arc::new(t.to_owned()));
 6306
 6307        if !self.focus_handle.is_focused(window) {
 6308            return;
 6309        }
 6310        let project = self.project.clone();
 6311
 6312        let code_actions_task = match deployed_from {
 6313            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6314            _ => self.code_actions(buffer_row, window, cx),
 6315        };
 6316
 6317        let runnable_task = match deployed_from {
 6318            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6319            _ => {
 6320                let mut task_context_task = Task::ready(None);
 6321                if let Some(tasks) = &tasks
 6322                    && let Some(project) = project
 6323                {
 6324                    task_context_task =
 6325                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6326                }
 6327
 6328                cx.spawn_in(window, {
 6329                    let buffer = buffer.clone();
 6330                    async move |editor, cx| {
 6331                        let task_context = task_context_task.await;
 6332
 6333                        let resolved_tasks =
 6334                            tasks
 6335                                .zip(task_context.clone())
 6336                                .map(|(tasks, task_context)| ResolvedTasks {
 6337                                    templates: tasks.resolve(&task_context).collect(),
 6338                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6339                                        multibuffer_point.row,
 6340                                        tasks.column,
 6341                                    )),
 6342                                });
 6343                        let debug_scenarios = editor
 6344                            .update(cx, |editor, cx| {
 6345                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6346                            })?
 6347                            .await;
 6348                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6349                    }
 6350                })
 6351            }
 6352        };
 6353
 6354        cx.spawn_in(window, async move |editor, cx| {
 6355            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6356            let code_actions = code_actions_task.await;
 6357            let spawn_straight_away = quick_launch
 6358                && resolved_tasks
 6359                    .as_ref()
 6360                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6361                && code_actions
 6362                    .as_ref()
 6363                    .is_none_or(|actions| actions.is_empty())
 6364                && debug_scenarios.is_empty();
 6365
 6366            editor.update_in(cx, |editor, window, cx| {
 6367                crate::hover_popover::hide_hover(editor, cx);
 6368                let actions = CodeActionContents::new(
 6369                    resolved_tasks,
 6370                    code_actions,
 6371                    debug_scenarios,
 6372                    task_context.unwrap_or_default(),
 6373                );
 6374
 6375                // Don't show the menu if there are no actions available
 6376                if actions.is_empty() {
 6377                    cx.notify();
 6378                    return Task::ready(Ok(()));
 6379                }
 6380
 6381                *editor.context_menu.borrow_mut() =
 6382                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6383                        buffer,
 6384                        actions,
 6385                        selected_item: Default::default(),
 6386                        scroll_handle: UniformListScrollHandle::default(),
 6387                        deployed_from,
 6388                    }));
 6389                cx.notify();
 6390                if spawn_straight_away
 6391                    && let Some(task) = editor.confirm_code_action(
 6392                        &ConfirmCodeAction { item_ix: Some(0) },
 6393                        window,
 6394                        cx,
 6395                    )
 6396                {
 6397                    return task;
 6398                }
 6399
 6400                Task::ready(Ok(()))
 6401            })
 6402        })
 6403        .detach_and_log_err(cx);
 6404    }
 6405
 6406    fn debug_scenarios(
 6407        &mut self,
 6408        resolved_tasks: &Option<ResolvedTasks>,
 6409        buffer: &Entity<Buffer>,
 6410        cx: &mut App,
 6411    ) -> Task<Vec<task::DebugScenario>> {
 6412        maybe!({
 6413            let project = self.project()?;
 6414            let dap_store = project.read(cx).dap_store();
 6415            let mut scenarios = vec![];
 6416            let resolved_tasks = resolved_tasks.as_ref()?;
 6417            let buffer = buffer.read(cx);
 6418            let language = buffer.language()?;
 6419            let file = buffer.file();
 6420            let debug_adapter = language_settings(language.name().into(), file, cx)
 6421                .debuggers
 6422                .first()
 6423                .map(SharedString::from)
 6424                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6425
 6426            dap_store.update(cx, |dap_store, cx| {
 6427                for (_, task) in &resolved_tasks.templates {
 6428                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6429                        task.original_task().clone(),
 6430                        debug_adapter.clone().into(),
 6431                        task.display_label().to_owned().into(),
 6432                        cx,
 6433                    );
 6434                    scenarios.push(maybe_scenario);
 6435                }
 6436            });
 6437            Some(cx.background_spawn(async move {
 6438                futures::future::join_all(scenarios)
 6439                    .await
 6440                    .into_iter()
 6441                    .flatten()
 6442                    .collect::<Vec<_>>()
 6443            }))
 6444        })
 6445        .unwrap_or_else(|| Task::ready(vec![]))
 6446    }
 6447
 6448    fn code_actions(
 6449        &mut self,
 6450        buffer_row: u32,
 6451        window: &mut Window,
 6452        cx: &mut Context<Self>,
 6453    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6454        let mut task = self.code_actions_task.take();
 6455        cx.spawn_in(window, async move |editor, cx| {
 6456            while let Some(prev_task) = task {
 6457                prev_task.await.log_err();
 6458                task = editor
 6459                    .update(cx, |this, _| this.code_actions_task.take())
 6460                    .ok()?;
 6461            }
 6462
 6463            editor
 6464                .update(cx, |editor, cx| {
 6465                    editor
 6466                        .available_code_actions
 6467                        .clone()
 6468                        .and_then(|(location, code_actions)| {
 6469                            let snapshot = location.buffer.read(cx).snapshot();
 6470                            let point_range = location.range.to_point(&snapshot);
 6471                            let point_range = point_range.start.row..=point_range.end.row;
 6472                            if point_range.contains(&buffer_row) {
 6473                                Some(code_actions)
 6474                            } else {
 6475                                None
 6476                            }
 6477                        })
 6478                })
 6479                .ok()
 6480                .flatten()
 6481        })
 6482    }
 6483
 6484    pub fn confirm_code_action(
 6485        &mut self,
 6486        action: &ConfirmCodeAction,
 6487        window: &mut Window,
 6488        cx: &mut Context<Self>,
 6489    ) -> Option<Task<Result<()>>> {
 6490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6491
 6492        let actions_menu =
 6493            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6494                menu
 6495            } else {
 6496                return None;
 6497            };
 6498
 6499        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6500        let action = actions_menu.actions.get(action_ix)?;
 6501        let title = action.label();
 6502        let buffer = actions_menu.buffer;
 6503        let workspace = self.workspace()?;
 6504
 6505        match action {
 6506            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6507                workspace.update(cx, |workspace, cx| {
 6508                    workspace.schedule_resolved_task(
 6509                        task_source_kind,
 6510                        resolved_task,
 6511                        false,
 6512                        window,
 6513                        cx,
 6514                    );
 6515
 6516                    Some(Task::ready(Ok(())))
 6517                })
 6518            }
 6519            CodeActionsItem::CodeAction {
 6520                excerpt_id,
 6521                action,
 6522                provider,
 6523            } => {
 6524                let apply_code_action =
 6525                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6526                let workspace = workspace.downgrade();
 6527                Some(cx.spawn_in(window, async move |editor, cx| {
 6528                    let project_transaction = apply_code_action.await?;
 6529                    Self::open_project_transaction(
 6530                        &editor,
 6531                        workspace,
 6532                        project_transaction,
 6533                        title,
 6534                        cx,
 6535                    )
 6536                    .await
 6537                }))
 6538            }
 6539            CodeActionsItem::DebugScenario(scenario) => {
 6540                let context = actions_menu.actions.context;
 6541
 6542                workspace.update(cx, |workspace, cx| {
 6543                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6544                    workspace.start_debug_session(
 6545                        scenario,
 6546                        context,
 6547                        Some(buffer),
 6548                        None,
 6549                        window,
 6550                        cx,
 6551                    );
 6552                });
 6553                Some(Task::ready(Ok(())))
 6554            }
 6555        }
 6556    }
 6557
 6558    pub async fn open_project_transaction(
 6559        editor: &WeakEntity<Editor>,
 6560        workspace: WeakEntity<Workspace>,
 6561        transaction: ProjectTransaction,
 6562        title: String,
 6563        cx: &mut AsyncWindowContext,
 6564    ) -> Result<()> {
 6565        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6566        cx.update(|_, cx| {
 6567            entries.sort_unstable_by_key(|(buffer, _)| {
 6568                buffer.read(cx).file().map(|f| f.path().clone())
 6569            });
 6570        })?;
 6571        if entries.is_empty() {
 6572            return Ok(());
 6573        }
 6574
 6575        // If the project transaction's edits are all contained within this editor, then
 6576        // avoid opening a new editor to display them.
 6577
 6578        if let [(buffer, transaction)] = &*entries {
 6579            let excerpt = editor.update(cx, |editor, cx| {
 6580                editor
 6581                    .buffer()
 6582                    .read(cx)
 6583                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6584            })?;
 6585            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6586                && excerpted_buffer == *buffer
 6587            {
 6588                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6589                    let excerpt_range = excerpt_range.to_offset(buffer);
 6590                    buffer
 6591                        .edited_ranges_for_transaction::<usize>(transaction)
 6592                        .all(|range| {
 6593                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6594                        })
 6595                })?;
 6596
 6597                if all_edits_within_excerpt {
 6598                    return Ok(());
 6599                }
 6600            }
 6601        }
 6602
 6603        let mut ranges_to_highlight = Vec::new();
 6604        let excerpt_buffer = cx.new(|cx| {
 6605            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6606            for (buffer_handle, transaction) in &entries {
 6607                let edited_ranges = buffer_handle
 6608                    .read(cx)
 6609                    .edited_ranges_for_transaction::<Point>(transaction)
 6610                    .collect::<Vec<_>>();
 6611                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6612                    PathKey::for_buffer(buffer_handle, cx),
 6613                    buffer_handle.clone(),
 6614                    edited_ranges,
 6615                    multibuffer_context_lines(cx),
 6616                    cx,
 6617                );
 6618
 6619                ranges_to_highlight.extend(ranges);
 6620            }
 6621            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6622            multibuffer
 6623        })?;
 6624
 6625        workspace.update_in(cx, |workspace, window, cx| {
 6626            let project = workspace.project().clone();
 6627            let editor =
 6628                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6629            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6630            editor.update(cx, |editor, cx| {
 6631                editor.highlight_background::<Self>(
 6632                    &ranges_to_highlight,
 6633                    |_, theme| theme.colors().editor_highlighted_line_background,
 6634                    cx,
 6635                );
 6636            });
 6637        })?;
 6638
 6639        Ok(())
 6640    }
 6641
 6642    pub fn clear_code_action_providers(&mut self) {
 6643        self.code_action_providers.clear();
 6644        self.available_code_actions.take();
 6645    }
 6646
 6647    pub fn add_code_action_provider(
 6648        &mut self,
 6649        provider: Rc<dyn CodeActionProvider>,
 6650        window: &mut Window,
 6651        cx: &mut Context<Self>,
 6652    ) {
 6653        if self
 6654            .code_action_providers
 6655            .iter()
 6656            .any(|existing_provider| existing_provider.id() == provider.id())
 6657        {
 6658            return;
 6659        }
 6660
 6661        self.code_action_providers.push(provider);
 6662        self.refresh_code_actions(window, cx);
 6663    }
 6664
 6665    pub fn remove_code_action_provider(
 6666        &mut self,
 6667        id: Arc<str>,
 6668        window: &mut Window,
 6669        cx: &mut Context<Self>,
 6670    ) {
 6671        self.code_action_providers
 6672            .retain(|provider| provider.id() != id);
 6673        self.refresh_code_actions(window, cx);
 6674    }
 6675
 6676    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6677        !self.code_action_providers.is_empty()
 6678            && EditorSettings::get_global(cx).toolbar.code_actions
 6679    }
 6680
 6681    pub fn has_available_code_actions(&self) -> bool {
 6682        self.available_code_actions
 6683            .as_ref()
 6684            .is_some_and(|(_, actions)| !actions.is_empty())
 6685    }
 6686
 6687    fn render_inline_code_actions(
 6688        &self,
 6689        icon_size: ui::IconSize,
 6690        display_row: DisplayRow,
 6691        is_active: bool,
 6692        cx: &mut Context<Self>,
 6693    ) -> AnyElement {
 6694        let show_tooltip = !self.context_menu_visible();
 6695        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6696            .icon_size(icon_size)
 6697            .shape(ui::IconButtonShape::Square)
 6698            .icon_color(ui::Color::Hidden)
 6699            .toggle_state(is_active)
 6700            .when(show_tooltip, |this| {
 6701                this.tooltip({
 6702                    let focus_handle = self.focus_handle.clone();
 6703                    move |_window, cx| {
 6704                        Tooltip::for_action_in(
 6705                            "Toggle Code Actions",
 6706                            &ToggleCodeActions {
 6707                                deployed_from: None,
 6708                                quick_launch: false,
 6709                            },
 6710                            &focus_handle,
 6711                            cx,
 6712                        )
 6713                    }
 6714                })
 6715            })
 6716            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6717                window.focus(&editor.focus_handle(cx));
 6718                editor.toggle_code_actions(
 6719                    &crate::actions::ToggleCodeActions {
 6720                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6721                            display_row,
 6722                        )),
 6723                        quick_launch: false,
 6724                    },
 6725                    window,
 6726                    cx,
 6727                );
 6728            }))
 6729            .into_any_element()
 6730    }
 6731
 6732    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6733        &self.context_menu
 6734    }
 6735
 6736    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6737        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6738            cx.background_executor()
 6739                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6740                .await;
 6741
 6742            let (start_buffer, start, _, end, newest_selection) = this
 6743                .update(cx, |this, cx| {
 6744                    let newest_selection = this.selections.newest_anchor().clone();
 6745                    if newest_selection.head().diff_base_anchor.is_some() {
 6746                        return None;
 6747                    }
 6748                    let display_snapshot = this.display_snapshot(cx);
 6749                    let newest_selection_adjusted =
 6750                        this.selections.newest_adjusted(&display_snapshot);
 6751                    let buffer = this.buffer.read(cx);
 6752
 6753                    let (start_buffer, start) =
 6754                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6755                    let (end_buffer, end) =
 6756                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6757
 6758                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6759                })?
 6760                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6761                .context(
 6762                    "Expected selection to lie in a single buffer when refreshing code actions",
 6763                )?;
 6764            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6765                let providers = this.code_action_providers.clone();
 6766                let tasks = this
 6767                    .code_action_providers
 6768                    .iter()
 6769                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6770                    .collect::<Vec<_>>();
 6771                (providers, tasks)
 6772            })?;
 6773
 6774            let mut actions = Vec::new();
 6775            for (provider, provider_actions) in
 6776                providers.into_iter().zip(future::join_all(tasks).await)
 6777            {
 6778                if let Some(provider_actions) = provider_actions.log_err() {
 6779                    actions.extend(provider_actions.into_iter().map(|action| {
 6780                        AvailableCodeAction {
 6781                            excerpt_id: newest_selection.start.excerpt_id,
 6782                            action,
 6783                            provider: provider.clone(),
 6784                        }
 6785                    }));
 6786                }
 6787            }
 6788
 6789            this.update(cx, |this, cx| {
 6790                this.available_code_actions = if actions.is_empty() {
 6791                    None
 6792                } else {
 6793                    Some((
 6794                        Location {
 6795                            buffer: start_buffer,
 6796                            range: start..end,
 6797                        },
 6798                        actions.into(),
 6799                    ))
 6800                };
 6801                cx.notify();
 6802            })
 6803        }));
 6804    }
 6805
 6806    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6807        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6808            self.show_git_blame_inline = false;
 6809
 6810            self.show_git_blame_inline_delay_task =
 6811                Some(cx.spawn_in(window, async move |this, cx| {
 6812                    cx.background_executor().timer(delay).await;
 6813
 6814                    this.update(cx, |this, cx| {
 6815                        this.show_git_blame_inline = true;
 6816                        cx.notify();
 6817                    })
 6818                    .log_err();
 6819                }));
 6820        }
 6821    }
 6822
 6823    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6824        let snapshot = self.snapshot(window, cx);
 6825        let cursor = self
 6826            .selections
 6827            .newest::<Point>(&snapshot.display_snapshot)
 6828            .head();
 6829        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6830        else {
 6831            return;
 6832        };
 6833
 6834        if self.blame.is_none() {
 6835            self.start_git_blame(true, window, cx);
 6836        }
 6837        let Some(blame) = self.blame.as_ref() else {
 6838            return;
 6839        };
 6840
 6841        let row_info = RowInfo {
 6842            buffer_id: Some(buffer.remote_id()),
 6843            buffer_row: Some(point.row),
 6844            ..Default::default()
 6845        };
 6846        let Some((buffer, blame_entry)) = blame
 6847            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6848            .flatten()
 6849        else {
 6850            return;
 6851        };
 6852
 6853        let anchor = self.selections.newest_anchor().head();
 6854        let position = self.to_pixel_point(anchor, &snapshot, window);
 6855        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6856            self.show_blame_popover(
 6857                buffer,
 6858                &blame_entry,
 6859                position + last_bounds.origin,
 6860                true,
 6861                cx,
 6862            );
 6863        };
 6864    }
 6865
 6866    fn show_blame_popover(
 6867        &mut self,
 6868        buffer: BufferId,
 6869        blame_entry: &BlameEntry,
 6870        position: gpui::Point<Pixels>,
 6871        ignore_timeout: bool,
 6872        cx: &mut Context<Self>,
 6873    ) {
 6874        if let Some(state) = &mut self.inline_blame_popover {
 6875            state.hide_task.take();
 6876        } else {
 6877            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6878            let blame_entry = blame_entry.clone();
 6879            let show_task = cx.spawn(async move |editor, cx| {
 6880                if !ignore_timeout {
 6881                    cx.background_executor()
 6882                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6883                        .await;
 6884                }
 6885                editor
 6886                    .update(cx, |editor, cx| {
 6887                        editor.inline_blame_popover_show_task.take();
 6888                        let Some(blame) = editor.blame.as_ref() else {
 6889                            return;
 6890                        };
 6891                        let blame = blame.read(cx);
 6892                        let details = blame.details_for_entry(buffer, &blame_entry);
 6893                        let markdown = cx.new(|cx| {
 6894                            Markdown::new(
 6895                                details
 6896                                    .as_ref()
 6897                                    .map(|message| message.message.clone())
 6898                                    .unwrap_or_default(),
 6899                                None,
 6900                                None,
 6901                                cx,
 6902                            )
 6903                        });
 6904                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6905                            position,
 6906                            hide_task: None,
 6907                            popover_bounds: None,
 6908                            popover_state: InlineBlamePopoverState {
 6909                                scroll_handle: ScrollHandle::new(),
 6910                                commit_message: details,
 6911                                markdown,
 6912                            },
 6913                            keyboard_grace: ignore_timeout,
 6914                        });
 6915                        cx.notify();
 6916                    })
 6917                    .ok();
 6918            });
 6919            self.inline_blame_popover_show_task = Some(show_task);
 6920        }
 6921    }
 6922
 6923    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6924        self.inline_blame_popover_show_task.take();
 6925        if let Some(state) = &mut self.inline_blame_popover {
 6926            let hide_task = cx.spawn(async move |editor, cx| {
 6927                if !ignore_timeout {
 6928                    cx.background_executor()
 6929                        .timer(std::time::Duration::from_millis(100))
 6930                        .await;
 6931                }
 6932                editor
 6933                    .update(cx, |editor, cx| {
 6934                        editor.inline_blame_popover.take();
 6935                        cx.notify();
 6936                    })
 6937                    .ok();
 6938            });
 6939            state.hide_task = Some(hide_task);
 6940            true
 6941        } else {
 6942            false
 6943        }
 6944    }
 6945
 6946    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6947        if self.pending_rename.is_some() {
 6948            return None;
 6949        }
 6950
 6951        let provider = self.semantics_provider.clone()?;
 6952        let buffer = self.buffer.read(cx);
 6953        let newest_selection = self.selections.newest_anchor().clone();
 6954        let cursor_position = newest_selection.head();
 6955        let (cursor_buffer, cursor_buffer_position) =
 6956            buffer.text_anchor_for_position(cursor_position, cx)?;
 6957        let (tail_buffer, tail_buffer_position) =
 6958            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6959        if cursor_buffer != tail_buffer {
 6960            return None;
 6961        }
 6962
 6963        let snapshot = cursor_buffer.read(cx).snapshot();
 6964        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6965        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6966        if start_word_range != end_word_range {
 6967            self.document_highlights_task.take();
 6968            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6969            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6970            return None;
 6971        }
 6972
 6973        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6974        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6975            cx.background_executor()
 6976                .timer(Duration::from_millis(debounce))
 6977                .await;
 6978
 6979            let highlights = if let Some(highlights) = cx
 6980                .update(|cx| {
 6981                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6982                })
 6983                .ok()
 6984                .flatten()
 6985            {
 6986                highlights.await.log_err()
 6987            } else {
 6988                None
 6989            };
 6990
 6991            if let Some(highlights) = highlights {
 6992                this.update(cx, |this, cx| {
 6993                    if this.pending_rename.is_some() {
 6994                        return;
 6995                    }
 6996
 6997                    let buffer = this.buffer.read(cx);
 6998                    if buffer
 6999                        .text_anchor_for_position(cursor_position, cx)
 7000                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7001                    {
 7002                        return;
 7003                    }
 7004
 7005                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7006                    let mut write_ranges = Vec::new();
 7007                    let mut read_ranges = Vec::new();
 7008                    for highlight in highlights {
 7009                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7010                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7011                        {
 7012                            let start = highlight
 7013                                .range
 7014                                .start
 7015                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7016                            let end = highlight
 7017                                .range
 7018                                .end
 7019                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7020                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7021                                continue;
 7022                            }
 7023
 7024                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7025                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7026                                write_ranges.push(range);
 7027                            } else {
 7028                                read_ranges.push(range);
 7029                            }
 7030                        }
 7031                    }
 7032
 7033                    this.highlight_background::<DocumentHighlightRead>(
 7034                        &read_ranges,
 7035                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7036                        cx,
 7037                    );
 7038                    this.highlight_background::<DocumentHighlightWrite>(
 7039                        &write_ranges,
 7040                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7041                        cx,
 7042                    );
 7043                    cx.notify();
 7044                })
 7045                .log_err();
 7046            }
 7047        }));
 7048        None
 7049    }
 7050
 7051    fn prepare_highlight_query_from_selection(
 7052        &mut self,
 7053        window: &Window,
 7054        cx: &mut Context<Editor>,
 7055    ) -> Option<(String, Range<Anchor>)> {
 7056        if matches!(self.mode, EditorMode::SingleLine) {
 7057            return None;
 7058        }
 7059        if !EditorSettings::get_global(cx).selection_highlight {
 7060            return None;
 7061        }
 7062        if self.selections.count() != 1 || self.selections.line_mode() {
 7063            return None;
 7064        }
 7065        let snapshot = self.snapshot(window, cx);
 7066        let selection = self.selections.newest::<Point>(&snapshot);
 7067        // If the selection spans multiple rows OR it is empty
 7068        if selection.start.row != selection.end.row
 7069            || selection.start.column == selection.end.column
 7070        {
 7071            return None;
 7072        }
 7073        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7074        let query = snapshot
 7075            .buffer_snapshot()
 7076            .text_for_range(selection_anchor_range.clone())
 7077            .collect::<String>();
 7078        if query.trim().is_empty() {
 7079            return None;
 7080        }
 7081        Some((query, selection_anchor_range))
 7082    }
 7083
 7084    fn update_selection_occurrence_highlights(
 7085        &mut self,
 7086        query_text: String,
 7087        query_range: Range<Anchor>,
 7088        multi_buffer_range_to_query: Range<Point>,
 7089        use_debounce: bool,
 7090        window: &mut Window,
 7091        cx: &mut Context<Editor>,
 7092    ) -> Task<()> {
 7093        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7094        cx.spawn_in(window, async move |editor, cx| {
 7095            if use_debounce {
 7096                cx.background_executor()
 7097                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7098                    .await;
 7099            }
 7100            let match_task = cx.background_spawn(async move {
 7101                let buffer_ranges = multi_buffer_snapshot
 7102                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7103                    .into_iter()
 7104                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7105                let mut match_ranges = Vec::new();
 7106                let Ok(regex) = project::search::SearchQuery::text(
 7107                    query_text.clone(),
 7108                    false,
 7109                    false,
 7110                    false,
 7111                    Default::default(),
 7112                    Default::default(),
 7113                    false,
 7114                    None,
 7115                ) else {
 7116                    return Vec::default();
 7117                };
 7118                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7119                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7120                    match_ranges.extend(
 7121                        regex
 7122                            .search(
 7123                                buffer_snapshot,
 7124                                Some(search_range.start.0..search_range.end.0),
 7125                            )
 7126                            .await
 7127                            .into_iter()
 7128                            .filter_map(|match_range| {
 7129                                let match_start = buffer_snapshot
 7130                                    .anchor_after(search_range.start + match_range.start);
 7131                                let match_end = buffer_snapshot
 7132                                    .anchor_before(search_range.start + match_range.end);
 7133                                let match_anchor_range =
 7134                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7135                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7136                            }),
 7137                    );
 7138                }
 7139                match_ranges
 7140            });
 7141            let match_ranges = match_task.await;
 7142            editor
 7143                .update_in(cx, |editor, _, cx| {
 7144                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7145                    if !match_ranges.is_empty() {
 7146                        editor.highlight_background::<SelectedTextHighlight>(
 7147                            &match_ranges,
 7148                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7149                            cx,
 7150                        )
 7151                    }
 7152                })
 7153                .log_err();
 7154        })
 7155    }
 7156
 7157    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7158        struct NewlineFold;
 7159        let type_id = std::any::TypeId::of::<NewlineFold>();
 7160        if !self.mode.is_single_line() {
 7161            return;
 7162        }
 7163        let snapshot = self.snapshot(window, cx);
 7164        if snapshot.buffer_snapshot().max_point().row == 0 {
 7165            return;
 7166        }
 7167        let task = cx.background_spawn(async move {
 7168            let new_newlines = snapshot
 7169                .buffer_chars_at(MultiBufferOffset(0))
 7170                .filter_map(|(c, i)| {
 7171                    if c == '\n' {
 7172                        Some(
 7173                            snapshot.buffer_snapshot().anchor_after(i)
 7174                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7175                        )
 7176                    } else {
 7177                        None
 7178                    }
 7179                })
 7180                .collect::<Vec<_>>();
 7181            let existing_newlines = snapshot
 7182                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7183                .filter_map(|fold| {
 7184                    if fold.placeholder.type_tag == Some(type_id) {
 7185                        Some(fold.range.start..fold.range.end)
 7186                    } else {
 7187                        None
 7188                    }
 7189                })
 7190                .collect::<Vec<_>>();
 7191
 7192            (new_newlines, existing_newlines)
 7193        });
 7194        self.folding_newlines = cx.spawn(async move |this, cx| {
 7195            let (new_newlines, existing_newlines) = task.await;
 7196            if new_newlines == existing_newlines {
 7197                return;
 7198            }
 7199            let placeholder = FoldPlaceholder {
 7200                render: Arc::new(move |_, _, cx| {
 7201                    div()
 7202                        .bg(cx.theme().status().hint_background)
 7203                        .border_b_1()
 7204                        .size_full()
 7205                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7206                        .border_color(cx.theme().status().hint)
 7207                        .child("\\n")
 7208                        .into_any()
 7209                }),
 7210                constrain_width: false,
 7211                merge_adjacent: false,
 7212                type_tag: Some(type_id),
 7213            };
 7214            let creases = new_newlines
 7215                .into_iter()
 7216                .map(|range| Crease::simple(range, placeholder.clone()))
 7217                .collect();
 7218            this.update(cx, |this, cx| {
 7219                this.display_map.update(cx, |display_map, cx| {
 7220                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7221                    display_map.fold(creases, cx);
 7222                });
 7223            })
 7224            .ok();
 7225        });
 7226    }
 7227
 7228    fn refresh_selected_text_highlights(
 7229        &mut self,
 7230        on_buffer_edit: bool,
 7231        window: &mut Window,
 7232        cx: &mut Context<Editor>,
 7233    ) {
 7234        let Some((query_text, query_range)) =
 7235            self.prepare_highlight_query_from_selection(window, cx)
 7236        else {
 7237            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7238            self.quick_selection_highlight_task.take();
 7239            self.debounced_selection_highlight_task.take();
 7240            return;
 7241        };
 7242        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7243        if on_buffer_edit
 7244            || self
 7245                .quick_selection_highlight_task
 7246                .as_ref()
 7247                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7248        {
 7249            let multi_buffer_visible_start = self
 7250                .scroll_manager
 7251                .anchor()
 7252                .anchor
 7253                .to_point(&multi_buffer_snapshot);
 7254            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7255                multi_buffer_visible_start
 7256                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7257                Bias::Left,
 7258            );
 7259            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7260            self.quick_selection_highlight_task = Some((
 7261                query_range.clone(),
 7262                self.update_selection_occurrence_highlights(
 7263                    query_text.clone(),
 7264                    query_range.clone(),
 7265                    multi_buffer_visible_range,
 7266                    false,
 7267                    window,
 7268                    cx,
 7269                ),
 7270            ));
 7271        }
 7272        if on_buffer_edit
 7273            || self
 7274                .debounced_selection_highlight_task
 7275                .as_ref()
 7276                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7277        {
 7278            let multi_buffer_start = multi_buffer_snapshot
 7279                .anchor_before(MultiBufferOffset(0))
 7280                .to_point(&multi_buffer_snapshot);
 7281            let multi_buffer_end = multi_buffer_snapshot
 7282                .anchor_after(multi_buffer_snapshot.len())
 7283                .to_point(&multi_buffer_snapshot);
 7284            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7285            self.debounced_selection_highlight_task = Some((
 7286                query_range.clone(),
 7287                self.update_selection_occurrence_highlights(
 7288                    query_text,
 7289                    query_range,
 7290                    multi_buffer_full_range,
 7291                    true,
 7292                    window,
 7293                    cx,
 7294                ),
 7295            ));
 7296        }
 7297    }
 7298
 7299    pub fn refresh_edit_prediction(
 7300        &mut self,
 7301        debounce: bool,
 7302        user_requested: bool,
 7303        window: &mut Window,
 7304        cx: &mut Context<Self>,
 7305    ) -> Option<()> {
 7306        if DisableAiSettings::get_global(cx).disable_ai {
 7307            return None;
 7308        }
 7309
 7310        let provider = self.edit_prediction_provider()?;
 7311        let cursor = self.selections.newest_anchor().head();
 7312        let (buffer, cursor_buffer_position) =
 7313            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7314
 7315        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7316            self.discard_edit_prediction(false, cx);
 7317            return None;
 7318        }
 7319
 7320        self.update_visible_edit_prediction(window, cx);
 7321
 7322        if !user_requested
 7323            && (!self.should_show_edit_predictions()
 7324                || !self.is_focused(window)
 7325                || buffer.read(cx).is_empty())
 7326        {
 7327            self.discard_edit_prediction(false, cx);
 7328            return None;
 7329        }
 7330
 7331        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7332        Some(())
 7333    }
 7334
 7335    fn show_edit_predictions_in_menu(&self) -> bool {
 7336        match self.edit_prediction_settings {
 7337            EditPredictionSettings::Disabled => false,
 7338            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7339        }
 7340    }
 7341
 7342    pub fn edit_predictions_enabled(&self) -> bool {
 7343        match self.edit_prediction_settings {
 7344            EditPredictionSettings::Disabled => false,
 7345            EditPredictionSettings::Enabled { .. } => true,
 7346        }
 7347    }
 7348
 7349    fn edit_prediction_requires_modifier(&self) -> bool {
 7350        match self.edit_prediction_settings {
 7351            EditPredictionSettings::Disabled => false,
 7352            EditPredictionSettings::Enabled {
 7353                preview_requires_modifier,
 7354                ..
 7355            } => preview_requires_modifier,
 7356        }
 7357    }
 7358
 7359    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7360        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7361            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7362            self.discard_edit_prediction(false, cx);
 7363        } else {
 7364            let selection = self.selections.newest_anchor();
 7365            let cursor = selection.head();
 7366
 7367            if let Some((buffer, cursor_buffer_position)) =
 7368                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7369            {
 7370                self.edit_prediction_settings =
 7371                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7372            }
 7373        }
 7374    }
 7375
 7376    fn edit_prediction_settings_at_position(
 7377        &self,
 7378        buffer: &Entity<Buffer>,
 7379        buffer_position: language::Anchor,
 7380        cx: &App,
 7381    ) -> EditPredictionSettings {
 7382        if !self.mode.is_full()
 7383            || !self.show_edit_predictions_override.unwrap_or(true)
 7384            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7385        {
 7386            return EditPredictionSettings::Disabled;
 7387        }
 7388
 7389        let buffer = buffer.read(cx);
 7390
 7391        let file = buffer.file();
 7392
 7393        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7394            return EditPredictionSettings::Disabled;
 7395        };
 7396
 7397        let by_provider = matches!(
 7398            self.menu_edit_predictions_policy,
 7399            MenuEditPredictionsPolicy::ByProvider
 7400        );
 7401
 7402        let show_in_menu = by_provider
 7403            && self
 7404                .edit_prediction_provider
 7405                .as_ref()
 7406                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7407
 7408        let preview_requires_modifier =
 7409            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7410
 7411        EditPredictionSettings::Enabled {
 7412            show_in_menu,
 7413            preview_requires_modifier,
 7414        }
 7415    }
 7416
 7417    fn should_show_edit_predictions(&self) -> bool {
 7418        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7419    }
 7420
 7421    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7422        matches!(
 7423            self.edit_prediction_preview,
 7424            EditPredictionPreview::Active { .. }
 7425        )
 7426    }
 7427
 7428    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7429        let cursor = self.selections.newest_anchor().head();
 7430        if let Some((buffer, cursor_position)) =
 7431            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7432        {
 7433            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7434        } else {
 7435            false
 7436        }
 7437    }
 7438
 7439    pub fn supports_minimap(&self, cx: &App) -> bool {
 7440        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7441    }
 7442
 7443    fn edit_predictions_enabled_in_buffer(
 7444        &self,
 7445        buffer: &Entity<Buffer>,
 7446        buffer_position: language::Anchor,
 7447        cx: &App,
 7448    ) -> bool {
 7449        maybe!({
 7450            if self.read_only(cx) {
 7451                return Some(false);
 7452            }
 7453            let provider = self.edit_prediction_provider()?;
 7454            if !provider.is_enabled(buffer, buffer_position, cx) {
 7455                return Some(false);
 7456            }
 7457            let buffer = buffer.read(cx);
 7458            let Some(file) = buffer.file() else {
 7459                return Some(true);
 7460            };
 7461            let settings = all_language_settings(Some(file), cx);
 7462            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7463        })
 7464        .unwrap_or(false)
 7465    }
 7466
 7467    fn cycle_edit_prediction(
 7468        &mut self,
 7469        direction: Direction,
 7470        window: &mut Window,
 7471        cx: &mut Context<Self>,
 7472    ) -> Option<()> {
 7473        let provider = self.edit_prediction_provider()?;
 7474        let cursor = self.selections.newest_anchor().head();
 7475        let (buffer, cursor_buffer_position) =
 7476            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7477        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7478            return None;
 7479        }
 7480
 7481        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7482        self.update_visible_edit_prediction(window, cx);
 7483
 7484        Some(())
 7485    }
 7486
 7487    pub fn show_edit_prediction(
 7488        &mut self,
 7489        _: &ShowEditPrediction,
 7490        window: &mut Window,
 7491        cx: &mut Context<Self>,
 7492    ) {
 7493        if !self.has_active_edit_prediction() {
 7494            self.refresh_edit_prediction(false, true, window, cx);
 7495            return;
 7496        }
 7497
 7498        self.update_visible_edit_prediction(window, cx);
 7499    }
 7500
 7501    pub fn display_cursor_names(
 7502        &mut self,
 7503        _: &DisplayCursorNames,
 7504        window: &mut Window,
 7505        cx: &mut Context<Self>,
 7506    ) {
 7507        self.show_cursor_names(window, cx);
 7508    }
 7509
 7510    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7511        self.show_cursor_names = true;
 7512        cx.notify();
 7513        cx.spawn_in(window, async move |this, cx| {
 7514            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7515            this.update(cx, |this, cx| {
 7516                this.show_cursor_names = false;
 7517                cx.notify()
 7518            })
 7519            .ok()
 7520        })
 7521        .detach();
 7522    }
 7523
 7524    pub fn next_edit_prediction(
 7525        &mut self,
 7526        _: &NextEditPrediction,
 7527        window: &mut Window,
 7528        cx: &mut Context<Self>,
 7529    ) {
 7530        if self.has_active_edit_prediction() {
 7531            self.cycle_edit_prediction(Direction::Next, window, cx);
 7532        } else {
 7533            let is_copilot_disabled = self
 7534                .refresh_edit_prediction(false, true, window, cx)
 7535                .is_none();
 7536            if is_copilot_disabled {
 7537                cx.propagate();
 7538            }
 7539        }
 7540    }
 7541
 7542    pub fn previous_edit_prediction(
 7543        &mut self,
 7544        _: &PreviousEditPrediction,
 7545        window: &mut Window,
 7546        cx: &mut Context<Self>,
 7547    ) {
 7548        if self.has_active_edit_prediction() {
 7549            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7550        } else {
 7551            let is_copilot_disabled = self
 7552                .refresh_edit_prediction(false, true, window, cx)
 7553                .is_none();
 7554            if is_copilot_disabled {
 7555                cx.propagate();
 7556            }
 7557        }
 7558    }
 7559
 7560    pub fn accept_edit_prediction(
 7561        &mut self,
 7562        _: &AcceptEditPrediction,
 7563        window: &mut Window,
 7564        cx: &mut Context<Self>,
 7565    ) {
 7566        if self.show_edit_predictions_in_menu() {
 7567            self.hide_context_menu(window, cx);
 7568        }
 7569
 7570        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7571            return;
 7572        };
 7573
 7574        match &active_edit_prediction.completion {
 7575            EditPrediction::MoveWithin { target, .. } => {
 7576                let target = *target;
 7577
 7578                if let Some(position_map) = &self.last_position_map {
 7579                    if position_map
 7580                        .visible_row_range
 7581                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7582                        || !self.edit_prediction_requires_modifier()
 7583                    {
 7584                        self.unfold_ranges(&[target..target], true, false, cx);
 7585                        // Note that this is also done in vim's handler of the Tab action.
 7586                        self.change_selections(
 7587                            SelectionEffects::scroll(Autoscroll::newest()),
 7588                            window,
 7589                            cx,
 7590                            |selections| {
 7591                                selections.select_anchor_ranges([target..target]);
 7592                            },
 7593                        );
 7594                        self.clear_row_highlights::<EditPredictionPreview>();
 7595
 7596                        self.edit_prediction_preview
 7597                            .set_previous_scroll_position(None);
 7598                    } else {
 7599                        self.edit_prediction_preview
 7600                            .set_previous_scroll_position(Some(
 7601                                position_map.snapshot.scroll_anchor,
 7602                            ));
 7603
 7604                        self.highlight_rows::<EditPredictionPreview>(
 7605                            target..target,
 7606                            cx.theme().colors().editor_highlighted_line_background,
 7607                            RowHighlightOptions {
 7608                                autoscroll: true,
 7609                                ..Default::default()
 7610                            },
 7611                            cx,
 7612                        );
 7613                        self.request_autoscroll(Autoscroll::fit(), cx);
 7614                    }
 7615                }
 7616            }
 7617            EditPrediction::MoveOutside { snapshot, target } => {
 7618                if let Some(workspace) = self.workspace() {
 7619                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7620                        .detach_and_log_err(cx);
 7621                }
 7622            }
 7623            EditPrediction::Edit { edits, .. } => {
 7624                self.report_edit_prediction_event(
 7625                    active_edit_prediction.completion_id.clone(),
 7626                    true,
 7627                    cx,
 7628                );
 7629
 7630                if let Some(provider) = self.edit_prediction_provider() {
 7631                    provider.accept(cx);
 7632                }
 7633
 7634                // Store the transaction ID and selections before applying the edit
 7635                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7636
 7637                let snapshot = self.buffer.read(cx).snapshot(cx);
 7638                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7639
 7640                self.buffer.update(cx, |buffer, cx| {
 7641                    buffer.edit(edits.iter().cloned(), None, cx)
 7642                });
 7643
 7644                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7645                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7646                });
 7647
 7648                let selections = self.selections.disjoint_anchors_arc();
 7649                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7650                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7651                    if has_new_transaction {
 7652                        self.selection_history
 7653                            .insert_transaction(transaction_id_now, selections);
 7654                    }
 7655                }
 7656
 7657                self.update_visible_edit_prediction(window, cx);
 7658                if self.active_edit_prediction.is_none() {
 7659                    self.refresh_edit_prediction(true, true, window, cx);
 7660                }
 7661
 7662                cx.notify();
 7663            }
 7664        }
 7665
 7666        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7667    }
 7668
 7669    pub fn accept_partial_edit_prediction(
 7670        &mut self,
 7671        _: &AcceptPartialEditPrediction,
 7672        window: &mut Window,
 7673        cx: &mut Context<Self>,
 7674    ) {
 7675        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7676            return;
 7677        };
 7678        if self.selections.count() != 1 {
 7679            return;
 7680        }
 7681
 7682        match &active_edit_prediction.completion {
 7683            EditPrediction::MoveWithin { target, .. } => {
 7684                let target = *target;
 7685                self.change_selections(
 7686                    SelectionEffects::scroll(Autoscroll::newest()),
 7687                    window,
 7688                    cx,
 7689                    |selections| {
 7690                        selections.select_anchor_ranges([target..target]);
 7691                    },
 7692                );
 7693            }
 7694            EditPrediction::MoveOutside { snapshot, target } => {
 7695                if let Some(workspace) = self.workspace() {
 7696                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7697                        .detach_and_log_err(cx);
 7698                }
 7699            }
 7700            EditPrediction::Edit { edits, .. } => {
 7701                self.report_edit_prediction_event(
 7702                    active_edit_prediction.completion_id.clone(),
 7703                    true,
 7704                    cx,
 7705                );
 7706
 7707                // Find an insertion that starts at the cursor position.
 7708                let snapshot = self.buffer.read(cx).snapshot(cx);
 7709                let cursor_offset = self
 7710                    .selections
 7711                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7712                    .head();
 7713                let insertion = edits.iter().find_map(|(range, text)| {
 7714                    let range = range.to_offset(&snapshot);
 7715                    if range.is_empty() && range.start == cursor_offset {
 7716                        Some(text)
 7717                    } else {
 7718                        None
 7719                    }
 7720                });
 7721
 7722                if let Some(text) = insertion {
 7723                    let mut partial_completion = text
 7724                        .chars()
 7725                        .by_ref()
 7726                        .take_while(|c| c.is_alphabetic())
 7727                        .collect::<String>();
 7728                    if partial_completion.is_empty() {
 7729                        partial_completion = text
 7730                            .chars()
 7731                            .by_ref()
 7732                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7733                            .collect::<String>();
 7734                    }
 7735
 7736                    cx.emit(EditorEvent::InputHandled {
 7737                        utf16_range_to_replace: None,
 7738                        text: partial_completion.clone().into(),
 7739                    });
 7740
 7741                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7742
 7743                    self.refresh_edit_prediction(true, true, window, cx);
 7744                    cx.notify();
 7745                } else {
 7746                    self.accept_edit_prediction(&Default::default(), window, cx);
 7747                }
 7748            }
 7749        }
 7750    }
 7751
 7752    fn discard_edit_prediction(
 7753        &mut self,
 7754        should_report_edit_prediction_event: bool,
 7755        cx: &mut Context<Self>,
 7756    ) -> bool {
 7757        if should_report_edit_prediction_event {
 7758            let completion_id = self
 7759                .active_edit_prediction
 7760                .as_ref()
 7761                .and_then(|active_completion| active_completion.completion_id.clone());
 7762
 7763            self.report_edit_prediction_event(completion_id, false, cx);
 7764        }
 7765
 7766        if let Some(provider) = self.edit_prediction_provider() {
 7767            provider.discard(cx);
 7768        }
 7769
 7770        self.take_active_edit_prediction(cx)
 7771    }
 7772
 7773    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7774        let Some(provider) = self.edit_prediction_provider() else {
 7775            return;
 7776        };
 7777
 7778        let Some((_, buffer, _)) = self
 7779            .buffer
 7780            .read(cx)
 7781            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7782        else {
 7783            return;
 7784        };
 7785
 7786        let extension = buffer
 7787            .read(cx)
 7788            .file()
 7789            .and_then(|file| Some(file.path().extension()?.to_string()));
 7790
 7791        let event_type = match accepted {
 7792            true => "Edit Prediction Accepted",
 7793            false => "Edit Prediction Discarded",
 7794        };
 7795        telemetry::event!(
 7796            event_type,
 7797            provider = provider.name(),
 7798            prediction_id = id,
 7799            suggestion_accepted = accepted,
 7800            file_extension = extension,
 7801        );
 7802    }
 7803
 7804    fn open_editor_at_anchor(
 7805        snapshot: &language::BufferSnapshot,
 7806        target: language::Anchor,
 7807        workspace: &Entity<Workspace>,
 7808        window: &mut Window,
 7809        cx: &mut App,
 7810    ) -> Task<Result<()>> {
 7811        workspace.update(cx, |workspace, cx| {
 7812            let path = snapshot.file().map(|file| file.full_path(cx));
 7813            let Some(path) =
 7814                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7815            else {
 7816                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7817            };
 7818            let target = text::ToPoint::to_point(&target, snapshot);
 7819            let item = workspace.open_path(path, None, true, window, cx);
 7820            window.spawn(cx, async move |cx| {
 7821                let Some(editor) = item.await?.downcast::<Editor>() else {
 7822                    return Ok(());
 7823                };
 7824                editor
 7825                    .update_in(cx, |editor, window, cx| {
 7826                        editor.go_to_singleton_buffer_point(target, window, cx);
 7827                    })
 7828                    .ok();
 7829                anyhow::Ok(())
 7830            })
 7831        })
 7832    }
 7833
 7834    pub fn has_active_edit_prediction(&self) -> bool {
 7835        self.active_edit_prediction.is_some()
 7836    }
 7837
 7838    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7839        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7840            return false;
 7841        };
 7842
 7843        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7844        self.clear_highlights::<EditPredictionHighlight>(cx);
 7845        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7846        true
 7847    }
 7848
 7849    /// Returns true when we're displaying the edit prediction popover below the cursor
 7850    /// like we are not previewing and the LSP autocomplete menu is visible
 7851    /// or we are in `when_holding_modifier` mode.
 7852    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7853        if self.edit_prediction_preview_is_active()
 7854            || !self.show_edit_predictions_in_menu()
 7855            || !self.edit_predictions_enabled()
 7856        {
 7857            return false;
 7858        }
 7859
 7860        if self.has_visible_completions_menu() {
 7861            return true;
 7862        }
 7863
 7864        has_completion && self.edit_prediction_requires_modifier()
 7865    }
 7866
 7867    fn handle_modifiers_changed(
 7868        &mut self,
 7869        modifiers: Modifiers,
 7870        position_map: &PositionMap,
 7871        window: &mut Window,
 7872        cx: &mut Context<Self>,
 7873    ) {
 7874        // Ensure that the edit prediction preview is updated, even when not
 7875        // enabled, if there's an active edit prediction preview.
 7876        if self.show_edit_predictions_in_menu()
 7877            || matches!(
 7878                self.edit_prediction_preview,
 7879                EditPredictionPreview::Active { .. }
 7880            )
 7881        {
 7882            self.update_edit_prediction_preview(&modifiers, window, cx);
 7883        }
 7884
 7885        self.update_selection_mode(&modifiers, position_map, window, cx);
 7886
 7887        let mouse_position = window.mouse_position();
 7888        if !position_map.text_hitbox.is_hovered(window) {
 7889            return;
 7890        }
 7891
 7892        self.update_hovered_link(
 7893            position_map.point_for_position(mouse_position),
 7894            &position_map.snapshot,
 7895            modifiers,
 7896            window,
 7897            cx,
 7898        )
 7899    }
 7900
 7901    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7902        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7903            MultiCursorModifier::Alt => modifiers.secondary(),
 7904            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7905        }
 7906    }
 7907
 7908    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7909        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7910            MultiCursorModifier::Alt => modifiers.alt,
 7911            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7912        }
 7913    }
 7914
 7915    fn columnar_selection_mode(
 7916        modifiers: &Modifiers,
 7917        cx: &mut Context<Self>,
 7918    ) -> Option<ColumnarMode> {
 7919        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7920            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7921                Some(ColumnarMode::FromMouse)
 7922            } else if Self::is_alt_pressed(modifiers, cx) {
 7923                Some(ColumnarMode::FromSelection)
 7924            } else {
 7925                None
 7926            }
 7927        } else {
 7928            None
 7929        }
 7930    }
 7931
 7932    fn update_selection_mode(
 7933        &mut self,
 7934        modifiers: &Modifiers,
 7935        position_map: &PositionMap,
 7936        window: &mut Window,
 7937        cx: &mut Context<Self>,
 7938    ) {
 7939        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7940            return;
 7941        };
 7942        if self.selections.pending_anchor().is_none() {
 7943            return;
 7944        }
 7945
 7946        let mouse_position = window.mouse_position();
 7947        let point_for_position = position_map.point_for_position(mouse_position);
 7948        let position = point_for_position.previous_valid;
 7949
 7950        self.select(
 7951            SelectPhase::BeginColumnar {
 7952                position,
 7953                reset: false,
 7954                mode,
 7955                goal_column: point_for_position.exact_unclipped.column(),
 7956            },
 7957            window,
 7958            cx,
 7959        );
 7960    }
 7961
 7962    fn update_edit_prediction_preview(
 7963        &mut self,
 7964        modifiers: &Modifiers,
 7965        window: &mut Window,
 7966        cx: &mut Context<Self>,
 7967    ) {
 7968        let mut modifiers_held = false;
 7969        if let Some(accept_keystroke) = self
 7970            .accept_edit_prediction_keybind(false, window, cx)
 7971            .keystroke()
 7972        {
 7973            modifiers_held = modifiers_held
 7974                || (accept_keystroke.modifiers() == modifiers
 7975                    && accept_keystroke.modifiers().modified());
 7976        };
 7977        if let Some(accept_partial_keystroke) = self
 7978            .accept_edit_prediction_keybind(true, window, cx)
 7979            .keystroke()
 7980        {
 7981            modifiers_held = modifiers_held
 7982                || (accept_partial_keystroke.modifiers() == modifiers
 7983                    && accept_partial_keystroke.modifiers().modified());
 7984        }
 7985
 7986        if modifiers_held {
 7987            if matches!(
 7988                self.edit_prediction_preview,
 7989                EditPredictionPreview::Inactive { .. }
 7990            ) {
 7991                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7992                    provider.provider.did_show(cx)
 7993                }
 7994
 7995                self.edit_prediction_preview = EditPredictionPreview::Active {
 7996                    previous_scroll_position: None,
 7997                    since: Instant::now(),
 7998                };
 7999
 8000                self.update_visible_edit_prediction(window, cx);
 8001                cx.notify();
 8002            }
 8003        } else if let EditPredictionPreview::Active {
 8004            previous_scroll_position,
 8005            since,
 8006        } = self.edit_prediction_preview
 8007        {
 8008            if let (Some(previous_scroll_position), Some(position_map)) =
 8009                (previous_scroll_position, self.last_position_map.as_ref())
 8010            {
 8011                self.set_scroll_position(
 8012                    previous_scroll_position
 8013                        .scroll_position(&position_map.snapshot.display_snapshot),
 8014                    window,
 8015                    cx,
 8016                );
 8017            }
 8018
 8019            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8020                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8021            };
 8022            self.clear_row_highlights::<EditPredictionPreview>();
 8023            self.update_visible_edit_prediction(window, cx);
 8024            cx.notify();
 8025        }
 8026    }
 8027
 8028    fn update_visible_edit_prediction(
 8029        &mut self,
 8030        _window: &mut Window,
 8031        cx: &mut Context<Self>,
 8032    ) -> Option<()> {
 8033        if DisableAiSettings::get_global(cx).disable_ai {
 8034            return None;
 8035        }
 8036
 8037        if self.ime_transaction.is_some() {
 8038            self.discard_edit_prediction(false, cx);
 8039            return None;
 8040        }
 8041
 8042        let selection = self.selections.newest_anchor();
 8043        let cursor = selection.head();
 8044        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8045        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8046        let excerpt_id = cursor.excerpt_id;
 8047
 8048        let show_in_menu = self.show_edit_predictions_in_menu();
 8049        let completions_menu_has_precedence = !show_in_menu
 8050            && (self.context_menu.borrow().is_some()
 8051                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8052
 8053        if completions_menu_has_precedence
 8054            || !offset_selection.is_empty()
 8055            || self
 8056                .active_edit_prediction
 8057                .as_ref()
 8058                .is_some_and(|completion| {
 8059                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8060                        return false;
 8061                    };
 8062                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8063                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8064                    !invalidation_range.contains(&offset_selection.head())
 8065                })
 8066        {
 8067            self.discard_edit_prediction(false, cx);
 8068            return None;
 8069        }
 8070
 8071        self.take_active_edit_prediction(cx);
 8072        let Some(provider) = self.edit_prediction_provider() else {
 8073            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8074            return None;
 8075        };
 8076
 8077        let (buffer, cursor_buffer_position) =
 8078            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8079
 8080        self.edit_prediction_settings =
 8081            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8082
 8083        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8084
 8085        if self.edit_prediction_indent_conflict {
 8086            let cursor_point = cursor.to_point(&multibuffer);
 8087            let mut suggested_indent = None;
 8088            multibuffer.suggested_indents_callback(
 8089                cursor_point.row..cursor_point.row + 1,
 8090                |_, indent| {
 8091                    suggested_indent = Some(indent);
 8092                    ControlFlow::Break(())
 8093                },
 8094                cx,
 8095            );
 8096
 8097            if let Some(indent) = suggested_indent
 8098                && indent.len == cursor_point.column
 8099            {
 8100                self.edit_prediction_indent_conflict = false;
 8101            }
 8102        }
 8103
 8104        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8105
 8106        let (completion_id, edits, edit_preview) = match edit_prediction {
 8107            edit_prediction_types::EditPrediction::Local {
 8108                id,
 8109                edits,
 8110                edit_preview,
 8111            } => (id, edits, edit_preview),
 8112            edit_prediction_types::EditPrediction::Jump {
 8113                id,
 8114                snapshot,
 8115                target,
 8116            } => {
 8117                self.stale_edit_prediction_in_menu = None;
 8118                self.active_edit_prediction = Some(EditPredictionState {
 8119                    inlay_ids: vec![],
 8120                    completion: EditPrediction::MoveOutside { snapshot, target },
 8121                    completion_id: id,
 8122                    invalidation_range: None,
 8123                });
 8124                cx.notify();
 8125                return Some(());
 8126            }
 8127        };
 8128
 8129        let edits = edits
 8130            .into_iter()
 8131            .flat_map(|(range, new_text)| {
 8132                Some((
 8133                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8134                    new_text,
 8135                ))
 8136            })
 8137            .collect::<Vec<_>>();
 8138        if edits.is_empty() {
 8139            return None;
 8140        }
 8141
 8142        let first_edit_start = edits.first().unwrap().0.start;
 8143        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8144        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8145
 8146        let last_edit_end = edits.last().unwrap().0.end;
 8147        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8148        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8149
 8150        let cursor_row = cursor.to_point(&multibuffer).row;
 8151
 8152        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8153
 8154        let mut inlay_ids = Vec::new();
 8155        let invalidation_row_range;
 8156        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8157            Some(cursor_row..edit_end_row)
 8158        } else if cursor_row > edit_end_row {
 8159            Some(edit_start_row..cursor_row)
 8160        } else {
 8161            None
 8162        };
 8163        let supports_jump = self
 8164            .edit_prediction_provider
 8165            .as_ref()
 8166            .map(|provider| provider.provider.supports_jump_to_edit())
 8167            .unwrap_or(true);
 8168
 8169        let is_move = supports_jump
 8170            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8171        let completion = if is_move {
 8172            invalidation_row_range =
 8173                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8174            let target = first_edit_start;
 8175            EditPrediction::MoveWithin { target, snapshot }
 8176        } else {
 8177            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8178                && !self.edit_predictions_hidden_for_vim_mode;
 8179
 8180            if show_completions_in_buffer {
 8181                if let Some(provider) = &self.edit_prediction_provider {
 8182                    provider.provider.did_show(cx);
 8183                }
 8184                if edits
 8185                    .iter()
 8186                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8187                {
 8188                    let mut inlays = Vec::new();
 8189                    for (range, new_text) in &edits {
 8190                        let inlay = Inlay::edit_prediction(
 8191                            post_inc(&mut self.next_inlay_id),
 8192                            range.start,
 8193                            new_text.as_ref(),
 8194                        );
 8195                        inlay_ids.push(inlay.id);
 8196                        inlays.push(inlay);
 8197                    }
 8198
 8199                    self.splice_inlays(&[], inlays, cx);
 8200                } else {
 8201                    let background_color = cx.theme().status().deleted_background;
 8202                    self.highlight_text::<EditPredictionHighlight>(
 8203                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8204                        HighlightStyle {
 8205                            background_color: Some(background_color),
 8206                            ..Default::default()
 8207                        },
 8208                        cx,
 8209                    );
 8210                }
 8211            }
 8212
 8213            invalidation_row_range = edit_start_row..edit_end_row;
 8214
 8215            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8216                if provider.show_tab_accept_marker() {
 8217                    EditDisplayMode::TabAccept
 8218                } else {
 8219                    EditDisplayMode::Inline
 8220                }
 8221            } else {
 8222                EditDisplayMode::DiffPopover
 8223            };
 8224
 8225            EditPrediction::Edit {
 8226                edits,
 8227                edit_preview,
 8228                display_mode,
 8229                snapshot,
 8230            }
 8231        };
 8232
 8233        let invalidation_range = multibuffer
 8234            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8235            ..multibuffer.anchor_after(Point::new(
 8236                invalidation_row_range.end,
 8237                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8238            ));
 8239
 8240        self.stale_edit_prediction_in_menu = None;
 8241        self.active_edit_prediction = Some(EditPredictionState {
 8242            inlay_ids,
 8243            completion,
 8244            completion_id,
 8245            invalidation_range: Some(invalidation_range),
 8246        });
 8247
 8248        cx.notify();
 8249
 8250        Some(())
 8251    }
 8252
 8253    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8254        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8255    }
 8256
 8257    fn clear_tasks(&mut self) {
 8258        self.tasks.clear()
 8259    }
 8260
 8261    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8262        if self.tasks.insert(key, value).is_some() {
 8263            // This case should hopefully be rare, but just in case...
 8264            log::error!(
 8265                "multiple different run targets found on a single line, only the last target will be rendered"
 8266            )
 8267        }
 8268    }
 8269
 8270    /// Get all display points of breakpoints that will be rendered within editor
 8271    ///
 8272    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8273    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8274    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8275    fn active_breakpoints(
 8276        &self,
 8277        range: Range<DisplayRow>,
 8278        window: &mut Window,
 8279        cx: &mut Context<Self>,
 8280    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8281        let mut breakpoint_display_points = HashMap::default();
 8282
 8283        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8284            return breakpoint_display_points;
 8285        };
 8286
 8287        let snapshot = self.snapshot(window, cx);
 8288
 8289        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8290        let Some(project) = self.project() else {
 8291            return breakpoint_display_points;
 8292        };
 8293
 8294        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8295            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8296
 8297        for (buffer_snapshot, range, excerpt_id) in
 8298            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8299        {
 8300            let Some(buffer) = project
 8301                .read(cx)
 8302                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8303            else {
 8304                continue;
 8305            };
 8306            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8307                &buffer,
 8308                Some(
 8309                    buffer_snapshot.anchor_before(range.start)
 8310                        ..buffer_snapshot.anchor_after(range.end),
 8311                ),
 8312                buffer_snapshot,
 8313                cx,
 8314            );
 8315            for (breakpoint, state) in breakpoints {
 8316                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8317                let position = multi_buffer_anchor
 8318                    .to_point(&multi_buffer_snapshot)
 8319                    .to_display_point(&snapshot);
 8320
 8321                breakpoint_display_points.insert(
 8322                    position.row(),
 8323                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8324                );
 8325            }
 8326        }
 8327
 8328        breakpoint_display_points
 8329    }
 8330
 8331    fn breakpoint_context_menu(
 8332        &self,
 8333        anchor: Anchor,
 8334        window: &mut Window,
 8335        cx: &mut Context<Self>,
 8336    ) -> Entity<ui::ContextMenu> {
 8337        let weak_editor = cx.weak_entity();
 8338        let focus_handle = self.focus_handle(cx);
 8339
 8340        let row = self
 8341            .buffer
 8342            .read(cx)
 8343            .snapshot(cx)
 8344            .summary_for_anchor::<Point>(&anchor)
 8345            .row;
 8346
 8347        let breakpoint = self
 8348            .breakpoint_at_row(row, window, cx)
 8349            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8350
 8351        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8352            "Edit Log Breakpoint"
 8353        } else {
 8354            "Set Log Breakpoint"
 8355        };
 8356
 8357        let condition_breakpoint_msg = if breakpoint
 8358            .as_ref()
 8359            .is_some_and(|bp| bp.1.condition.is_some())
 8360        {
 8361            "Edit Condition Breakpoint"
 8362        } else {
 8363            "Set Condition Breakpoint"
 8364        };
 8365
 8366        let hit_condition_breakpoint_msg = if breakpoint
 8367            .as_ref()
 8368            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8369        {
 8370            "Edit Hit Condition Breakpoint"
 8371        } else {
 8372            "Set Hit Condition Breakpoint"
 8373        };
 8374
 8375        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8376            "Unset Breakpoint"
 8377        } else {
 8378            "Set Breakpoint"
 8379        };
 8380
 8381        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8382
 8383        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8384            BreakpointState::Enabled => Some("Disable"),
 8385            BreakpointState::Disabled => Some("Enable"),
 8386        });
 8387
 8388        let (anchor, breakpoint) =
 8389            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8390
 8391        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8392            menu.on_blur_subscription(Subscription::new(|| {}))
 8393                .context(focus_handle)
 8394                .when(run_to_cursor, |this| {
 8395                    let weak_editor = weak_editor.clone();
 8396                    this.entry("Run to cursor", None, move |window, cx| {
 8397                        weak_editor
 8398                            .update(cx, |editor, cx| {
 8399                                editor.change_selections(
 8400                                    SelectionEffects::no_scroll(),
 8401                                    window,
 8402                                    cx,
 8403                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8404                                );
 8405                            })
 8406                            .ok();
 8407
 8408                        window.dispatch_action(Box::new(RunToCursor), cx);
 8409                    })
 8410                    .separator()
 8411                })
 8412                .when_some(toggle_state_msg, |this, msg| {
 8413                    this.entry(msg, None, {
 8414                        let weak_editor = weak_editor.clone();
 8415                        let breakpoint = breakpoint.clone();
 8416                        move |_window, cx| {
 8417                            weak_editor
 8418                                .update(cx, |this, cx| {
 8419                                    this.edit_breakpoint_at_anchor(
 8420                                        anchor,
 8421                                        breakpoint.as_ref().clone(),
 8422                                        BreakpointEditAction::InvertState,
 8423                                        cx,
 8424                                    );
 8425                                })
 8426                                .log_err();
 8427                        }
 8428                    })
 8429                })
 8430                .entry(set_breakpoint_msg, None, {
 8431                    let weak_editor = weak_editor.clone();
 8432                    let breakpoint = breakpoint.clone();
 8433                    move |_window, cx| {
 8434                        weak_editor
 8435                            .update(cx, |this, cx| {
 8436                                this.edit_breakpoint_at_anchor(
 8437                                    anchor,
 8438                                    breakpoint.as_ref().clone(),
 8439                                    BreakpointEditAction::Toggle,
 8440                                    cx,
 8441                                );
 8442                            })
 8443                            .log_err();
 8444                    }
 8445                })
 8446                .entry(log_breakpoint_msg, None, {
 8447                    let breakpoint = breakpoint.clone();
 8448                    let weak_editor = weak_editor.clone();
 8449                    move |window, cx| {
 8450                        weak_editor
 8451                            .update(cx, |this, cx| {
 8452                                this.add_edit_breakpoint_block(
 8453                                    anchor,
 8454                                    breakpoint.as_ref(),
 8455                                    BreakpointPromptEditAction::Log,
 8456                                    window,
 8457                                    cx,
 8458                                );
 8459                            })
 8460                            .log_err();
 8461                    }
 8462                })
 8463                .entry(condition_breakpoint_msg, None, {
 8464                    let breakpoint = breakpoint.clone();
 8465                    let weak_editor = weak_editor.clone();
 8466                    move |window, cx| {
 8467                        weak_editor
 8468                            .update(cx, |this, cx| {
 8469                                this.add_edit_breakpoint_block(
 8470                                    anchor,
 8471                                    breakpoint.as_ref(),
 8472                                    BreakpointPromptEditAction::Condition,
 8473                                    window,
 8474                                    cx,
 8475                                );
 8476                            })
 8477                            .log_err();
 8478                    }
 8479                })
 8480                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8481                    weak_editor
 8482                        .update(cx, |this, cx| {
 8483                            this.add_edit_breakpoint_block(
 8484                                anchor,
 8485                                breakpoint.as_ref(),
 8486                                BreakpointPromptEditAction::HitCondition,
 8487                                window,
 8488                                cx,
 8489                            );
 8490                        })
 8491                        .log_err();
 8492                })
 8493        })
 8494    }
 8495
 8496    fn render_breakpoint(
 8497        &self,
 8498        position: Anchor,
 8499        row: DisplayRow,
 8500        breakpoint: &Breakpoint,
 8501        state: Option<BreakpointSessionState>,
 8502        cx: &mut Context<Self>,
 8503    ) -> IconButton {
 8504        let is_rejected = state.is_some_and(|s| !s.verified);
 8505        // Is it a breakpoint that shows up when hovering over gutter?
 8506        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8507            (false, false),
 8508            |PhantomBreakpointIndicator {
 8509                 is_active,
 8510                 display_row,
 8511                 collides_with_existing_breakpoint,
 8512             }| {
 8513                (
 8514                    is_active && display_row == row,
 8515                    collides_with_existing_breakpoint,
 8516                )
 8517            },
 8518        );
 8519
 8520        let (color, icon) = {
 8521            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8522                (false, false) => ui::IconName::DebugBreakpoint,
 8523                (true, false) => ui::IconName::DebugLogBreakpoint,
 8524                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8525                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8526            };
 8527
 8528            let color = cx.theme().colors();
 8529
 8530            let color = if is_phantom {
 8531                if collides_with_existing {
 8532                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8533                } else {
 8534                    Color::Hint
 8535                }
 8536            } else if is_rejected {
 8537                Color::Disabled
 8538            } else {
 8539                Color::Debugger
 8540            };
 8541
 8542            (color, icon)
 8543        };
 8544
 8545        let breakpoint = Arc::from(breakpoint.clone());
 8546
 8547        let alt_as_text = gpui::Keystroke {
 8548            modifiers: Modifiers::secondary_key(),
 8549            ..Default::default()
 8550        };
 8551        let primary_action_text = if breakpoint.is_disabled() {
 8552            "Enable breakpoint"
 8553        } else if is_phantom && !collides_with_existing {
 8554            "Set breakpoint"
 8555        } else {
 8556            "Unset breakpoint"
 8557        };
 8558        let focus_handle = self.focus_handle.clone();
 8559
 8560        let meta = if is_rejected {
 8561            SharedString::from("No executable code is associated with this line.")
 8562        } else if collides_with_existing && !breakpoint.is_disabled() {
 8563            SharedString::from(format!(
 8564                "{alt_as_text}-click to disable,\nright-click for more options."
 8565            ))
 8566        } else {
 8567            SharedString::from("Right-click for more options.")
 8568        };
 8569        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8570            .icon_size(IconSize::XSmall)
 8571            .size(ui::ButtonSize::None)
 8572            .when(is_rejected, |this| {
 8573                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8574            })
 8575            .icon_color(color)
 8576            .style(ButtonStyle::Transparent)
 8577            .on_click(cx.listener({
 8578                move |editor, event: &ClickEvent, window, cx| {
 8579                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8580                        BreakpointEditAction::InvertState
 8581                    } else {
 8582                        BreakpointEditAction::Toggle
 8583                    };
 8584
 8585                    window.focus(&editor.focus_handle(cx));
 8586                    editor.edit_breakpoint_at_anchor(
 8587                        position,
 8588                        breakpoint.as_ref().clone(),
 8589                        edit_action,
 8590                        cx,
 8591                    );
 8592                }
 8593            }))
 8594            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8595                editor.set_breakpoint_context_menu(
 8596                    row,
 8597                    Some(position),
 8598                    event.position(),
 8599                    window,
 8600                    cx,
 8601                );
 8602            }))
 8603            .tooltip(move |_window, cx| {
 8604                Tooltip::with_meta_in(
 8605                    primary_action_text,
 8606                    Some(&ToggleBreakpoint),
 8607                    meta.clone(),
 8608                    &focus_handle,
 8609                    cx,
 8610                )
 8611            })
 8612    }
 8613
 8614    fn build_tasks_context(
 8615        project: &Entity<Project>,
 8616        buffer: &Entity<Buffer>,
 8617        buffer_row: u32,
 8618        tasks: &Arc<RunnableTasks>,
 8619        cx: &mut Context<Self>,
 8620    ) -> Task<Option<task::TaskContext>> {
 8621        let position = Point::new(buffer_row, tasks.column);
 8622        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8623        let location = Location {
 8624            buffer: buffer.clone(),
 8625            range: range_start..range_start,
 8626        };
 8627        // Fill in the environmental variables from the tree-sitter captures
 8628        let mut captured_task_variables = TaskVariables::default();
 8629        for (capture_name, value) in tasks.extra_variables.clone() {
 8630            captured_task_variables.insert(
 8631                task::VariableName::Custom(capture_name.into()),
 8632                value.clone(),
 8633            );
 8634        }
 8635        project.update(cx, |project, cx| {
 8636            project.task_store().update(cx, |task_store, cx| {
 8637                task_store.task_context_for_location(captured_task_variables, location, cx)
 8638            })
 8639        })
 8640    }
 8641
 8642    pub fn spawn_nearest_task(
 8643        &mut self,
 8644        action: &SpawnNearestTask,
 8645        window: &mut Window,
 8646        cx: &mut Context<Self>,
 8647    ) {
 8648        let Some((workspace, _)) = self.workspace.clone() else {
 8649            return;
 8650        };
 8651        let Some(project) = self.project.clone() else {
 8652            return;
 8653        };
 8654
 8655        // Try to find a closest, enclosing node using tree-sitter that has a task
 8656        let Some((buffer, buffer_row, tasks)) = self
 8657            .find_enclosing_node_task(cx)
 8658            // Or find the task that's closest in row-distance.
 8659            .or_else(|| self.find_closest_task(cx))
 8660        else {
 8661            return;
 8662        };
 8663
 8664        let reveal_strategy = action.reveal;
 8665        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8666        cx.spawn_in(window, async move |_, cx| {
 8667            let context = task_context.await?;
 8668            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8669
 8670            let resolved = &mut resolved_task.resolved;
 8671            resolved.reveal = reveal_strategy;
 8672
 8673            workspace
 8674                .update_in(cx, |workspace, window, cx| {
 8675                    workspace.schedule_resolved_task(
 8676                        task_source_kind,
 8677                        resolved_task,
 8678                        false,
 8679                        window,
 8680                        cx,
 8681                    );
 8682                })
 8683                .ok()
 8684        })
 8685        .detach();
 8686    }
 8687
 8688    fn find_closest_task(
 8689        &mut self,
 8690        cx: &mut Context<Self>,
 8691    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8692        let cursor_row = self
 8693            .selections
 8694            .newest_adjusted(&self.display_snapshot(cx))
 8695            .head()
 8696            .row;
 8697
 8698        let ((buffer_id, row), tasks) = self
 8699            .tasks
 8700            .iter()
 8701            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8702
 8703        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8704        let tasks = Arc::new(tasks.to_owned());
 8705        Some((buffer, *row, tasks))
 8706    }
 8707
 8708    fn find_enclosing_node_task(
 8709        &mut self,
 8710        cx: &mut Context<Self>,
 8711    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8712        let snapshot = self.buffer.read(cx).snapshot(cx);
 8713        let offset = self
 8714            .selections
 8715            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8716            .head();
 8717        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8718        let offset = excerpt.map_offset_to_buffer(offset);
 8719        let buffer_id = excerpt.buffer().remote_id();
 8720
 8721        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8722        let mut cursor = layer.node().walk();
 8723
 8724        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8725            if cursor.node().end_byte() == offset.0 {
 8726                cursor.goto_next_sibling();
 8727            }
 8728        }
 8729
 8730        // Ascend to the smallest ancestor that contains the range and has a task.
 8731        loop {
 8732            let node = cursor.node();
 8733            let node_range = node.byte_range();
 8734            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8735
 8736            // Check if this node contains our offset
 8737            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8738                // If it contains offset, check for task
 8739                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8740                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8741                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8742                }
 8743            }
 8744
 8745            if !cursor.goto_parent() {
 8746                break;
 8747            }
 8748        }
 8749        None
 8750    }
 8751
 8752    fn render_run_indicator(
 8753        &self,
 8754        _style: &EditorStyle,
 8755        is_active: bool,
 8756        row: DisplayRow,
 8757        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8758        cx: &mut Context<Self>,
 8759    ) -> IconButton {
 8760        let color = Color::Muted;
 8761        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8762
 8763        IconButton::new(
 8764            ("run_indicator", row.0 as usize),
 8765            ui::IconName::PlayOutlined,
 8766        )
 8767        .shape(ui::IconButtonShape::Square)
 8768        .icon_size(IconSize::XSmall)
 8769        .icon_color(color)
 8770        .toggle_state(is_active)
 8771        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8772            let quick_launch = match e {
 8773                ClickEvent::Keyboard(_) => true,
 8774                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8775            };
 8776
 8777            window.focus(&editor.focus_handle(cx));
 8778            editor.toggle_code_actions(
 8779                &ToggleCodeActions {
 8780                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8781                    quick_launch,
 8782                },
 8783                window,
 8784                cx,
 8785            );
 8786        }))
 8787        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8788            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8789        }))
 8790    }
 8791
 8792    pub fn context_menu_visible(&self) -> bool {
 8793        !self.edit_prediction_preview_is_active()
 8794            && self
 8795                .context_menu
 8796                .borrow()
 8797                .as_ref()
 8798                .is_some_and(|menu| menu.visible())
 8799    }
 8800
 8801    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8802        self.context_menu
 8803            .borrow()
 8804            .as_ref()
 8805            .map(|menu| menu.origin())
 8806    }
 8807
 8808    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8809        self.context_menu_options = Some(options);
 8810    }
 8811
 8812    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8813    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8814
 8815    fn render_edit_prediction_popover(
 8816        &mut self,
 8817        text_bounds: &Bounds<Pixels>,
 8818        content_origin: gpui::Point<Pixels>,
 8819        right_margin: Pixels,
 8820        editor_snapshot: &EditorSnapshot,
 8821        visible_row_range: Range<DisplayRow>,
 8822        scroll_top: ScrollOffset,
 8823        scroll_bottom: ScrollOffset,
 8824        line_layouts: &[LineWithInvisibles],
 8825        line_height: Pixels,
 8826        scroll_position: gpui::Point<ScrollOffset>,
 8827        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8828        newest_selection_head: Option<DisplayPoint>,
 8829        editor_width: Pixels,
 8830        style: &EditorStyle,
 8831        window: &mut Window,
 8832        cx: &mut App,
 8833    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8834        if self.mode().is_minimap() {
 8835            return None;
 8836        }
 8837        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8838
 8839        if self.edit_prediction_visible_in_cursor_popover(true) {
 8840            return None;
 8841        }
 8842
 8843        match &active_edit_prediction.completion {
 8844            EditPrediction::MoveWithin { target, .. } => {
 8845                let target_display_point = target.to_display_point(editor_snapshot);
 8846
 8847                if self.edit_prediction_requires_modifier() {
 8848                    if !self.edit_prediction_preview_is_active() {
 8849                        return None;
 8850                    }
 8851
 8852                    self.render_edit_prediction_modifier_jump_popover(
 8853                        text_bounds,
 8854                        content_origin,
 8855                        visible_row_range,
 8856                        line_layouts,
 8857                        line_height,
 8858                        scroll_pixel_position,
 8859                        newest_selection_head,
 8860                        target_display_point,
 8861                        window,
 8862                        cx,
 8863                    )
 8864                } else {
 8865                    self.render_edit_prediction_eager_jump_popover(
 8866                        text_bounds,
 8867                        content_origin,
 8868                        editor_snapshot,
 8869                        visible_row_range,
 8870                        scroll_top,
 8871                        scroll_bottom,
 8872                        line_height,
 8873                        scroll_pixel_position,
 8874                        target_display_point,
 8875                        editor_width,
 8876                        window,
 8877                        cx,
 8878                    )
 8879                }
 8880            }
 8881            EditPrediction::Edit {
 8882                display_mode: EditDisplayMode::Inline,
 8883                ..
 8884            } => None,
 8885            EditPrediction::Edit {
 8886                display_mode: EditDisplayMode::TabAccept,
 8887                edits,
 8888                ..
 8889            } => {
 8890                let range = &edits.first()?.0;
 8891                let target_display_point = range.end.to_display_point(editor_snapshot);
 8892
 8893                self.render_edit_prediction_end_of_line_popover(
 8894                    "Accept",
 8895                    editor_snapshot,
 8896                    visible_row_range,
 8897                    target_display_point,
 8898                    line_height,
 8899                    scroll_pixel_position,
 8900                    content_origin,
 8901                    editor_width,
 8902                    window,
 8903                    cx,
 8904                )
 8905            }
 8906            EditPrediction::Edit {
 8907                edits,
 8908                edit_preview,
 8909                display_mode: EditDisplayMode::DiffPopover,
 8910                snapshot,
 8911            } => self.render_edit_prediction_diff_popover(
 8912                text_bounds,
 8913                content_origin,
 8914                right_margin,
 8915                editor_snapshot,
 8916                visible_row_range,
 8917                line_layouts,
 8918                line_height,
 8919                scroll_position,
 8920                scroll_pixel_position,
 8921                newest_selection_head,
 8922                editor_width,
 8923                style,
 8924                edits,
 8925                edit_preview,
 8926                snapshot,
 8927                window,
 8928                cx,
 8929            ),
 8930            EditPrediction::MoveOutside { snapshot, .. } => {
 8931                let mut element = self
 8932                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8933                    .into_any();
 8934
 8935                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8936                let origin_x = text_bounds.size.width - size.width - px(30.);
 8937                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8938                element.prepaint_at(origin, window, cx);
 8939
 8940                Some((element, origin))
 8941            }
 8942        }
 8943    }
 8944
 8945    fn render_edit_prediction_modifier_jump_popover(
 8946        &mut self,
 8947        text_bounds: &Bounds<Pixels>,
 8948        content_origin: gpui::Point<Pixels>,
 8949        visible_row_range: Range<DisplayRow>,
 8950        line_layouts: &[LineWithInvisibles],
 8951        line_height: Pixels,
 8952        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8953        newest_selection_head: Option<DisplayPoint>,
 8954        target_display_point: DisplayPoint,
 8955        window: &mut Window,
 8956        cx: &mut App,
 8957    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8958        let scrolled_content_origin =
 8959            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8960
 8961        const SCROLL_PADDING_Y: Pixels = px(12.);
 8962
 8963        if target_display_point.row() < visible_row_range.start {
 8964            return self.render_edit_prediction_scroll_popover(
 8965                |_| SCROLL_PADDING_Y,
 8966                IconName::ArrowUp,
 8967                visible_row_range,
 8968                line_layouts,
 8969                newest_selection_head,
 8970                scrolled_content_origin,
 8971                window,
 8972                cx,
 8973            );
 8974        } else if target_display_point.row() >= visible_row_range.end {
 8975            return self.render_edit_prediction_scroll_popover(
 8976                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8977                IconName::ArrowDown,
 8978                visible_row_range,
 8979                line_layouts,
 8980                newest_selection_head,
 8981                scrolled_content_origin,
 8982                window,
 8983                cx,
 8984            );
 8985        }
 8986
 8987        const POLE_WIDTH: Pixels = px(2.);
 8988
 8989        let line_layout =
 8990            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8991        let target_column = target_display_point.column() as usize;
 8992
 8993        let target_x = line_layout.x_for_index(target_column);
 8994        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8995            - scroll_pixel_position.y;
 8996
 8997        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8998
 8999        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9000        border_color.l += 0.001;
 9001
 9002        let mut element = v_flex()
 9003            .items_end()
 9004            .when(flag_on_right, |el| el.items_start())
 9005            .child(if flag_on_right {
 9006                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9007                    .rounded_bl(px(0.))
 9008                    .rounded_tl(px(0.))
 9009                    .border_l_2()
 9010                    .border_color(border_color)
 9011            } else {
 9012                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9013                    .rounded_br(px(0.))
 9014                    .rounded_tr(px(0.))
 9015                    .border_r_2()
 9016                    .border_color(border_color)
 9017            })
 9018            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9019            .into_any();
 9020
 9021        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9022
 9023        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9024            - point(
 9025                if flag_on_right {
 9026                    POLE_WIDTH
 9027                } else {
 9028                    size.width - POLE_WIDTH
 9029                },
 9030                size.height - line_height,
 9031            );
 9032
 9033        origin.x = origin.x.max(content_origin.x);
 9034
 9035        element.prepaint_at(origin, window, cx);
 9036
 9037        Some((element, origin))
 9038    }
 9039
 9040    fn render_edit_prediction_scroll_popover(
 9041        &mut self,
 9042        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9043        scroll_icon: IconName,
 9044        visible_row_range: Range<DisplayRow>,
 9045        line_layouts: &[LineWithInvisibles],
 9046        newest_selection_head: Option<DisplayPoint>,
 9047        scrolled_content_origin: gpui::Point<Pixels>,
 9048        window: &mut Window,
 9049        cx: &mut App,
 9050    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9051        let mut element = self
 9052            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9053            .into_any();
 9054
 9055        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9056
 9057        let cursor = newest_selection_head?;
 9058        let cursor_row_layout =
 9059            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9060        let cursor_column = cursor.column() as usize;
 9061
 9062        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9063
 9064        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9065
 9066        element.prepaint_at(origin, window, cx);
 9067        Some((element, origin))
 9068    }
 9069
 9070    fn render_edit_prediction_eager_jump_popover(
 9071        &mut self,
 9072        text_bounds: &Bounds<Pixels>,
 9073        content_origin: gpui::Point<Pixels>,
 9074        editor_snapshot: &EditorSnapshot,
 9075        visible_row_range: Range<DisplayRow>,
 9076        scroll_top: ScrollOffset,
 9077        scroll_bottom: ScrollOffset,
 9078        line_height: Pixels,
 9079        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9080        target_display_point: DisplayPoint,
 9081        editor_width: Pixels,
 9082        window: &mut Window,
 9083        cx: &mut App,
 9084    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9085        if target_display_point.row().as_f64() < scroll_top {
 9086            let mut element = self
 9087                .render_edit_prediction_line_popover(
 9088                    "Jump to Edit",
 9089                    Some(IconName::ArrowUp),
 9090                    window,
 9091                    cx,
 9092                )
 9093                .into_any();
 9094
 9095            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9096            let offset = point(
 9097                (text_bounds.size.width - size.width) / 2.,
 9098                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9099            );
 9100
 9101            let origin = text_bounds.origin + offset;
 9102            element.prepaint_at(origin, window, cx);
 9103            Some((element, origin))
 9104        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9105            let mut element = self
 9106                .render_edit_prediction_line_popover(
 9107                    "Jump to Edit",
 9108                    Some(IconName::ArrowDown),
 9109                    window,
 9110                    cx,
 9111                )
 9112                .into_any();
 9113
 9114            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9115            let offset = point(
 9116                (text_bounds.size.width - size.width) / 2.,
 9117                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9118            );
 9119
 9120            let origin = text_bounds.origin + offset;
 9121            element.prepaint_at(origin, window, cx);
 9122            Some((element, origin))
 9123        } else {
 9124            self.render_edit_prediction_end_of_line_popover(
 9125                "Jump to Edit",
 9126                editor_snapshot,
 9127                visible_row_range,
 9128                target_display_point,
 9129                line_height,
 9130                scroll_pixel_position,
 9131                content_origin,
 9132                editor_width,
 9133                window,
 9134                cx,
 9135            )
 9136        }
 9137    }
 9138
 9139    fn render_edit_prediction_end_of_line_popover(
 9140        self: &mut Editor,
 9141        label: &'static str,
 9142        editor_snapshot: &EditorSnapshot,
 9143        visible_row_range: Range<DisplayRow>,
 9144        target_display_point: DisplayPoint,
 9145        line_height: Pixels,
 9146        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9147        content_origin: gpui::Point<Pixels>,
 9148        editor_width: Pixels,
 9149        window: &mut Window,
 9150        cx: &mut App,
 9151    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9152        let target_line_end = DisplayPoint::new(
 9153            target_display_point.row(),
 9154            editor_snapshot.line_len(target_display_point.row()),
 9155        );
 9156
 9157        let mut element = self
 9158            .render_edit_prediction_line_popover(label, None, window, cx)
 9159            .into_any();
 9160
 9161        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9162
 9163        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9164
 9165        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9166        let mut origin = start_point
 9167            + line_origin
 9168            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9169        origin.x = origin.x.max(content_origin.x);
 9170
 9171        let max_x = content_origin.x + editor_width - size.width;
 9172
 9173        if origin.x > max_x {
 9174            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9175
 9176            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9177                origin.y += offset;
 9178                IconName::ArrowUp
 9179            } else {
 9180                origin.y -= offset;
 9181                IconName::ArrowDown
 9182            };
 9183
 9184            element = self
 9185                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9186                .into_any();
 9187
 9188            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9189
 9190            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9191        }
 9192
 9193        element.prepaint_at(origin, window, cx);
 9194        Some((element, origin))
 9195    }
 9196
 9197    fn render_edit_prediction_diff_popover(
 9198        self: &Editor,
 9199        text_bounds: &Bounds<Pixels>,
 9200        content_origin: gpui::Point<Pixels>,
 9201        right_margin: Pixels,
 9202        editor_snapshot: &EditorSnapshot,
 9203        visible_row_range: Range<DisplayRow>,
 9204        line_layouts: &[LineWithInvisibles],
 9205        line_height: Pixels,
 9206        scroll_position: gpui::Point<ScrollOffset>,
 9207        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9208        newest_selection_head: Option<DisplayPoint>,
 9209        editor_width: Pixels,
 9210        style: &EditorStyle,
 9211        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9212        edit_preview: &Option<language::EditPreview>,
 9213        snapshot: &language::BufferSnapshot,
 9214        window: &mut Window,
 9215        cx: &mut App,
 9216    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9217        let edit_start = edits
 9218            .first()
 9219            .unwrap()
 9220            .0
 9221            .start
 9222            .to_display_point(editor_snapshot);
 9223        let edit_end = edits
 9224            .last()
 9225            .unwrap()
 9226            .0
 9227            .end
 9228            .to_display_point(editor_snapshot);
 9229
 9230        let is_visible = visible_row_range.contains(&edit_start.row())
 9231            || visible_row_range.contains(&edit_end.row());
 9232        if !is_visible {
 9233            return None;
 9234        }
 9235
 9236        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9237            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9238        } else {
 9239            // Fallback for providers without edit_preview
 9240            crate::edit_prediction_fallback_text(edits, cx)
 9241        };
 9242
 9243        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9244        let line_count = highlighted_edits.text.lines().count();
 9245
 9246        const BORDER_WIDTH: Pixels = px(1.);
 9247
 9248        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9249        let has_keybind = keybind.is_some();
 9250
 9251        let mut element = h_flex()
 9252            .items_start()
 9253            .child(
 9254                h_flex()
 9255                    .bg(cx.theme().colors().editor_background)
 9256                    .border(BORDER_WIDTH)
 9257                    .shadow_xs()
 9258                    .border_color(cx.theme().colors().border)
 9259                    .rounded_l_lg()
 9260                    .when(line_count > 1, |el| el.rounded_br_lg())
 9261                    .pr_1()
 9262                    .child(styled_text),
 9263            )
 9264            .child(
 9265                h_flex()
 9266                    .h(line_height + BORDER_WIDTH * 2.)
 9267                    .px_1p5()
 9268                    .gap_1()
 9269                    // Workaround: For some reason, there's a gap if we don't do this
 9270                    .ml(-BORDER_WIDTH)
 9271                    .shadow(vec![gpui::BoxShadow {
 9272                        color: gpui::black().opacity(0.05),
 9273                        offset: point(px(1.), px(1.)),
 9274                        blur_radius: px(2.),
 9275                        spread_radius: px(0.),
 9276                    }])
 9277                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9278                    .border(BORDER_WIDTH)
 9279                    .border_color(cx.theme().colors().border)
 9280                    .rounded_r_lg()
 9281                    .id("edit_prediction_diff_popover_keybind")
 9282                    .when(!has_keybind, |el| {
 9283                        let status_colors = cx.theme().status();
 9284
 9285                        el.bg(status_colors.error_background)
 9286                            .border_color(status_colors.error.opacity(0.6))
 9287                            .child(Icon::new(IconName::Info).color(Color::Error))
 9288                            .cursor_default()
 9289                            .hoverable_tooltip(move |_window, cx| {
 9290                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9291                            })
 9292                    })
 9293                    .children(keybind),
 9294            )
 9295            .into_any();
 9296
 9297        let longest_row =
 9298            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9299        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9300            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9301        } else {
 9302            layout_line(
 9303                longest_row,
 9304                editor_snapshot,
 9305                style,
 9306                editor_width,
 9307                |_| false,
 9308                window,
 9309                cx,
 9310            )
 9311            .width
 9312        };
 9313
 9314        let viewport_bounds =
 9315            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9316                right: -right_margin,
 9317                ..Default::default()
 9318            });
 9319
 9320        let x_after_longest = Pixels::from(
 9321            ScrollPixelOffset::from(
 9322                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9323            ) - scroll_pixel_position.x,
 9324        );
 9325
 9326        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9327
 9328        // Fully visible if it can be displayed within the window (allow overlapping other
 9329        // panes). However, this is only allowed if the popover starts within text_bounds.
 9330        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9331            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9332
 9333        let mut origin = if can_position_to_the_right {
 9334            point(
 9335                x_after_longest,
 9336                text_bounds.origin.y
 9337                    + Pixels::from(
 9338                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9339                            - scroll_pixel_position.y,
 9340                    ),
 9341            )
 9342        } else {
 9343            let cursor_row = newest_selection_head.map(|head| head.row());
 9344            let above_edit = edit_start
 9345                .row()
 9346                .0
 9347                .checked_sub(line_count as u32)
 9348                .map(DisplayRow);
 9349            let below_edit = Some(edit_end.row() + 1);
 9350            let above_cursor =
 9351                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9352            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9353
 9354            // Place the edit popover adjacent to the edit if there is a location
 9355            // available that is onscreen and does not obscure the cursor. Otherwise,
 9356            // place it adjacent to the cursor.
 9357            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9358                .into_iter()
 9359                .flatten()
 9360                .find(|&start_row| {
 9361                    let end_row = start_row + line_count as u32;
 9362                    visible_row_range.contains(&start_row)
 9363                        && visible_row_range.contains(&end_row)
 9364                        && cursor_row
 9365                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9366                })?;
 9367
 9368            content_origin
 9369                + point(
 9370                    Pixels::from(-scroll_pixel_position.x),
 9371                    Pixels::from(
 9372                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9373                    ),
 9374                )
 9375        };
 9376
 9377        origin.x -= BORDER_WIDTH;
 9378
 9379        window.defer_draw(element, origin, 1);
 9380
 9381        // Do not return an element, since it will already be drawn due to defer_draw.
 9382        None
 9383    }
 9384
 9385    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9386        px(30.)
 9387    }
 9388
 9389    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9390        if self.read_only(cx) {
 9391            cx.theme().players().read_only()
 9392        } else {
 9393            self.style.as_ref().unwrap().local_player
 9394        }
 9395    }
 9396
 9397    fn render_edit_prediction_accept_keybind(
 9398        &self,
 9399        window: &mut Window,
 9400        cx: &mut App,
 9401    ) -> Option<AnyElement> {
 9402        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9403        let accept_keystroke = accept_binding.keystroke()?;
 9404
 9405        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9406
 9407        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9408            Color::Accent
 9409        } else {
 9410            Color::Muted
 9411        };
 9412
 9413        h_flex()
 9414            .px_0p5()
 9415            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9416            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9417            .text_size(TextSize::XSmall.rems(cx))
 9418            .child(h_flex().children(ui::render_modifiers(
 9419                accept_keystroke.modifiers(),
 9420                PlatformStyle::platform(),
 9421                Some(modifiers_color),
 9422                Some(IconSize::XSmall.rems().into()),
 9423                true,
 9424            )))
 9425            .when(is_platform_style_mac, |parent| {
 9426                parent.child(accept_keystroke.key().to_string())
 9427            })
 9428            .when(!is_platform_style_mac, |parent| {
 9429                parent.child(
 9430                    Key::new(
 9431                        util::capitalize(accept_keystroke.key()),
 9432                        Some(Color::Default),
 9433                    )
 9434                    .size(Some(IconSize::XSmall.rems().into())),
 9435                )
 9436            })
 9437            .into_any()
 9438            .into()
 9439    }
 9440
 9441    fn render_edit_prediction_line_popover(
 9442        &self,
 9443        label: impl Into<SharedString>,
 9444        icon: Option<IconName>,
 9445        window: &mut Window,
 9446        cx: &mut App,
 9447    ) -> Stateful<Div> {
 9448        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9449
 9450        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9451        let has_keybind = keybind.is_some();
 9452
 9453        h_flex()
 9454            .id("ep-line-popover")
 9455            .py_0p5()
 9456            .pl_1()
 9457            .pr(padding_right)
 9458            .gap_1()
 9459            .rounded_md()
 9460            .border_1()
 9461            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9462            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9463            .shadow_xs()
 9464            .when(!has_keybind, |el| {
 9465                let status_colors = cx.theme().status();
 9466
 9467                el.bg(status_colors.error_background)
 9468                    .border_color(status_colors.error.opacity(0.6))
 9469                    .pl_2()
 9470                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9471                    .cursor_default()
 9472                    .hoverable_tooltip(move |_window, cx| {
 9473                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9474                    })
 9475            })
 9476            .children(keybind)
 9477            .child(
 9478                Label::new(label)
 9479                    .size(LabelSize::Small)
 9480                    .when(!has_keybind, |el| {
 9481                        el.color(cx.theme().status().error.into()).strikethrough()
 9482                    }),
 9483            )
 9484            .when(!has_keybind, |el| {
 9485                el.child(
 9486                    h_flex().ml_1().child(
 9487                        Icon::new(IconName::Info)
 9488                            .size(IconSize::Small)
 9489                            .color(cx.theme().status().error.into()),
 9490                    ),
 9491                )
 9492            })
 9493            .when_some(icon, |element, icon| {
 9494                element.child(
 9495                    div()
 9496                        .mt(px(1.5))
 9497                        .child(Icon::new(icon).size(IconSize::Small)),
 9498                )
 9499            })
 9500    }
 9501
 9502    fn render_edit_prediction_jump_outside_popover(
 9503        &self,
 9504        snapshot: &BufferSnapshot,
 9505        window: &mut Window,
 9506        cx: &mut App,
 9507    ) -> Stateful<Div> {
 9508        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9509        let has_keybind = keybind.is_some();
 9510
 9511        let file_name = snapshot
 9512            .file()
 9513            .map(|file| SharedString::new(file.file_name(cx)))
 9514            .unwrap_or(SharedString::new_static("untitled"));
 9515
 9516        h_flex()
 9517            .id("ep-jump-outside-popover")
 9518            .py_1()
 9519            .px_2()
 9520            .gap_1()
 9521            .rounded_md()
 9522            .border_1()
 9523            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9524            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9525            .shadow_xs()
 9526            .when(!has_keybind, |el| {
 9527                let status_colors = cx.theme().status();
 9528
 9529                el.bg(status_colors.error_background)
 9530                    .border_color(status_colors.error.opacity(0.6))
 9531                    .pl_2()
 9532                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9533                    .cursor_default()
 9534                    .hoverable_tooltip(move |_window, cx| {
 9535                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9536                    })
 9537            })
 9538            .children(keybind)
 9539            .child(
 9540                Label::new(file_name)
 9541                    .size(LabelSize::Small)
 9542                    .buffer_font(cx)
 9543                    .when(!has_keybind, |el| {
 9544                        el.color(cx.theme().status().error.into()).strikethrough()
 9545                    }),
 9546            )
 9547            .when(!has_keybind, |el| {
 9548                el.child(
 9549                    h_flex().ml_1().child(
 9550                        Icon::new(IconName::Info)
 9551                            .size(IconSize::Small)
 9552                            .color(cx.theme().status().error.into()),
 9553                    ),
 9554                )
 9555            })
 9556            .child(
 9557                div()
 9558                    .mt(px(1.5))
 9559                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9560            )
 9561    }
 9562
 9563    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9564        let accent_color = cx.theme().colors().text_accent;
 9565        let editor_bg_color = cx.theme().colors().editor_background;
 9566        editor_bg_color.blend(accent_color.opacity(0.1))
 9567    }
 9568
 9569    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9570        let accent_color = cx.theme().colors().text_accent;
 9571        let editor_bg_color = cx.theme().colors().editor_background;
 9572        editor_bg_color.blend(accent_color.opacity(0.6))
 9573    }
 9574    fn get_prediction_provider_icon_name(
 9575        provider: &Option<RegisteredEditPredictionDelegate>,
 9576    ) -> IconName {
 9577        match provider {
 9578            Some(provider) => match provider.provider.name() {
 9579                "copilot" => IconName::Copilot,
 9580                "supermaven" => IconName::Supermaven,
 9581                _ => IconName::ZedPredict,
 9582            },
 9583            None => IconName::ZedPredict,
 9584        }
 9585    }
 9586
 9587    fn render_edit_prediction_cursor_popover(
 9588        &self,
 9589        min_width: Pixels,
 9590        max_width: Pixels,
 9591        cursor_point: Point,
 9592        style: &EditorStyle,
 9593        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9594        _window: &Window,
 9595        cx: &mut Context<Editor>,
 9596    ) -> Option<AnyElement> {
 9597        let provider = self.edit_prediction_provider.as_ref()?;
 9598        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9599
 9600        let is_refreshing = provider.provider.is_refreshing(cx);
 9601
 9602        fn pending_completion_container(icon: IconName) -> Div {
 9603            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9604        }
 9605
 9606        let completion = match &self.active_edit_prediction {
 9607            Some(prediction) => {
 9608                if !self.has_visible_completions_menu() {
 9609                    const RADIUS: Pixels = px(6.);
 9610                    const BORDER_WIDTH: Pixels = px(1.);
 9611
 9612                    return Some(
 9613                        h_flex()
 9614                            .elevation_2(cx)
 9615                            .border(BORDER_WIDTH)
 9616                            .border_color(cx.theme().colors().border)
 9617                            .when(accept_keystroke.is_none(), |el| {
 9618                                el.border_color(cx.theme().status().error)
 9619                            })
 9620                            .rounded(RADIUS)
 9621                            .rounded_tl(px(0.))
 9622                            .overflow_hidden()
 9623                            .child(div().px_1p5().child(match &prediction.completion {
 9624                                EditPrediction::MoveWithin { target, snapshot } => {
 9625                                    use text::ToPoint as _;
 9626                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9627                                    {
 9628                                        Icon::new(IconName::ZedPredictDown)
 9629                                    } else {
 9630                                        Icon::new(IconName::ZedPredictUp)
 9631                                    }
 9632                                }
 9633                                EditPrediction::MoveOutside { .. } => {
 9634                                    // TODO [zeta2] custom icon for external jump?
 9635                                    Icon::new(provider_icon)
 9636                                }
 9637                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9638                            }))
 9639                            .child(
 9640                                h_flex()
 9641                                    .gap_1()
 9642                                    .py_1()
 9643                                    .px_2()
 9644                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9645                                    .border_l_1()
 9646                                    .border_color(cx.theme().colors().border)
 9647                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9648                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9649                                        el.child(
 9650                                            Label::new("Hold")
 9651                                                .size(LabelSize::Small)
 9652                                                .when(accept_keystroke.is_none(), |el| {
 9653                                                    el.strikethrough()
 9654                                                })
 9655                                                .line_height_style(LineHeightStyle::UiLabel),
 9656                                        )
 9657                                    })
 9658                                    .id("edit_prediction_cursor_popover_keybind")
 9659                                    .when(accept_keystroke.is_none(), |el| {
 9660                                        let status_colors = cx.theme().status();
 9661
 9662                                        el.bg(status_colors.error_background)
 9663                                            .border_color(status_colors.error.opacity(0.6))
 9664                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9665                                            .cursor_default()
 9666                                            .hoverable_tooltip(move |_window, cx| {
 9667                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9668                                                    .into()
 9669                                            })
 9670                                    })
 9671                                    .when_some(
 9672                                        accept_keystroke.as_ref(),
 9673                                        |el, accept_keystroke| {
 9674                                            el.child(h_flex().children(ui::render_modifiers(
 9675                                                accept_keystroke.modifiers(),
 9676                                                PlatformStyle::platform(),
 9677                                                Some(Color::Default),
 9678                                                Some(IconSize::XSmall.rems().into()),
 9679                                                false,
 9680                                            )))
 9681                                        },
 9682                                    ),
 9683                            )
 9684                            .into_any(),
 9685                    );
 9686                }
 9687
 9688                self.render_edit_prediction_cursor_popover_preview(
 9689                    prediction,
 9690                    cursor_point,
 9691                    style,
 9692                    cx,
 9693                )?
 9694            }
 9695
 9696            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9697                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9698                    stale_completion,
 9699                    cursor_point,
 9700                    style,
 9701                    cx,
 9702                )?,
 9703
 9704                None => pending_completion_container(provider_icon)
 9705                    .child(Label::new("...").size(LabelSize::Small)),
 9706            },
 9707
 9708            None => pending_completion_container(provider_icon)
 9709                .child(Label::new("...").size(LabelSize::Small)),
 9710        };
 9711
 9712        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9713            completion
 9714                .with_animation(
 9715                    "loading-completion",
 9716                    Animation::new(Duration::from_secs(2))
 9717                        .repeat()
 9718                        .with_easing(pulsating_between(0.4, 0.8)),
 9719                    |label, delta| label.opacity(delta),
 9720                )
 9721                .into_any_element()
 9722        } else {
 9723            completion.into_any_element()
 9724        };
 9725
 9726        let has_completion = self.active_edit_prediction.is_some();
 9727
 9728        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9729        Some(
 9730            h_flex()
 9731                .min_w(min_width)
 9732                .max_w(max_width)
 9733                .flex_1()
 9734                .elevation_2(cx)
 9735                .border_color(cx.theme().colors().border)
 9736                .child(
 9737                    div()
 9738                        .flex_1()
 9739                        .py_1()
 9740                        .px_2()
 9741                        .overflow_hidden()
 9742                        .child(completion),
 9743                )
 9744                .when_some(accept_keystroke, |el, accept_keystroke| {
 9745                    if !accept_keystroke.modifiers().modified() {
 9746                        return el;
 9747                    }
 9748
 9749                    el.child(
 9750                        h_flex()
 9751                            .h_full()
 9752                            .border_l_1()
 9753                            .rounded_r_lg()
 9754                            .border_color(cx.theme().colors().border)
 9755                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9756                            .gap_1()
 9757                            .py_1()
 9758                            .px_2()
 9759                            .child(
 9760                                h_flex()
 9761                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9762                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9763                                    .child(h_flex().children(ui::render_modifiers(
 9764                                        accept_keystroke.modifiers(),
 9765                                        PlatformStyle::platform(),
 9766                                        Some(if !has_completion {
 9767                                            Color::Muted
 9768                                        } else {
 9769                                            Color::Default
 9770                                        }),
 9771                                        None,
 9772                                        false,
 9773                                    ))),
 9774                            )
 9775                            .child(Label::new("Preview").into_any_element())
 9776                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9777                    )
 9778                })
 9779                .into_any(),
 9780        )
 9781    }
 9782
 9783    fn render_edit_prediction_cursor_popover_preview(
 9784        &self,
 9785        completion: &EditPredictionState,
 9786        cursor_point: Point,
 9787        style: &EditorStyle,
 9788        cx: &mut Context<Editor>,
 9789    ) -> Option<Div> {
 9790        use text::ToPoint as _;
 9791
 9792        fn render_relative_row_jump(
 9793            prefix: impl Into<String>,
 9794            current_row: u32,
 9795            target_row: u32,
 9796        ) -> Div {
 9797            let (row_diff, arrow) = if target_row < current_row {
 9798                (current_row - target_row, IconName::ArrowUp)
 9799            } else {
 9800                (target_row - current_row, IconName::ArrowDown)
 9801            };
 9802
 9803            h_flex()
 9804                .child(
 9805                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9806                        .color(Color::Muted)
 9807                        .size(LabelSize::Small),
 9808                )
 9809                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9810        }
 9811
 9812        let supports_jump = self
 9813            .edit_prediction_provider
 9814            .as_ref()
 9815            .map(|provider| provider.provider.supports_jump_to_edit())
 9816            .unwrap_or(true);
 9817
 9818        match &completion.completion {
 9819            EditPrediction::MoveWithin {
 9820                target, snapshot, ..
 9821            } => {
 9822                if !supports_jump {
 9823                    return None;
 9824                }
 9825
 9826                Some(
 9827                    h_flex()
 9828                        .px_2()
 9829                        .gap_2()
 9830                        .flex_1()
 9831                        .child(
 9832                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9833                                Icon::new(IconName::ZedPredictDown)
 9834                            } else {
 9835                                Icon::new(IconName::ZedPredictUp)
 9836                            },
 9837                        )
 9838                        .child(Label::new("Jump to Edit")),
 9839                )
 9840            }
 9841            EditPrediction::MoveOutside { snapshot, .. } => {
 9842                let file_name = snapshot
 9843                    .file()
 9844                    .map(|file| file.file_name(cx))
 9845                    .unwrap_or("untitled");
 9846                Some(
 9847                    h_flex()
 9848                        .px_2()
 9849                        .gap_2()
 9850                        .flex_1()
 9851                        .child(Icon::new(IconName::ZedPredict))
 9852                        .child(Label::new(format!("Jump to {file_name}"))),
 9853                )
 9854            }
 9855            EditPrediction::Edit {
 9856                edits,
 9857                edit_preview,
 9858                snapshot,
 9859                display_mode: _,
 9860            } => {
 9861                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9862
 9863                let (highlighted_edits, has_more_lines) =
 9864                    if let Some(edit_preview) = edit_preview.as_ref() {
 9865                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9866                            .first_line_preview()
 9867                    } else {
 9868                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9869                    };
 9870
 9871                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9872                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9873
 9874                let preview = h_flex()
 9875                    .gap_1()
 9876                    .min_w_16()
 9877                    .child(styled_text)
 9878                    .when(has_more_lines, |parent| parent.child(""));
 9879
 9880                let left = if supports_jump && first_edit_row != cursor_point.row {
 9881                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9882                        .into_any_element()
 9883                } else {
 9884                    let icon_name =
 9885                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9886                    Icon::new(icon_name).into_any_element()
 9887                };
 9888
 9889                Some(
 9890                    h_flex()
 9891                        .h_full()
 9892                        .flex_1()
 9893                        .gap_2()
 9894                        .pr_1()
 9895                        .overflow_x_hidden()
 9896                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9897                        .child(left)
 9898                        .child(preview),
 9899                )
 9900            }
 9901        }
 9902    }
 9903
 9904    pub fn render_context_menu(
 9905        &self,
 9906        style: &EditorStyle,
 9907        max_height_in_lines: u32,
 9908        window: &mut Window,
 9909        cx: &mut Context<Editor>,
 9910    ) -> Option<AnyElement> {
 9911        let menu = self.context_menu.borrow();
 9912        let menu = menu.as_ref()?;
 9913        if !menu.visible() {
 9914            return None;
 9915        };
 9916        Some(menu.render(style, max_height_in_lines, window, cx))
 9917    }
 9918
 9919    fn render_context_menu_aside(
 9920        &mut self,
 9921        max_size: Size<Pixels>,
 9922        window: &mut Window,
 9923        cx: &mut Context<Editor>,
 9924    ) -> Option<AnyElement> {
 9925        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9926            if menu.visible() {
 9927                menu.render_aside(max_size, window, cx)
 9928            } else {
 9929                None
 9930            }
 9931        })
 9932    }
 9933
 9934    fn hide_context_menu(
 9935        &mut self,
 9936        window: &mut Window,
 9937        cx: &mut Context<Self>,
 9938    ) -> Option<CodeContextMenu> {
 9939        cx.notify();
 9940        self.completion_tasks.clear();
 9941        let context_menu = self.context_menu.borrow_mut().take();
 9942        self.stale_edit_prediction_in_menu.take();
 9943        self.update_visible_edit_prediction(window, cx);
 9944        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9945            && let Some(completion_provider) = &self.completion_provider
 9946        {
 9947            completion_provider.selection_changed(None, window, cx);
 9948        }
 9949        context_menu
 9950    }
 9951
 9952    fn show_snippet_choices(
 9953        &mut self,
 9954        choices: &Vec<String>,
 9955        selection: Range<Anchor>,
 9956        cx: &mut Context<Self>,
 9957    ) {
 9958        let Some((_, buffer, _)) = self
 9959            .buffer()
 9960            .read(cx)
 9961            .excerpt_containing(selection.start, cx)
 9962        else {
 9963            return;
 9964        };
 9965        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9966        else {
 9967            return;
 9968        };
 9969        if buffer != end_buffer {
 9970            log::error!("expected anchor range to have matching buffer IDs");
 9971            return;
 9972        }
 9973
 9974        let id = post_inc(&mut self.next_completion_id);
 9975        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9976        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9977            CompletionsMenu::new_snippet_choices(
 9978                id,
 9979                true,
 9980                choices,
 9981                selection,
 9982                buffer,
 9983                snippet_sort_order,
 9984            ),
 9985        ));
 9986    }
 9987
 9988    pub fn insert_snippet(
 9989        &mut self,
 9990        insertion_ranges: &[Range<MultiBufferOffset>],
 9991        snippet: Snippet,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) -> Result<()> {
 9995        struct Tabstop<T> {
 9996            is_end_tabstop: bool,
 9997            ranges: Vec<Range<T>>,
 9998            choices: Option<Vec<String>>,
 9999        }
10000
10001        let tabstops = self.buffer.update(cx, |buffer, cx| {
10002            let snippet_text: Arc<str> = snippet.text.clone().into();
10003            let edits = insertion_ranges
10004                .iter()
10005                .cloned()
10006                .map(|range| (range, snippet_text.clone()));
10007            let autoindent_mode = AutoindentMode::Block {
10008                original_indent_columns: Vec::new(),
10009            };
10010            buffer.edit(edits, Some(autoindent_mode), cx);
10011
10012            let snapshot = &*buffer.read(cx);
10013            let snippet = &snippet;
10014            snippet
10015                .tabstops
10016                .iter()
10017                .map(|tabstop| {
10018                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10019                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10020                    });
10021                    let mut tabstop_ranges = tabstop
10022                        .ranges
10023                        .iter()
10024                        .flat_map(|tabstop_range| {
10025                            let mut delta = 0_isize;
10026                            insertion_ranges.iter().map(move |insertion_range| {
10027                                let insertion_start = insertion_range.start + delta;
10028                                delta += snippet.text.len() as isize
10029                                    - (insertion_range.end - insertion_range.start) as isize;
10030
10031                                let start =
10032                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10033                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10034                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10035                            })
10036                        })
10037                        .collect::<Vec<_>>();
10038                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10039
10040                    Tabstop {
10041                        is_end_tabstop,
10042                        ranges: tabstop_ranges,
10043                        choices: tabstop.choices.clone(),
10044                    }
10045                })
10046                .collect::<Vec<_>>()
10047        });
10048        if let Some(tabstop) = tabstops.first() {
10049            self.change_selections(Default::default(), window, cx, |s| {
10050                // Reverse order so that the first range is the newest created selection.
10051                // Completions will use it and autoscroll will prioritize it.
10052                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10053            });
10054
10055            if let Some(choices) = &tabstop.choices
10056                && let Some(selection) = tabstop.ranges.first()
10057            {
10058                self.show_snippet_choices(choices, selection.clone(), cx)
10059            }
10060
10061            // If we're already at the last tabstop and it's at the end of the snippet,
10062            // we're done, we don't need to keep the state around.
10063            if !tabstop.is_end_tabstop {
10064                let choices = tabstops
10065                    .iter()
10066                    .map(|tabstop| tabstop.choices.clone())
10067                    .collect();
10068
10069                let ranges = tabstops
10070                    .into_iter()
10071                    .map(|tabstop| tabstop.ranges)
10072                    .collect::<Vec<_>>();
10073
10074                self.snippet_stack.push(SnippetState {
10075                    active_index: 0,
10076                    ranges,
10077                    choices,
10078                });
10079            }
10080
10081            // Check whether the just-entered snippet ends with an auto-closable bracket.
10082            if self.autoclose_regions.is_empty() {
10083                let snapshot = self.buffer.read(cx).snapshot(cx);
10084                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10085                    let selection_head = selection.head();
10086                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10087                        continue;
10088                    };
10089
10090                    let mut bracket_pair = None;
10091                    let max_lookup_length = scope
10092                        .brackets()
10093                        .map(|(pair, _)| {
10094                            pair.start
10095                                .as_str()
10096                                .chars()
10097                                .count()
10098                                .max(pair.end.as_str().chars().count())
10099                        })
10100                        .max();
10101                    if let Some(max_lookup_length) = max_lookup_length {
10102                        let next_text = snapshot
10103                            .chars_at(selection_head)
10104                            .take(max_lookup_length)
10105                            .collect::<String>();
10106                        let prev_text = snapshot
10107                            .reversed_chars_at(selection_head)
10108                            .take(max_lookup_length)
10109                            .collect::<String>();
10110
10111                        for (pair, enabled) in scope.brackets() {
10112                            if enabled
10113                                && pair.close
10114                                && prev_text.starts_with(pair.start.as_str())
10115                                && next_text.starts_with(pair.end.as_str())
10116                            {
10117                                bracket_pair = Some(pair.clone());
10118                                break;
10119                            }
10120                        }
10121                    }
10122
10123                    if let Some(pair) = bracket_pair {
10124                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10125                        let autoclose_enabled =
10126                            self.use_autoclose && snapshot_settings.use_autoclose;
10127                        if autoclose_enabled {
10128                            let start = snapshot.anchor_after(selection_head);
10129                            let end = snapshot.anchor_after(selection_head);
10130                            self.autoclose_regions.push(AutocloseRegion {
10131                                selection_id: selection.id,
10132                                range: start..end,
10133                                pair,
10134                            });
10135                        }
10136                    }
10137                }
10138            }
10139        }
10140        Ok(())
10141    }
10142
10143    pub fn move_to_next_snippet_tabstop(
10144        &mut self,
10145        window: &mut Window,
10146        cx: &mut Context<Self>,
10147    ) -> bool {
10148        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10149    }
10150
10151    pub fn move_to_prev_snippet_tabstop(
10152        &mut self,
10153        window: &mut Window,
10154        cx: &mut Context<Self>,
10155    ) -> bool {
10156        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10157    }
10158
10159    pub fn move_to_snippet_tabstop(
10160        &mut self,
10161        bias: Bias,
10162        window: &mut Window,
10163        cx: &mut Context<Self>,
10164    ) -> bool {
10165        if let Some(mut snippet) = self.snippet_stack.pop() {
10166            match bias {
10167                Bias::Left => {
10168                    if snippet.active_index > 0 {
10169                        snippet.active_index -= 1;
10170                    } else {
10171                        self.snippet_stack.push(snippet);
10172                        return false;
10173                    }
10174                }
10175                Bias::Right => {
10176                    if snippet.active_index + 1 < snippet.ranges.len() {
10177                        snippet.active_index += 1;
10178                    } else {
10179                        self.snippet_stack.push(snippet);
10180                        return false;
10181                    }
10182                }
10183            }
10184            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10185                self.change_selections(Default::default(), window, cx, |s| {
10186                    // Reverse order so that the first range is the newest created selection.
10187                    // Completions will use it and autoscroll will prioritize it.
10188                    s.select_ranges(current_ranges.iter().rev().cloned())
10189                });
10190
10191                if let Some(choices) = &snippet.choices[snippet.active_index]
10192                    && let Some(selection) = current_ranges.first()
10193                {
10194                    self.show_snippet_choices(choices, selection.clone(), cx);
10195                }
10196
10197                // If snippet state is not at the last tabstop, push it back on the stack
10198                if snippet.active_index + 1 < snippet.ranges.len() {
10199                    self.snippet_stack.push(snippet);
10200                }
10201                return true;
10202            }
10203        }
10204
10205        false
10206    }
10207
10208    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10209        self.transact(window, cx, |this, window, cx| {
10210            this.select_all(&SelectAll, window, cx);
10211            this.insert("", window, cx);
10212        });
10213    }
10214
10215    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10216        if self.read_only(cx) {
10217            return;
10218        }
10219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10220        self.transact(window, cx, |this, window, cx| {
10221            this.select_autoclose_pair(window, cx);
10222
10223            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10224
10225            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10226            if !this.linked_edit_ranges.is_empty() {
10227                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10228                let snapshot = this.buffer.read(cx).snapshot(cx);
10229
10230                for selection in selections.iter() {
10231                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10232                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10233                    if selection_start.buffer_id != selection_end.buffer_id {
10234                        continue;
10235                    }
10236                    if let Some(ranges) =
10237                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10238                    {
10239                        for (buffer, entries) in ranges {
10240                            linked_ranges.entry(buffer).or_default().extend(entries);
10241                        }
10242                    }
10243                }
10244            }
10245
10246            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10247            for selection in &mut selections {
10248                if selection.is_empty() {
10249                    let old_head = selection.head();
10250                    let mut new_head =
10251                        movement::left(&display_map, old_head.to_display_point(&display_map))
10252                            .to_point(&display_map);
10253                    if let Some((buffer, line_buffer_range)) = display_map
10254                        .buffer_snapshot()
10255                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10256                    {
10257                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10258                        let indent_len = match indent_size.kind {
10259                            IndentKind::Space => {
10260                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10261                            }
10262                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10263                        };
10264                        if old_head.column <= indent_size.len && old_head.column > 0 {
10265                            let indent_len = indent_len.get();
10266                            new_head = cmp::min(
10267                                new_head,
10268                                MultiBufferPoint::new(
10269                                    old_head.row,
10270                                    ((old_head.column - 1) / indent_len) * indent_len,
10271                                ),
10272                            );
10273                        }
10274                    }
10275
10276                    selection.set_head(new_head, SelectionGoal::None);
10277                }
10278            }
10279
10280            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10281            this.insert("", window, cx);
10282            let empty_str: Arc<str> = Arc::from("");
10283            for (buffer, edits) in linked_ranges {
10284                let snapshot = buffer.read(cx).snapshot();
10285                use text::ToPoint as TP;
10286
10287                let edits = edits
10288                    .into_iter()
10289                    .map(|range| {
10290                        let end_point = TP::to_point(&range.end, &snapshot);
10291                        let mut start_point = TP::to_point(&range.start, &snapshot);
10292
10293                        if end_point == start_point {
10294                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10295                                .saturating_sub(1);
10296                            start_point =
10297                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10298                        };
10299
10300                        (start_point..end_point, empty_str.clone())
10301                    })
10302                    .sorted_by_key(|(range, _)| range.start)
10303                    .collect::<Vec<_>>();
10304                buffer.update(cx, |this, cx| {
10305                    this.edit(edits, None, cx);
10306                })
10307            }
10308            this.refresh_edit_prediction(true, false, window, cx);
10309            refresh_linked_ranges(this, window, cx);
10310        });
10311    }
10312
10313    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10314        if self.read_only(cx) {
10315            return;
10316        }
10317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10318        self.transact(window, cx, |this, window, cx| {
10319            this.change_selections(Default::default(), window, cx, |s| {
10320                s.move_with(|map, selection| {
10321                    if selection.is_empty() {
10322                        let cursor = movement::right(map, selection.head());
10323                        selection.end = cursor;
10324                        selection.reversed = true;
10325                        selection.goal = SelectionGoal::None;
10326                    }
10327                })
10328            });
10329            this.insert("", window, cx);
10330            this.refresh_edit_prediction(true, false, window, cx);
10331        });
10332    }
10333
10334    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10335        if self.mode.is_single_line() {
10336            cx.propagate();
10337            return;
10338        }
10339
10340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10341        if self.move_to_prev_snippet_tabstop(window, cx) {
10342            return;
10343        }
10344        self.outdent(&Outdent, window, cx);
10345    }
10346
10347    pub fn next_snippet_tabstop(
10348        &mut self,
10349        _: &NextSnippetTabstop,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) {
10353        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10354            cx.propagate();
10355            return;
10356        }
10357
10358        if self.move_to_next_snippet_tabstop(window, cx) {
10359            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10360            return;
10361        }
10362        cx.propagate();
10363    }
10364
10365    pub fn previous_snippet_tabstop(
10366        &mut self,
10367        _: &PreviousSnippetTabstop,
10368        window: &mut Window,
10369        cx: &mut Context<Self>,
10370    ) {
10371        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10372            cx.propagate();
10373            return;
10374        }
10375
10376        if self.move_to_prev_snippet_tabstop(window, cx) {
10377            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10378            return;
10379        }
10380        cx.propagate();
10381    }
10382
10383    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10384        if self.mode.is_single_line() {
10385            cx.propagate();
10386            return;
10387        }
10388
10389        if self.move_to_next_snippet_tabstop(window, cx) {
10390            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10391            return;
10392        }
10393        if self.read_only(cx) {
10394            return;
10395        }
10396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10397        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10398        let buffer = self.buffer.read(cx);
10399        let snapshot = buffer.snapshot(cx);
10400        let rows_iter = selections.iter().map(|s| s.head().row);
10401        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10402
10403        let has_some_cursor_in_whitespace = selections
10404            .iter()
10405            .filter(|selection| selection.is_empty())
10406            .any(|selection| {
10407                let cursor = selection.head();
10408                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10409                cursor.column < current_indent.len
10410            });
10411
10412        let mut edits = Vec::new();
10413        let mut prev_edited_row = 0;
10414        let mut row_delta = 0;
10415        for selection in &mut selections {
10416            if selection.start.row != prev_edited_row {
10417                row_delta = 0;
10418            }
10419            prev_edited_row = selection.end.row;
10420
10421            // If the selection is non-empty, then increase the indentation of the selected lines.
10422            if !selection.is_empty() {
10423                row_delta =
10424                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10425                continue;
10426            }
10427
10428            let cursor = selection.head();
10429            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10430            if let Some(suggested_indent) =
10431                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10432            {
10433                // Don't do anything if already at suggested indent
10434                // and there is any other cursor which is not
10435                if has_some_cursor_in_whitespace
10436                    && cursor.column == current_indent.len
10437                    && current_indent.len == suggested_indent.len
10438                {
10439                    continue;
10440                }
10441
10442                // Adjust line and move cursor to suggested indent
10443                // if cursor is not at suggested indent
10444                if cursor.column < suggested_indent.len
10445                    && cursor.column <= current_indent.len
10446                    && current_indent.len <= suggested_indent.len
10447                {
10448                    selection.start = Point::new(cursor.row, suggested_indent.len);
10449                    selection.end = selection.start;
10450                    if row_delta == 0 {
10451                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10452                            cursor.row,
10453                            current_indent,
10454                            suggested_indent,
10455                        ));
10456                        row_delta = suggested_indent.len - current_indent.len;
10457                    }
10458                    continue;
10459                }
10460
10461                // If current indent is more than suggested indent
10462                // only move cursor to current indent and skip indent
10463                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10464                    selection.start = Point::new(cursor.row, current_indent.len);
10465                    selection.end = selection.start;
10466                    continue;
10467                }
10468            }
10469
10470            // Otherwise, insert a hard or soft tab.
10471            let settings = buffer.language_settings_at(cursor, cx);
10472            let tab_size = if settings.hard_tabs {
10473                IndentSize::tab()
10474            } else {
10475                let tab_size = settings.tab_size.get();
10476                let indent_remainder = snapshot
10477                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10478                    .flat_map(str::chars)
10479                    .fold(row_delta % tab_size, |counter: u32, c| {
10480                        if c == '\t' {
10481                            0
10482                        } else {
10483                            (counter + 1) % tab_size
10484                        }
10485                    });
10486
10487                let chars_to_next_tab_stop = tab_size - indent_remainder;
10488                IndentSize::spaces(chars_to_next_tab_stop)
10489            };
10490            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10491            selection.end = selection.start;
10492            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10493            row_delta += tab_size.len;
10494        }
10495
10496        self.transact(window, cx, |this, window, cx| {
10497            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10498            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10499            this.refresh_edit_prediction(true, false, window, cx);
10500        });
10501    }
10502
10503    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10504        if self.read_only(cx) {
10505            return;
10506        }
10507        if self.mode.is_single_line() {
10508            cx.propagate();
10509            return;
10510        }
10511
10512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10513        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10514        let mut prev_edited_row = 0;
10515        let mut row_delta = 0;
10516        let mut edits = Vec::new();
10517        let buffer = self.buffer.read(cx);
10518        let snapshot = buffer.snapshot(cx);
10519        for selection in &mut selections {
10520            if selection.start.row != prev_edited_row {
10521                row_delta = 0;
10522            }
10523            prev_edited_row = selection.end.row;
10524
10525            row_delta =
10526                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10527        }
10528
10529        self.transact(window, cx, |this, window, cx| {
10530            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10531            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10532        });
10533    }
10534
10535    fn indent_selection(
10536        buffer: &MultiBuffer,
10537        snapshot: &MultiBufferSnapshot,
10538        selection: &mut Selection<Point>,
10539        edits: &mut Vec<(Range<Point>, String)>,
10540        delta_for_start_row: u32,
10541        cx: &App,
10542    ) -> u32 {
10543        let settings = buffer.language_settings_at(selection.start, cx);
10544        let tab_size = settings.tab_size.get();
10545        let indent_kind = if settings.hard_tabs {
10546            IndentKind::Tab
10547        } else {
10548            IndentKind::Space
10549        };
10550        let mut start_row = selection.start.row;
10551        let mut end_row = selection.end.row + 1;
10552
10553        // If a selection ends at the beginning of a line, don't indent
10554        // that last line.
10555        if selection.end.column == 0 && selection.end.row > selection.start.row {
10556            end_row -= 1;
10557        }
10558
10559        // Avoid re-indenting a row that has already been indented by a
10560        // previous selection, but still update this selection's column
10561        // to reflect that indentation.
10562        if delta_for_start_row > 0 {
10563            start_row += 1;
10564            selection.start.column += delta_for_start_row;
10565            if selection.end.row == selection.start.row {
10566                selection.end.column += delta_for_start_row;
10567            }
10568        }
10569
10570        let mut delta_for_end_row = 0;
10571        let has_multiple_rows = start_row + 1 != end_row;
10572        for row in start_row..end_row {
10573            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10574            let indent_delta = match (current_indent.kind, indent_kind) {
10575                (IndentKind::Space, IndentKind::Space) => {
10576                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10577                    IndentSize::spaces(columns_to_next_tab_stop)
10578                }
10579                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10580                (_, IndentKind::Tab) => IndentSize::tab(),
10581            };
10582
10583            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10584                0
10585            } else {
10586                selection.start.column
10587            };
10588            let row_start = Point::new(row, start);
10589            edits.push((
10590                row_start..row_start,
10591                indent_delta.chars().collect::<String>(),
10592            ));
10593
10594            // Update this selection's endpoints to reflect the indentation.
10595            if row == selection.start.row {
10596                selection.start.column += indent_delta.len;
10597            }
10598            if row == selection.end.row {
10599                selection.end.column += indent_delta.len;
10600                delta_for_end_row = indent_delta.len;
10601            }
10602        }
10603
10604        if selection.start.row == selection.end.row {
10605            delta_for_start_row + delta_for_end_row
10606        } else {
10607            delta_for_end_row
10608        }
10609    }
10610
10611    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10612        if self.read_only(cx) {
10613            return;
10614        }
10615        if self.mode.is_single_line() {
10616            cx.propagate();
10617            return;
10618        }
10619
10620        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10622        let selections = self.selections.all::<Point>(&display_map);
10623        let mut deletion_ranges = Vec::new();
10624        let mut last_outdent = None;
10625        {
10626            let buffer = self.buffer.read(cx);
10627            let snapshot = buffer.snapshot(cx);
10628            for selection in &selections {
10629                let settings = buffer.language_settings_at(selection.start, cx);
10630                let tab_size = settings.tab_size.get();
10631                let mut rows = selection.spanned_rows(false, &display_map);
10632
10633                // Avoid re-outdenting a row that has already been outdented by a
10634                // previous selection.
10635                if let Some(last_row) = last_outdent
10636                    && last_row == rows.start
10637                {
10638                    rows.start = rows.start.next_row();
10639                }
10640                let has_multiple_rows = rows.len() > 1;
10641                for row in rows.iter_rows() {
10642                    let indent_size = snapshot.indent_size_for_line(row);
10643                    if indent_size.len > 0 {
10644                        let deletion_len = match indent_size.kind {
10645                            IndentKind::Space => {
10646                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10647                                if columns_to_prev_tab_stop == 0 {
10648                                    tab_size
10649                                } else {
10650                                    columns_to_prev_tab_stop
10651                                }
10652                            }
10653                            IndentKind::Tab => 1,
10654                        };
10655                        let start = if has_multiple_rows
10656                            || deletion_len > selection.start.column
10657                            || indent_size.len < selection.start.column
10658                        {
10659                            0
10660                        } else {
10661                            selection.start.column - deletion_len
10662                        };
10663                        deletion_ranges.push(
10664                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10665                        );
10666                        last_outdent = Some(row);
10667                    }
10668                }
10669            }
10670        }
10671
10672        self.transact(window, cx, |this, window, cx| {
10673            this.buffer.update(cx, |buffer, cx| {
10674                let empty_str: Arc<str> = Arc::default();
10675                buffer.edit(
10676                    deletion_ranges
10677                        .into_iter()
10678                        .map(|range| (range, empty_str.clone())),
10679                    None,
10680                    cx,
10681                );
10682            });
10683            let selections = this
10684                .selections
10685                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10686            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10687        });
10688    }
10689
10690    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10691        if self.read_only(cx) {
10692            return;
10693        }
10694        if self.mode.is_single_line() {
10695            cx.propagate();
10696            return;
10697        }
10698
10699        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10700        let selections = self
10701            .selections
10702            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10703            .into_iter()
10704            .map(|s| s.range());
10705
10706        self.transact(window, cx, |this, window, cx| {
10707            this.buffer.update(cx, |buffer, cx| {
10708                buffer.autoindent_ranges(selections, cx);
10709            });
10710            let selections = this
10711                .selections
10712                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10713            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10714        });
10715    }
10716
10717    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10718        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10719        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10720        let selections = self.selections.all::<Point>(&display_map);
10721
10722        let mut new_cursors = Vec::new();
10723        let mut edit_ranges = Vec::new();
10724        let mut selections = selections.iter().peekable();
10725        while let Some(selection) = selections.next() {
10726            let mut rows = selection.spanned_rows(false, &display_map);
10727
10728            // Accumulate contiguous regions of rows that we want to delete.
10729            while let Some(next_selection) = selections.peek() {
10730                let next_rows = next_selection.spanned_rows(false, &display_map);
10731                if next_rows.start <= rows.end {
10732                    rows.end = next_rows.end;
10733                    selections.next().unwrap();
10734                } else {
10735                    break;
10736                }
10737            }
10738
10739            let buffer = display_map.buffer_snapshot();
10740            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10741            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10742                // If there's a line after the range, delete the \n from the end of the row range
10743                (
10744                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10745                    rows.end,
10746                )
10747            } else {
10748                // If there isn't a line after the range, delete the \n from the line before the
10749                // start of the row range
10750                edit_start = edit_start.saturating_sub_usize(1);
10751                (buffer.len(), rows.start.previous_row())
10752            };
10753
10754            let text_layout_details = self.text_layout_details(window);
10755            let x = display_map.x_for_display_point(
10756                selection.head().to_display_point(&display_map),
10757                &text_layout_details,
10758            );
10759            let row = Point::new(target_row.0, 0)
10760                .to_display_point(&display_map)
10761                .row();
10762            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10763
10764            new_cursors.push((
10765                selection.id,
10766                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10767                SelectionGoal::None,
10768            ));
10769            edit_ranges.push(edit_start..edit_end);
10770        }
10771
10772        self.transact(window, cx, |this, window, cx| {
10773            let buffer = this.buffer.update(cx, |buffer, cx| {
10774                let empty_str: Arc<str> = Arc::default();
10775                buffer.edit(
10776                    edit_ranges
10777                        .into_iter()
10778                        .map(|range| (range, empty_str.clone())),
10779                    None,
10780                    cx,
10781                );
10782                buffer.snapshot(cx)
10783            });
10784            let new_selections = new_cursors
10785                .into_iter()
10786                .map(|(id, cursor, goal)| {
10787                    let cursor = cursor.to_point(&buffer);
10788                    Selection {
10789                        id,
10790                        start: cursor,
10791                        end: cursor,
10792                        reversed: false,
10793                        goal,
10794                    }
10795                })
10796                .collect();
10797
10798            this.change_selections(Default::default(), window, cx, |s| {
10799                s.select(new_selections);
10800            });
10801        });
10802    }
10803
10804    pub fn join_lines_impl(
10805        &mut self,
10806        insert_whitespace: bool,
10807        window: &mut Window,
10808        cx: &mut Context<Self>,
10809    ) {
10810        if self.read_only(cx) {
10811            return;
10812        }
10813        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10814        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10815            let start = MultiBufferRow(selection.start.row);
10816            // Treat single line selections as if they include the next line. Otherwise this action
10817            // would do nothing for single line selections individual cursors.
10818            let end = if selection.start.row == selection.end.row {
10819                MultiBufferRow(selection.start.row + 1)
10820            } else {
10821                MultiBufferRow(selection.end.row)
10822            };
10823
10824            if let Some(last_row_range) = row_ranges.last_mut()
10825                && start <= last_row_range.end
10826            {
10827                last_row_range.end = end;
10828                continue;
10829            }
10830            row_ranges.push(start..end);
10831        }
10832
10833        let snapshot = self.buffer.read(cx).snapshot(cx);
10834        let mut cursor_positions = Vec::new();
10835        for row_range in &row_ranges {
10836            let anchor = snapshot.anchor_before(Point::new(
10837                row_range.end.previous_row().0,
10838                snapshot.line_len(row_range.end.previous_row()),
10839            ));
10840            cursor_positions.push(anchor..anchor);
10841        }
10842
10843        self.transact(window, cx, |this, window, cx| {
10844            for row_range in row_ranges.into_iter().rev() {
10845                for row in row_range.iter_rows().rev() {
10846                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10847                    let next_line_row = row.next_row();
10848                    let indent = snapshot.indent_size_for_line(next_line_row);
10849                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10850
10851                    let replace =
10852                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10853                            " "
10854                        } else {
10855                            ""
10856                        };
10857
10858                    this.buffer.update(cx, |buffer, cx| {
10859                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10860                    });
10861                }
10862            }
10863
10864            this.change_selections(Default::default(), window, cx, |s| {
10865                s.select_anchor_ranges(cursor_positions)
10866            });
10867        });
10868    }
10869
10870    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10871        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10872        self.join_lines_impl(true, window, cx);
10873    }
10874
10875    pub fn sort_lines_case_sensitive(
10876        &mut self,
10877        _: &SortLinesCaseSensitive,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10882    }
10883
10884    pub fn sort_lines_by_length(
10885        &mut self,
10886        _: &SortLinesByLength,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        self.manipulate_immutable_lines(window, cx, |lines| {
10891            lines.sort_by_key(|&line| line.chars().count())
10892        })
10893    }
10894
10895    pub fn sort_lines_case_insensitive(
10896        &mut self,
10897        _: &SortLinesCaseInsensitive,
10898        window: &mut Window,
10899        cx: &mut Context<Self>,
10900    ) {
10901        self.manipulate_immutable_lines(window, cx, |lines| {
10902            lines.sort_by_key(|line| line.to_lowercase())
10903        })
10904    }
10905
10906    pub fn unique_lines_case_insensitive(
10907        &mut self,
10908        _: &UniqueLinesCaseInsensitive,
10909        window: &mut Window,
10910        cx: &mut Context<Self>,
10911    ) {
10912        self.manipulate_immutable_lines(window, cx, |lines| {
10913            let mut seen = HashSet::default();
10914            lines.retain(|line| seen.insert(line.to_lowercase()));
10915        })
10916    }
10917
10918    pub fn unique_lines_case_sensitive(
10919        &mut self,
10920        _: &UniqueLinesCaseSensitive,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        self.manipulate_immutable_lines(window, cx, |lines| {
10925            let mut seen = HashSet::default();
10926            lines.retain(|line| seen.insert(*line));
10927        })
10928    }
10929
10930    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10931        let snapshot = self.buffer.read(cx).snapshot(cx);
10932        for selection in self.selections.disjoint_anchors_arc().iter() {
10933            if snapshot
10934                .language_at(selection.start)
10935                .and_then(|lang| lang.config().wrap_characters.as_ref())
10936                .is_some()
10937            {
10938                return true;
10939            }
10940        }
10941        false
10942    }
10943
10944    fn wrap_selections_in_tag(
10945        &mut self,
10946        _: &WrapSelectionsInTag,
10947        window: &mut Window,
10948        cx: &mut Context<Self>,
10949    ) {
10950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10951
10952        let snapshot = self.buffer.read(cx).snapshot(cx);
10953
10954        let mut edits = Vec::new();
10955        let mut boundaries = Vec::new();
10956
10957        for selection in self
10958            .selections
10959            .all_adjusted(&self.display_snapshot(cx))
10960            .iter()
10961        {
10962            let Some(wrap_config) = snapshot
10963                .language_at(selection.start)
10964                .and_then(|lang| lang.config().wrap_characters.clone())
10965            else {
10966                continue;
10967            };
10968
10969            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10970            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10971
10972            let start_before = snapshot.anchor_before(selection.start);
10973            let end_after = snapshot.anchor_after(selection.end);
10974
10975            edits.push((start_before..start_before, open_tag));
10976            edits.push((end_after..end_after, close_tag));
10977
10978            boundaries.push((
10979                start_before,
10980                end_after,
10981                wrap_config.start_prefix.len(),
10982                wrap_config.end_suffix.len(),
10983            ));
10984        }
10985
10986        if edits.is_empty() {
10987            return;
10988        }
10989
10990        self.transact(window, cx, |this, window, cx| {
10991            let buffer = this.buffer.update(cx, |buffer, cx| {
10992                buffer.edit(edits, None, cx);
10993                buffer.snapshot(cx)
10994            });
10995
10996            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10997            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10998                boundaries.into_iter()
10999            {
11000                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11001                let close_offset = end_after
11002                    .to_offset(&buffer)
11003                    .saturating_sub_usize(end_suffix_len);
11004                new_selections.push(open_offset..open_offset);
11005                new_selections.push(close_offset..close_offset);
11006            }
11007
11008            this.change_selections(Default::default(), window, cx, |s| {
11009                s.select_ranges(new_selections);
11010            });
11011
11012            this.request_autoscroll(Autoscroll::fit(), cx);
11013        });
11014    }
11015
11016    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11017        let Some(project) = self.project.clone() else {
11018            return;
11019        };
11020        self.reload(project, window, cx)
11021            .detach_and_notify_err(window, cx);
11022    }
11023
11024    pub fn restore_file(
11025        &mut self,
11026        _: &::git::RestoreFile,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029    ) {
11030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11031        let mut buffer_ids = HashSet::default();
11032        let snapshot = self.buffer().read(cx).snapshot(cx);
11033        for selection in self
11034            .selections
11035            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11036        {
11037            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11038        }
11039
11040        let buffer = self.buffer().read(cx);
11041        let ranges = buffer_ids
11042            .into_iter()
11043            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11044            .collect::<Vec<_>>();
11045
11046        self.restore_hunks_in_ranges(ranges, window, cx);
11047    }
11048
11049    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11050        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11051        let selections = self
11052            .selections
11053            .all(&self.display_snapshot(cx))
11054            .into_iter()
11055            .map(|s| s.range())
11056            .collect();
11057        self.restore_hunks_in_ranges(selections, window, cx);
11058    }
11059
11060    pub fn restore_hunks_in_ranges(
11061        &mut self,
11062        ranges: Vec<Range<Point>>,
11063        window: &mut Window,
11064        cx: &mut Context<Editor>,
11065    ) {
11066        let mut revert_changes = HashMap::default();
11067        let chunk_by = self
11068            .snapshot(window, cx)
11069            .hunks_for_ranges(ranges)
11070            .into_iter()
11071            .chunk_by(|hunk| hunk.buffer_id);
11072        for (buffer_id, hunks) in &chunk_by {
11073            let hunks = hunks.collect::<Vec<_>>();
11074            for hunk in &hunks {
11075                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11076            }
11077            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11078        }
11079        drop(chunk_by);
11080        if !revert_changes.is_empty() {
11081            self.transact(window, cx, |editor, window, cx| {
11082                editor.restore(revert_changes, window, cx);
11083            });
11084        }
11085    }
11086
11087    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11088        if let Some(status) = self
11089            .addons
11090            .iter()
11091            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11092        {
11093            return Some(status);
11094        }
11095        self.project
11096            .as_ref()?
11097            .read(cx)
11098            .status_for_buffer_id(buffer_id, cx)
11099    }
11100
11101    pub fn open_active_item_in_terminal(
11102        &mut self,
11103        _: &OpenInTerminal,
11104        window: &mut Window,
11105        cx: &mut Context<Self>,
11106    ) {
11107        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11108            let project_path = buffer.read(cx).project_path(cx)?;
11109            let project = self.project()?.read(cx);
11110            let entry = project.entry_for_path(&project_path, cx)?;
11111            let parent = match &entry.canonical_path {
11112                Some(canonical_path) => canonical_path.to_path_buf(),
11113                None => project.absolute_path(&project_path, cx)?,
11114            }
11115            .parent()?
11116            .to_path_buf();
11117            Some(parent)
11118        }) {
11119            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11120        }
11121    }
11122
11123    fn set_breakpoint_context_menu(
11124        &mut self,
11125        display_row: DisplayRow,
11126        position: Option<Anchor>,
11127        clicked_point: gpui::Point<Pixels>,
11128        window: &mut Window,
11129        cx: &mut Context<Self>,
11130    ) {
11131        let source = self
11132            .buffer
11133            .read(cx)
11134            .snapshot(cx)
11135            .anchor_before(Point::new(display_row.0, 0u32));
11136
11137        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11138
11139        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11140            self,
11141            source,
11142            clicked_point,
11143            context_menu,
11144            window,
11145            cx,
11146        );
11147    }
11148
11149    fn add_edit_breakpoint_block(
11150        &mut self,
11151        anchor: Anchor,
11152        breakpoint: &Breakpoint,
11153        edit_action: BreakpointPromptEditAction,
11154        window: &mut Window,
11155        cx: &mut Context<Self>,
11156    ) {
11157        let weak_editor = cx.weak_entity();
11158        let bp_prompt = cx.new(|cx| {
11159            BreakpointPromptEditor::new(
11160                weak_editor,
11161                anchor,
11162                breakpoint.clone(),
11163                edit_action,
11164                window,
11165                cx,
11166            )
11167        });
11168
11169        let height = bp_prompt.update(cx, |this, cx| {
11170            this.prompt
11171                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11172        });
11173        let cloned_prompt = bp_prompt.clone();
11174        let blocks = vec![BlockProperties {
11175            style: BlockStyle::Sticky,
11176            placement: BlockPlacement::Above(anchor),
11177            height: Some(height),
11178            render: Arc::new(move |cx| {
11179                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11180                cloned_prompt.clone().into_any_element()
11181            }),
11182            priority: 0,
11183        }];
11184
11185        let focus_handle = bp_prompt.focus_handle(cx);
11186        window.focus(&focus_handle);
11187
11188        let block_ids = self.insert_blocks(blocks, None, cx);
11189        bp_prompt.update(cx, |prompt, _| {
11190            prompt.add_block_ids(block_ids);
11191        });
11192    }
11193
11194    pub(crate) fn breakpoint_at_row(
11195        &self,
11196        row: u32,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) -> Option<(Anchor, Breakpoint)> {
11200        let snapshot = self.snapshot(window, cx);
11201        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11202
11203        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11204    }
11205
11206    pub(crate) fn breakpoint_at_anchor(
11207        &self,
11208        breakpoint_position: Anchor,
11209        snapshot: &EditorSnapshot,
11210        cx: &mut Context<Self>,
11211    ) -> Option<(Anchor, Breakpoint)> {
11212        let buffer = self
11213            .buffer
11214            .read(cx)
11215            .buffer_for_anchor(breakpoint_position, cx)?;
11216
11217        let enclosing_excerpt = breakpoint_position.excerpt_id;
11218        let buffer_snapshot = buffer.read(cx).snapshot();
11219
11220        let row = buffer_snapshot
11221            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11222            .row;
11223
11224        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11225        let anchor_end = snapshot
11226            .buffer_snapshot()
11227            .anchor_after(Point::new(row, line_len));
11228
11229        self.breakpoint_store
11230            .as_ref()?
11231            .read_with(cx, |breakpoint_store, cx| {
11232                breakpoint_store
11233                    .breakpoints(
11234                        &buffer,
11235                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11236                        &buffer_snapshot,
11237                        cx,
11238                    )
11239                    .next()
11240                    .and_then(|(bp, _)| {
11241                        let breakpoint_row = buffer_snapshot
11242                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11243                            .row;
11244
11245                        if breakpoint_row == row {
11246                            snapshot
11247                                .buffer_snapshot()
11248                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11249                                .map(|position| (position, bp.bp.clone()))
11250                        } else {
11251                            None
11252                        }
11253                    })
11254            })
11255    }
11256
11257    pub fn edit_log_breakpoint(
11258        &mut self,
11259        _: &EditLogBreakpoint,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262    ) {
11263        if self.breakpoint_store.is_none() {
11264            return;
11265        }
11266
11267        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11268            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11269                message: None,
11270                state: BreakpointState::Enabled,
11271                condition: None,
11272                hit_condition: None,
11273            });
11274
11275            self.add_edit_breakpoint_block(
11276                anchor,
11277                &breakpoint,
11278                BreakpointPromptEditAction::Log,
11279                window,
11280                cx,
11281            );
11282        }
11283    }
11284
11285    fn breakpoints_at_cursors(
11286        &self,
11287        window: &mut Window,
11288        cx: &mut Context<Self>,
11289    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11290        let snapshot = self.snapshot(window, cx);
11291        let cursors = self
11292            .selections
11293            .disjoint_anchors_arc()
11294            .iter()
11295            .map(|selection| {
11296                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11297
11298                let breakpoint_position = self
11299                    .breakpoint_at_row(cursor_position.row, window, cx)
11300                    .map(|bp| bp.0)
11301                    .unwrap_or_else(|| {
11302                        snapshot
11303                            .display_snapshot
11304                            .buffer_snapshot()
11305                            .anchor_after(Point::new(cursor_position.row, 0))
11306                    });
11307
11308                let breakpoint = self
11309                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11310                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11311
11312                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11313            })
11314            // 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.
11315            .collect::<HashMap<Anchor, _>>();
11316
11317        cursors.into_iter().collect()
11318    }
11319
11320    pub fn enable_breakpoint(
11321        &mut self,
11322        _: &crate::actions::EnableBreakpoint,
11323        window: &mut Window,
11324        cx: &mut Context<Self>,
11325    ) {
11326        if self.breakpoint_store.is_none() {
11327            return;
11328        }
11329
11330        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11331            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11332                continue;
11333            };
11334            self.edit_breakpoint_at_anchor(
11335                anchor,
11336                breakpoint,
11337                BreakpointEditAction::InvertState,
11338                cx,
11339            );
11340        }
11341    }
11342
11343    pub fn disable_breakpoint(
11344        &mut self,
11345        _: &crate::actions::DisableBreakpoint,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        if self.breakpoint_store.is_none() {
11350            return;
11351        }
11352
11353        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11354            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11355                continue;
11356            };
11357            self.edit_breakpoint_at_anchor(
11358                anchor,
11359                breakpoint,
11360                BreakpointEditAction::InvertState,
11361                cx,
11362            );
11363        }
11364    }
11365
11366    pub fn toggle_breakpoint(
11367        &mut self,
11368        _: &crate::actions::ToggleBreakpoint,
11369        window: &mut Window,
11370        cx: &mut Context<Self>,
11371    ) {
11372        if self.breakpoint_store.is_none() {
11373            return;
11374        }
11375
11376        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11377            if let Some(breakpoint) = breakpoint {
11378                self.edit_breakpoint_at_anchor(
11379                    anchor,
11380                    breakpoint,
11381                    BreakpointEditAction::Toggle,
11382                    cx,
11383                );
11384            } else {
11385                self.edit_breakpoint_at_anchor(
11386                    anchor,
11387                    Breakpoint::new_standard(),
11388                    BreakpointEditAction::Toggle,
11389                    cx,
11390                );
11391            }
11392        }
11393    }
11394
11395    pub fn edit_breakpoint_at_anchor(
11396        &mut self,
11397        breakpoint_position: Anchor,
11398        breakpoint: Breakpoint,
11399        edit_action: BreakpointEditAction,
11400        cx: &mut Context<Self>,
11401    ) {
11402        let Some(breakpoint_store) = &self.breakpoint_store else {
11403            return;
11404        };
11405
11406        let Some(buffer) = self
11407            .buffer
11408            .read(cx)
11409            .buffer_for_anchor(breakpoint_position, cx)
11410        else {
11411            return;
11412        };
11413
11414        breakpoint_store.update(cx, |breakpoint_store, cx| {
11415            breakpoint_store.toggle_breakpoint(
11416                buffer,
11417                BreakpointWithPosition {
11418                    position: breakpoint_position.text_anchor,
11419                    bp: breakpoint,
11420                },
11421                edit_action,
11422                cx,
11423            );
11424        });
11425
11426        cx.notify();
11427    }
11428
11429    #[cfg(any(test, feature = "test-support"))]
11430    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11431        self.breakpoint_store.clone()
11432    }
11433
11434    pub fn prepare_restore_change(
11435        &self,
11436        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11437        hunk: &MultiBufferDiffHunk,
11438        cx: &mut App,
11439    ) -> Option<()> {
11440        if hunk.is_created_file() {
11441            return None;
11442        }
11443        let buffer = self.buffer.read(cx);
11444        let diff = buffer.diff_for(hunk.buffer_id)?;
11445        let buffer = buffer.buffer(hunk.buffer_id)?;
11446        let buffer = buffer.read(cx);
11447        let original_text = diff
11448            .read(cx)
11449            .base_text()
11450            .as_rope()
11451            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11452        let buffer_snapshot = buffer.snapshot();
11453        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11454        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11455            probe
11456                .0
11457                .start
11458                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11459                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11460        }) {
11461            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11462            Some(())
11463        } else {
11464            None
11465        }
11466    }
11467
11468    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11469        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11470    }
11471
11472    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11473        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11474    }
11475
11476    fn manipulate_lines<M>(
11477        &mut self,
11478        window: &mut Window,
11479        cx: &mut Context<Self>,
11480        mut manipulate: M,
11481    ) where
11482        M: FnMut(&str) -> LineManipulationResult,
11483    {
11484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11485
11486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11487        let buffer = self.buffer.read(cx).snapshot(cx);
11488
11489        let mut edits = Vec::new();
11490
11491        let selections = self.selections.all::<Point>(&display_map);
11492        let mut selections = selections.iter().peekable();
11493        let mut contiguous_row_selections = Vec::new();
11494        let mut new_selections = Vec::new();
11495        let mut added_lines = 0;
11496        let mut removed_lines = 0;
11497
11498        while let Some(selection) = selections.next() {
11499            let (start_row, end_row) = consume_contiguous_rows(
11500                &mut contiguous_row_selections,
11501                selection,
11502                &display_map,
11503                &mut selections,
11504            );
11505
11506            let start_point = Point::new(start_row.0, 0);
11507            let end_point = Point::new(
11508                end_row.previous_row().0,
11509                buffer.line_len(end_row.previous_row()),
11510            );
11511            let text = buffer
11512                .text_for_range(start_point..end_point)
11513                .collect::<String>();
11514
11515            let LineManipulationResult {
11516                new_text,
11517                line_count_before,
11518                line_count_after,
11519            } = manipulate(&text);
11520
11521            edits.push((start_point..end_point, new_text));
11522
11523            // Selections must change based on added and removed line count
11524            let start_row =
11525                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11526            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11527            new_selections.push(Selection {
11528                id: selection.id,
11529                start: start_row,
11530                end: end_row,
11531                goal: SelectionGoal::None,
11532                reversed: selection.reversed,
11533            });
11534
11535            if line_count_after > line_count_before {
11536                added_lines += line_count_after - line_count_before;
11537            } else if line_count_before > line_count_after {
11538                removed_lines += line_count_before - line_count_after;
11539            }
11540        }
11541
11542        self.transact(window, cx, |this, window, cx| {
11543            let buffer = this.buffer.update(cx, |buffer, cx| {
11544                buffer.edit(edits, None, cx);
11545                buffer.snapshot(cx)
11546            });
11547
11548            // Recalculate offsets on newly edited buffer
11549            let new_selections = new_selections
11550                .iter()
11551                .map(|s| {
11552                    let start_point = Point::new(s.start.0, 0);
11553                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11554                    Selection {
11555                        id: s.id,
11556                        start: buffer.point_to_offset(start_point),
11557                        end: buffer.point_to_offset(end_point),
11558                        goal: s.goal,
11559                        reversed: s.reversed,
11560                    }
11561                })
11562                .collect();
11563
11564            this.change_selections(Default::default(), window, cx, |s| {
11565                s.select(new_selections);
11566            });
11567
11568            this.request_autoscroll(Autoscroll::fit(), cx);
11569        });
11570    }
11571
11572    fn manipulate_immutable_lines<Fn>(
11573        &mut self,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576        mut callback: Fn,
11577    ) where
11578        Fn: FnMut(&mut Vec<&str>),
11579    {
11580        self.manipulate_lines(window, cx, |text| {
11581            let mut lines: Vec<&str> = text.split('\n').collect();
11582            let line_count_before = lines.len();
11583
11584            callback(&mut lines);
11585
11586            LineManipulationResult {
11587                new_text: lines.join("\n"),
11588                line_count_before,
11589                line_count_after: lines.len(),
11590            }
11591        });
11592    }
11593
11594    fn manipulate_mutable_lines<Fn>(
11595        &mut self,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598        mut callback: Fn,
11599    ) where
11600        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11601    {
11602        self.manipulate_lines(window, cx, |text| {
11603            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11604            let line_count_before = lines.len();
11605
11606            callback(&mut lines);
11607
11608            LineManipulationResult {
11609                new_text: lines.join("\n"),
11610                line_count_before,
11611                line_count_after: lines.len(),
11612            }
11613        });
11614    }
11615
11616    pub fn convert_indentation_to_spaces(
11617        &mut self,
11618        _: &ConvertIndentationToSpaces,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        let settings = self.buffer.read(cx).language_settings(cx);
11623        let tab_size = settings.tab_size.get() as usize;
11624
11625        self.manipulate_mutable_lines(window, cx, |lines| {
11626            // Allocates a reasonably sized scratch buffer once for the whole loop
11627            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11628            // Avoids recomputing spaces that could be inserted many times
11629            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11630                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11631                .collect();
11632
11633            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11634                let mut chars = line.as_ref().chars();
11635                let mut col = 0;
11636                let mut changed = false;
11637
11638                for ch in chars.by_ref() {
11639                    match ch {
11640                        ' ' => {
11641                            reindented_line.push(' ');
11642                            col += 1;
11643                        }
11644                        '\t' => {
11645                            // \t are converted to spaces depending on the current column
11646                            let spaces_len = tab_size - (col % tab_size);
11647                            reindented_line.extend(&space_cache[spaces_len - 1]);
11648                            col += spaces_len;
11649                            changed = true;
11650                        }
11651                        _ => {
11652                            // If we dont append before break, the character is consumed
11653                            reindented_line.push(ch);
11654                            break;
11655                        }
11656                    }
11657                }
11658
11659                if !changed {
11660                    reindented_line.clear();
11661                    continue;
11662                }
11663                // Append the rest of the line and replace old reference with new one
11664                reindented_line.extend(chars);
11665                *line = Cow::Owned(reindented_line.clone());
11666                reindented_line.clear();
11667            }
11668        });
11669    }
11670
11671    pub fn convert_indentation_to_tabs(
11672        &mut self,
11673        _: &ConvertIndentationToTabs,
11674        window: &mut Window,
11675        cx: &mut Context<Self>,
11676    ) {
11677        let settings = self.buffer.read(cx).language_settings(cx);
11678        let tab_size = settings.tab_size.get() as usize;
11679
11680        self.manipulate_mutable_lines(window, cx, |lines| {
11681            // Allocates a reasonably sized buffer once for the whole loop
11682            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11683            // Avoids recomputing spaces that could be inserted many times
11684            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11685                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11686                .collect();
11687
11688            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11689                let mut chars = line.chars();
11690                let mut spaces_count = 0;
11691                let mut first_non_indent_char = None;
11692                let mut changed = false;
11693
11694                for ch in chars.by_ref() {
11695                    match ch {
11696                        ' ' => {
11697                            // Keep track of spaces. Append \t when we reach tab_size
11698                            spaces_count += 1;
11699                            changed = true;
11700                            if spaces_count == tab_size {
11701                                reindented_line.push('\t');
11702                                spaces_count = 0;
11703                            }
11704                        }
11705                        '\t' => {
11706                            reindented_line.push('\t');
11707                            spaces_count = 0;
11708                        }
11709                        _ => {
11710                            // Dont append it yet, we might have remaining spaces
11711                            first_non_indent_char = Some(ch);
11712                            break;
11713                        }
11714                    }
11715                }
11716
11717                if !changed {
11718                    reindented_line.clear();
11719                    continue;
11720                }
11721                // Remaining spaces that didn't make a full tab stop
11722                if spaces_count > 0 {
11723                    reindented_line.extend(&space_cache[spaces_count - 1]);
11724                }
11725                // If we consume an extra character that was not indentation, add it back
11726                if let Some(extra_char) = first_non_indent_char {
11727                    reindented_line.push(extra_char);
11728                }
11729                // Append the rest of the line and replace old reference with new one
11730                reindented_line.extend(chars);
11731                *line = Cow::Owned(reindented_line.clone());
11732                reindented_line.clear();
11733            }
11734        });
11735    }
11736
11737    pub fn convert_to_upper_case(
11738        &mut self,
11739        _: &ConvertToUpperCase,
11740        window: &mut Window,
11741        cx: &mut Context<Self>,
11742    ) {
11743        self.manipulate_text(window, cx, |text| text.to_uppercase())
11744    }
11745
11746    pub fn convert_to_lower_case(
11747        &mut self,
11748        _: &ConvertToLowerCase,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        self.manipulate_text(window, cx, |text| text.to_lowercase())
11753    }
11754
11755    pub fn convert_to_title_case(
11756        &mut self,
11757        _: &ConvertToTitleCase,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        self.manipulate_text(window, cx, |text| {
11762            text.split('\n')
11763                .map(|line| line.to_case(Case::Title))
11764                .join("\n")
11765        })
11766    }
11767
11768    pub fn convert_to_snake_case(
11769        &mut self,
11770        _: &ConvertToSnakeCase,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11775    }
11776
11777    pub fn convert_to_kebab_case(
11778        &mut self,
11779        _: &ConvertToKebabCase,
11780        window: &mut Window,
11781        cx: &mut Context<Self>,
11782    ) {
11783        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11784    }
11785
11786    pub fn convert_to_upper_camel_case(
11787        &mut self,
11788        _: &ConvertToUpperCamelCase,
11789        window: &mut Window,
11790        cx: &mut Context<Self>,
11791    ) {
11792        self.manipulate_text(window, cx, |text| {
11793            text.split('\n')
11794                .map(|line| line.to_case(Case::UpperCamel))
11795                .join("\n")
11796        })
11797    }
11798
11799    pub fn convert_to_lower_camel_case(
11800        &mut self,
11801        _: &ConvertToLowerCamelCase,
11802        window: &mut Window,
11803        cx: &mut Context<Self>,
11804    ) {
11805        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11806    }
11807
11808    pub fn convert_to_opposite_case(
11809        &mut self,
11810        _: &ConvertToOppositeCase,
11811        window: &mut Window,
11812        cx: &mut Context<Self>,
11813    ) {
11814        self.manipulate_text(window, cx, |text| {
11815            text.chars()
11816                .fold(String::with_capacity(text.len()), |mut t, c| {
11817                    if c.is_uppercase() {
11818                        t.extend(c.to_lowercase());
11819                    } else {
11820                        t.extend(c.to_uppercase());
11821                    }
11822                    t
11823                })
11824        })
11825    }
11826
11827    pub fn convert_to_sentence_case(
11828        &mut self,
11829        _: &ConvertToSentenceCase,
11830        window: &mut Window,
11831        cx: &mut Context<Self>,
11832    ) {
11833        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11834    }
11835
11836    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11837        self.manipulate_text(window, cx, |text| {
11838            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11839            if has_upper_case_characters {
11840                text.to_lowercase()
11841            } else {
11842                text.to_uppercase()
11843            }
11844        })
11845    }
11846
11847    pub fn convert_to_rot13(
11848        &mut self,
11849        _: &ConvertToRot13,
11850        window: &mut Window,
11851        cx: &mut Context<Self>,
11852    ) {
11853        self.manipulate_text(window, cx, |text| {
11854            text.chars()
11855                .map(|c| match c {
11856                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11857                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11858                    _ => c,
11859                })
11860                .collect()
11861        })
11862    }
11863
11864    pub fn convert_to_rot47(
11865        &mut self,
11866        _: &ConvertToRot47,
11867        window: &mut Window,
11868        cx: &mut Context<Self>,
11869    ) {
11870        self.manipulate_text(window, cx, |text| {
11871            text.chars()
11872                .map(|c| {
11873                    let code_point = c as u32;
11874                    if code_point >= 33 && code_point <= 126 {
11875                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11876                    }
11877                    c
11878                })
11879                .collect()
11880        })
11881    }
11882
11883    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11884    where
11885        Fn: FnMut(&str) -> String,
11886    {
11887        let buffer = self.buffer.read(cx).snapshot(cx);
11888
11889        let mut new_selections = Vec::new();
11890        let mut edits = Vec::new();
11891        let mut selection_adjustment = 0isize;
11892
11893        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11894            let selection_is_empty = selection.is_empty();
11895
11896            let (start, end) = if selection_is_empty {
11897                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11898                (word_range.start, word_range.end)
11899            } else {
11900                (
11901                    buffer.point_to_offset(selection.start),
11902                    buffer.point_to_offset(selection.end),
11903                )
11904            };
11905
11906            let text = buffer.text_for_range(start..end).collect::<String>();
11907            let old_length = text.len() as isize;
11908            let text = callback(&text);
11909
11910            new_selections.push(Selection {
11911                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11912                end: MultiBufferOffset(
11913                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11914                ),
11915                goal: SelectionGoal::None,
11916                id: selection.id,
11917                reversed: selection.reversed,
11918            });
11919
11920            selection_adjustment += old_length - text.len() as isize;
11921
11922            edits.push((start..end, text));
11923        }
11924
11925        self.transact(window, cx, |this, window, cx| {
11926            this.buffer.update(cx, |buffer, cx| {
11927                buffer.edit(edits, None, cx);
11928            });
11929
11930            this.change_selections(Default::default(), window, cx, |s| {
11931                s.select(new_selections);
11932            });
11933
11934            this.request_autoscroll(Autoscroll::fit(), cx);
11935        });
11936    }
11937
11938    pub fn move_selection_on_drop(
11939        &mut self,
11940        selection: &Selection<Anchor>,
11941        target: DisplayPoint,
11942        is_cut: bool,
11943        window: &mut Window,
11944        cx: &mut Context<Self>,
11945    ) {
11946        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11947        let buffer = display_map.buffer_snapshot();
11948        let mut edits = Vec::new();
11949        let insert_point = display_map
11950            .clip_point(target, Bias::Left)
11951            .to_point(&display_map);
11952        let text = buffer
11953            .text_for_range(selection.start..selection.end)
11954            .collect::<String>();
11955        if is_cut {
11956            edits.push(((selection.start..selection.end), String::new()));
11957        }
11958        let insert_anchor = buffer.anchor_before(insert_point);
11959        edits.push(((insert_anchor..insert_anchor), text));
11960        let last_edit_start = insert_anchor.bias_left(buffer);
11961        let last_edit_end = insert_anchor.bias_right(buffer);
11962        self.transact(window, cx, |this, window, cx| {
11963            this.buffer.update(cx, |buffer, cx| {
11964                buffer.edit(edits, None, cx);
11965            });
11966            this.change_selections(Default::default(), window, cx, |s| {
11967                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11968            });
11969        });
11970    }
11971
11972    pub fn clear_selection_drag_state(&mut self) {
11973        self.selection_drag_state = SelectionDragState::None;
11974    }
11975
11976    pub fn duplicate(
11977        &mut self,
11978        upwards: bool,
11979        whole_lines: bool,
11980        window: &mut Window,
11981        cx: &mut Context<Self>,
11982    ) {
11983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11984
11985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11986        let buffer = display_map.buffer_snapshot();
11987        let selections = self.selections.all::<Point>(&display_map);
11988
11989        let mut edits = Vec::new();
11990        let mut selections_iter = selections.iter().peekable();
11991        while let Some(selection) = selections_iter.next() {
11992            let mut rows = selection.spanned_rows(false, &display_map);
11993            // duplicate line-wise
11994            if whole_lines || selection.start == selection.end {
11995                // Avoid duplicating the same lines twice.
11996                while let Some(next_selection) = selections_iter.peek() {
11997                    let next_rows = next_selection.spanned_rows(false, &display_map);
11998                    if next_rows.start < rows.end {
11999                        rows.end = next_rows.end;
12000                        selections_iter.next().unwrap();
12001                    } else {
12002                        break;
12003                    }
12004                }
12005
12006                // Copy the text from the selected row region and splice it either at the start
12007                // or end of the region.
12008                let start = Point::new(rows.start.0, 0);
12009                let end = Point::new(
12010                    rows.end.previous_row().0,
12011                    buffer.line_len(rows.end.previous_row()),
12012                );
12013
12014                let mut text = buffer.text_for_range(start..end).collect::<String>();
12015
12016                let insert_location = if upwards {
12017                    // When duplicating upward, we need to insert before the current line.
12018                    // If we're on the last line and it doesn't end with a newline,
12019                    // we need to add a newline before the duplicated content.
12020                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12021                        && buffer.max_point().column > 0
12022                        && !text.ends_with('\n');
12023
12024                    if needs_leading_newline {
12025                        text.insert(0, '\n');
12026                        end
12027                    } else {
12028                        text.push('\n');
12029                        Point::new(rows.start.0, 0)
12030                    }
12031                } else {
12032                    text.push('\n');
12033                    start
12034                };
12035                edits.push((insert_location..insert_location, text));
12036            } else {
12037                // duplicate character-wise
12038                let start = selection.start;
12039                let end = selection.end;
12040                let text = buffer.text_for_range(start..end).collect::<String>();
12041                edits.push((selection.end..selection.end, text));
12042            }
12043        }
12044
12045        self.transact(window, cx, |this, window, cx| {
12046            this.buffer.update(cx, |buffer, cx| {
12047                buffer.edit(edits, None, cx);
12048            });
12049
12050            // When duplicating upward with whole lines, move the cursor to the duplicated line
12051            if upwards && whole_lines {
12052                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12053
12054                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12055                    let mut new_ranges = Vec::new();
12056                    let selections = s.all::<Point>(&display_map);
12057                    let mut selections_iter = selections.iter().peekable();
12058
12059                    while let Some(first_selection) = selections_iter.next() {
12060                        // Group contiguous selections together to find the total row span
12061                        let mut group_selections = vec![first_selection];
12062                        let mut rows = first_selection.spanned_rows(false, &display_map);
12063
12064                        while let Some(next_selection) = selections_iter.peek() {
12065                            let next_rows = next_selection.spanned_rows(false, &display_map);
12066                            if next_rows.start < rows.end {
12067                                rows.end = next_rows.end;
12068                                group_selections.push(selections_iter.next().unwrap());
12069                            } else {
12070                                break;
12071                            }
12072                        }
12073
12074                        let row_count = rows.end.0 - rows.start.0;
12075
12076                        // Move all selections in this group up by the total number of duplicated rows
12077                        for selection in group_selections {
12078                            let new_start = Point::new(
12079                                selection.start.row.saturating_sub(row_count),
12080                                selection.start.column,
12081                            );
12082
12083                            let new_end = Point::new(
12084                                selection.end.row.saturating_sub(row_count),
12085                                selection.end.column,
12086                            );
12087
12088                            new_ranges.push(new_start..new_end);
12089                        }
12090                    }
12091
12092                    s.select_ranges(new_ranges);
12093                });
12094            }
12095
12096            this.request_autoscroll(Autoscroll::fit(), cx);
12097        });
12098    }
12099
12100    pub fn duplicate_line_up(
12101        &mut self,
12102        _: &DuplicateLineUp,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        self.duplicate(true, true, window, cx);
12107    }
12108
12109    pub fn duplicate_line_down(
12110        &mut self,
12111        _: &DuplicateLineDown,
12112        window: &mut Window,
12113        cx: &mut Context<Self>,
12114    ) {
12115        self.duplicate(false, true, window, cx);
12116    }
12117
12118    pub fn duplicate_selection(
12119        &mut self,
12120        _: &DuplicateSelection,
12121        window: &mut Window,
12122        cx: &mut Context<Self>,
12123    ) {
12124        self.duplicate(false, false, window, cx);
12125    }
12126
12127    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12129        if self.mode.is_single_line() {
12130            cx.propagate();
12131            return;
12132        }
12133
12134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12135        let buffer = self.buffer.read(cx).snapshot(cx);
12136
12137        let mut edits = Vec::new();
12138        let mut unfold_ranges = Vec::new();
12139        let mut refold_creases = Vec::new();
12140
12141        let selections = self.selections.all::<Point>(&display_map);
12142        let mut selections = selections.iter().peekable();
12143        let mut contiguous_row_selections = Vec::new();
12144        let mut new_selections = Vec::new();
12145
12146        while let Some(selection) = selections.next() {
12147            // Find all the selections that span a contiguous row range
12148            let (start_row, end_row) = consume_contiguous_rows(
12149                &mut contiguous_row_selections,
12150                selection,
12151                &display_map,
12152                &mut selections,
12153            );
12154
12155            // Move the text spanned by the row range to be before the line preceding the row range
12156            if start_row.0 > 0 {
12157                let range_to_move = Point::new(
12158                    start_row.previous_row().0,
12159                    buffer.line_len(start_row.previous_row()),
12160                )
12161                    ..Point::new(
12162                        end_row.previous_row().0,
12163                        buffer.line_len(end_row.previous_row()),
12164                    );
12165                let insertion_point = display_map
12166                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12167                    .0;
12168
12169                // Don't move lines across excerpts
12170                if buffer
12171                    .excerpt_containing(insertion_point..range_to_move.end)
12172                    .is_some()
12173                {
12174                    let text = buffer
12175                        .text_for_range(range_to_move.clone())
12176                        .flat_map(|s| s.chars())
12177                        .skip(1)
12178                        .chain(['\n'])
12179                        .collect::<String>();
12180
12181                    edits.push((
12182                        buffer.anchor_after(range_to_move.start)
12183                            ..buffer.anchor_before(range_to_move.end),
12184                        String::new(),
12185                    ));
12186                    let insertion_anchor = buffer.anchor_after(insertion_point);
12187                    edits.push((insertion_anchor..insertion_anchor, text));
12188
12189                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12190
12191                    // Move selections up
12192                    new_selections.extend(contiguous_row_selections.drain(..).map(
12193                        |mut selection| {
12194                            selection.start.row -= row_delta;
12195                            selection.end.row -= row_delta;
12196                            selection
12197                        },
12198                    ));
12199
12200                    // Move folds up
12201                    unfold_ranges.push(range_to_move.clone());
12202                    for fold in display_map.folds_in_range(
12203                        buffer.anchor_before(range_to_move.start)
12204                            ..buffer.anchor_after(range_to_move.end),
12205                    ) {
12206                        let mut start = fold.range.start.to_point(&buffer);
12207                        let mut end = fold.range.end.to_point(&buffer);
12208                        start.row -= row_delta;
12209                        end.row -= row_delta;
12210                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12211                    }
12212                }
12213            }
12214
12215            // If we didn't move line(s), preserve the existing selections
12216            new_selections.append(&mut contiguous_row_selections);
12217        }
12218
12219        self.transact(window, cx, |this, window, cx| {
12220            this.unfold_ranges(&unfold_ranges, true, true, cx);
12221            this.buffer.update(cx, |buffer, cx| {
12222                for (range, text) in edits {
12223                    buffer.edit([(range, text)], None, cx);
12224                }
12225            });
12226            this.fold_creases(refold_creases, true, window, cx);
12227            this.change_selections(Default::default(), window, cx, |s| {
12228                s.select(new_selections);
12229            })
12230        });
12231    }
12232
12233    pub fn move_line_down(
12234        &mut self,
12235        _: &MoveLineDown,
12236        window: &mut Window,
12237        cx: &mut Context<Self>,
12238    ) {
12239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12240        if self.mode.is_single_line() {
12241            cx.propagate();
12242            return;
12243        }
12244
12245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12246        let buffer = self.buffer.read(cx).snapshot(cx);
12247
12248        let mut edits = Vec::new();
12249        let mut unfold_ranges = Vec::new();
12250        let mut refold_creases = Vec::new();
12251
12252        let selections = self.selections.all::<Point>(&display_map);
12253        let mut selections = selections.iter().peekable();
12254        let mut contiguous_row_selections = Vec::new();
12255        let mut new_selections = Vec::new();
12256
12257        while let Some(selection) = selections.next() {
12258            // Find all the selections that span a contiguous row range
12259            let (start_row, end_row) = consume_contiguous_rows(
12260                &mut contiguous_row_selections,
12261                selection,
12262                &display_map,
12263                &mut selections,
12264            );
12265
12266            // Move the text spanned by the row range to be after the last line of the row range
12267            if end_row.0 <= buffer.max_point().row {
12268                let range_to_move =
12269                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12270                let insertion_point = display_map
12271                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12272                    .0;
12273
12274                // Don't move lines across excerpt boundaries
12275                if buffer
12276                    .excerpt_containing(range_to_move.start..insertion_point)
12277                    .is_some()
12278                {
12279                    let mut text = String::from("\n");
12280                    text.extend(buffer.text_for_range(range_to_move.clone()));
12281                    text.pop(); // Drop trailing newline
12282                    edits.push((
12283                        buffer.anchor_after(range_to_move.start)
12284                            ..buffer.anchor_before(range_to_move.end),
12285                        String::new(),
12286                    ));
12287                    let insertion_anchor = buffer.anchor_after(insertion_point);
12288                    edits.push((insertion_anchor..insertion_anchor, text));
12289
12290                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12291
12292                    // Move selections down
12293                    new_selections.extend(contiguous_row_selections.drain(..).map(
12294                        |mut selection| {
12295                            selection.start.row += row_delta;
12296                            selection.end.row += row_delta;
12297                            selection
12298                        },
12299                    ));
12300
12301                    // Move folds down
12302                    unfold_ranges.push(range_to_move.clone());
12303                    for fold in display_map.folds_in_range(
12304                        buffer.anchor_before(range_to_move.start)
12305                            ..buffer.anchor_after(range_to_move.end),
12306                    ) {
12307                        let mut start = fold.range.start.to_point(&buffer);
12308                        let mut end = fold.range.end.to_point(&buffer);
12309                        start.row += row_delta;
12310                        end.row += row_delta;
12311                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12312                    }
12313                }
12314            }
12315
12316            // If we didn't move line(s), preserve the existing selections
12317            new_selections.append(&mut contiguous_row_selections);
12318        }
12319
12320        self.transact(window, cx, |this, window, cx| {
12321            this.unfold_ranges(&unfold_ranges, true, true, cx);
12322            this.buffer.update(cx, |buffer, cx| {
12323                for (range, text) in edits {
12324                    buffer.edit([(range, text)], None, cx);
12325                }
12326            });
12327            this.fold_creases(refold_creases, true, window, cx);
12328            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12329        });
12330    }
12331
12332    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12333        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12334        let text_layout_details = &self.text_layout_details(window);
12335        self.transact(window, cx, |this, window, cx| {
12336            let edits = this.change_selections(Default::default(), window, cx, |s| {
12337                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12338                s.move_with(|display_map, selection| {
12339                    if !selection.is_empty() {
12340                        return;
12341                    }
12342
12343                    let mut head = selection.head();
12344                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12345                    if head.column() == display_map.line_len(head.row()) {
12346                        transpose_offset = display_map
12347                            .buffer_snapshot()
12348                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12349                    }
12350
12351                    if transpose_offset == MultiBufferOffset(0) {
12352                        return;
12353                    }
12354
12355                    *head.column_mut() += 1;
12356                    head = display_map.clip_point(head, Bias::Right);
12357                    let goal = SelectionGoal::HorizontalPosition(
12358                        display_map
12359                            .x_for_display_point(head, text_layout_details)
12360                            .into(),
12361                    );
12362                    selection.collapse_to(head, goal);
12363
12364                    let transpose_start = display_map
12365                        .buffer_snapshot()
12366                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12367                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12368                        let transpose_end = display_map
12369                            .buffer_snapshot()
12370                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12371                        if let Some(ch) = display_map
12372                            .buffer_snapshot()
12373                            .chars_at(transpose_start)
12374                            .next()
12375                        {
12376                            edits.push((transpose_start..transpose_offset, String::new()));
12377                            edits.push((transpose_end..transpose_end, ch.to_string()));
12378                        }
12379                    }
12380                });
12381                edits
12382            });
12383            this.buffer
12384                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12385            let selections = this
12386                .selections
12387                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12388            this.change_selections(Default::default(), window, cx, |s| {
12389                s.select(selections);
12390            });
12391        });
12392    }
12393
12394    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12396        if self.mode.is_single_line() {
12397            cx.propagate();
12398            return;
12399        }
12400
12401        self.rewrap_impl(RewrapOptions::default(), cx)
12402    }
12403
12404    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12405        let buffer = self.buffer.read(cx).snapshot(cx);
12406        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12407
12408        #[derive(Clone, Debug, PartialEq)]
12409        enum CommentFormat {
12410            /// single line comment, with prefix for line
12411            Line(String),
12412            /// single line within a block comment, with prefix for line
12413            BlockLine(String),
12414            /// a single line of a block comment that includes the initial delimiter
12415            BlockCommentWithStart(BlockCommentConfig),
12416            /// a single line of a block comment that includes the ending delimiter
12417            BlockCommentWithEnd(BlockCommentConfig),
12418        }
12419
12420        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12421        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12422            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12423                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12424                .peekable();
12425
12426            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12427                row
12428            } else {
12429                return Vec::new();
12430            };
12431
12432            let language_settings = buffer.language_settings_at(selection.head(), cx);
12433            let language_scope = buffer.language_scope_at(selection.head());
12434
12435            let indent_and_prefix_for_row =
12436                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12437                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12438                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12439                        &language_scope
12440                    {
12441                        let indent_end = Point::new(row, indent.len);
12442                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12443                        let line_text_after_indent = buffer
12444                            .text_for_range(indent_end..line_end)
12445                            .collect::<String>();
12446
12447                        let is_within_comment_override = buffer
12448                            .language_scope_at(indent_end)
12449                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12450                        let comment_delimiters = if is_within_comment_override {
12451                            // we are within a comment syntax node, but we don't
12452                            // yet know what kind of comment: block, doc or line
12453                            match (
12454                                language_scope.documentation_comment(),
12455                                language_scope.block_comment(),
12456                            ) {
12457                                (Some(config), _) | (_, Some(config))
12458                                    if buffer.contains_str_at(indent_end, &config.start) =>
12459                                {
12460                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12461                                }
12462                                (Some(config), _) | (_, Some(config))
12463                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12464                                {
12465                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12466                                }
12467                                (Some(config), _) | (_, Some(config))
12468                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12469                                {
12470                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12471                                }
12472                                (_, _) => language_scope
12473                                    .line_comment_prefixes()
12474                                    .iter()
12475                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12476                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12477                            }
12478                        } else {
12479                            // we not in an overridden comment node, but we may
12480                            // be within a non-overridden line comment node
12481                            language_scope
12482                                .line_comment_prefixes()
12483                                .iter()
12484                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12485                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12486                        };
12487
12488                        let rewrap_prefix = language_scope
12489                            .rewrap_prefixes()
12490                            .iter()
12491                            .find_map(|prefix_regex| {
12492                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12493                                    if mat.start() == 0 {
12494                                        Some(mat.as_str().to_string())
12495                                    } else {
12496                                        None
12497                                    }
12498                                })
12499                            })
12500                            .flatten();
12501                        (comment_delimiters, rewrap_prefix)
12502                    } else {
12503                        (None, None)
12504                    };
12505                    (indent, comment_prefix, rewrap_prefix)
12506                };
12507
12508            let mut ranges = Vec::new();
12509            let from_empty_selection = selection.is_empty();
12510
12511            let mut current_range_start = first_row;
12512            let mut prev_row = first_row;
12513            let (
12514                mut current_range_indent,
12515                mut current_range_comment_delimiters,
12516                mut current_range_rewrap_prefix,
12517            ) = indent_and_prefix_for_row(first_row);
12518
12519            for row in non_blank_rows_iter.skip(1) {
12520                let has_paragraph_break = row > prev_row + 1;
12521
12522                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12523                    indent_and_prefix_for_row(row);
12524
12525                let has_indent_change = row_indent != current_range_indent;
12526                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12527
12528                let has_boundary_change = has_comment_change
12529                    || row_rewrap_prefix.is_some()
12530                    || (has_indent_change && current_range_comment_delimiters.is_some());
12531
12532                if has_paragraph_break || has_boundary_change {
12533                    ranges.push((
12534                        language_settings.clone(),
12535                        Point::new(current_range_start, 0)
12536                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12537                        current_range_indent,
12538                        current_range_comment_delimiters.clone(),
12539                        current_range_rewrap_prefix.clone(),
12540                        from_empty_selection,
12541                    ));
12542                    current_range_start = row;
12543                    current_range_indent = row_indent;
12544                    current_range_comment_delimiters = row_comment_delimiters;
12545                    current_range_rewrap_prefix = row_rewrap_prefix;
12546                }
12547                prev_row = row;
12548            }
12549
12550            ranges.push((
12551                language_settings.clone(),
12552                Point::new(current_range_start, 0)
12553                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12554                current_range_indent,
12555                current_range_comment_delimiters,
12556                current_range_rewrap_prefix,
12557                from_empty_selection,
12558            ));
12559
12560            ranges
12561        });
12562
12563        let mut edits = Vec::new();
12564        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12565
12566        for (
12567            language_settings,
12568            wrap_range,
12569            mut indent_size,
12570            comment_prefix,
12571            rewrap_prefix,
12572            from_empty_selection,
12573        ) in wrap_ranges
12574        {
12575            let mut start_row = wrap_range.start.row;
12576            let mut end_row = wrap_range.end.row;
12577
12578            // Skip selections that overlap with a range that has already been rewrapped.
12579            let selection_range = start_row..end_row;
12580            if rewrapped_row_ranges
12581                .iter()
12582                .any(|range| range.overlaps(&selection_range))
12583            {
12584                continue;
12585            }
12586
12587            let tab_size = language_settings.tab_size;
12588
12589            let (line_prefix, inside_comment) = match &comment_prefix {
12590                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12591                    (Some(prefix.as_str()), true)
12592                }
12593                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12594                    (Some(prefix.as_ref()), true)
12595                }
12596                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12597                    start: _,
12598                    end: _,
12599                    prefix,
12600                    tab_size,
12601                })) => {
12602                    indent_size.len += tab_size;
12603                    (Some(prefix.as_ref()), true)
12604                }
12605                None => (None, false),
12606            };
12607            let indent_prefix = indent_size.chars().collect::<String>();
12608            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12609
12610            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12611                RewrapBehavior::InComments => inside_comment,
12612                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12613                RewrapBehavior::Anywhere => true,
12614            };
12615
12616            let should_rewrap = options.override_language_settings
12617                || allow_rewrap_based_on_language
12618                || self.hard_wrap.is_some();
12619            if !should_rewrap {
12620                continue;
12621            }
12622
12623            if from_empty_selection {
12624                'expand_upwards: while start_row > 0 {
12625                    let prev_row = start_row - 1;
12626                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12627                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12628                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12629                    {
12630                        start_row = prev_row;
12631                    } else {
12632                        break 'expand_upwards;
12633                    }
12634                }
12635
12636                'expand_downwards: while end_row < buffer.max_point().row {
12637                    let next_row = end_row + 1;
12638                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12639                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12640                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12641                    {
12642                        end_row = next_row;
12643                    } else {
12644                        break 'expand_downwards;
12645                    }
12646                }
12647            }
12648
12649            let start = Point::new(start_row, 0);
12650            let start_offset = ToOffset::to_offset(&start, &buffer);
12651            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12652            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12653            let mut first_line_delimiter = None;
12654            let mut last_line_delimiter = None;
12655            let Some(lines_without_prefixes) = selection_text
12656                .lines()
12657                .enumerate()
12658                .map(|(ix, line)| {
12659                    let line_trimmed = line.trim_start();
12660                    if rewrap_prefix.is_some() && ix > 0 {
12661                        Ok(line_trimmed)
12662                    } else if let Some(
12663                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12664                            start,
12665                            prefix,
12666                            end,
12667                            tab_size,
12668                        })
12669                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12670                            start,
12671                            prefix,
12672                            end,
12673                            tab_size,
12674                        }),
12675                    ) = &comment_prefix
12676                    {
12677                        let line_trimmed = line_trimmed
12678                            .strip_prefix(start.as_ref())
12679                            .map(|s| {
12680                                let mut indent_size = indent_size;
12681                                indent_size.len -= tab_size;
12682                                let indent_prefix: String = indent_size.chars().collect();
12683                                first_line_delimiter = Some((indent_prefix, start));
12684                                s.trim_start()
12685                            })
12686                            .unwrap_or(line_trimmed);
12687                        let line_trimmed = line_trimmed
12688                            .strip_suffix(end.as_ref())
12689                            .map(|s| {
12690                                last_line_delimiter = Some(end);
12691                                s.trim_end()
12692                            })
12693                            .unwrap_or(line_trimmed);
12694                        let line_trimmed = line_trimmed
12695                            .strip_prefix(prefix.as_ref())
12696                            .unwrap_or(line_trimmed);
12697                        Ok(line_trimmed)
12698                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12699                        line_trimmed.strip_prefix(prefix).with_context(|| {
12700                            format!("line did not start with prefix {prefix:?}: {line:?}")
12701                        })
12702                    } else {
12703                        line_trimmed
12704                            .strip_prefix(&line_prefix.trim_start())
12705                            .with_context(|| {
12706                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12707                            })
12708                    }
12709                })
12710                .collect::<Result<Vec<_>, _>>()
12711                .log_err()
12712            else {
12713                continue;
12714            };
12715
12716            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12717                buffer
12718                    .language_settings_at(Point::new(start_row, 0), cx)
12719                    .preferred_line_length as usize
12720            });
12721
12722            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12723                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12724            } else {
12725                line_prefix.clone()
12726            };
12727
12728            let wrapped_text = {
12729                let mut wrapped_text = wrap_with_prefix(
12730                    line_prefix,
12731                    subsequent_lines_prefix,
12732                    lines_without_prefixes.join("\n"),
12733                    wrap_column,
12734                    tab_size,
12735                    options.preserve_existing_whitespace,
12736                );
12737
12738                if let Some((indent, delimiter)) = first_line_delimiter {
12739                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12740                }
12741                if let Some(last_line) = last_line_delimiter {
12742                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12743                }
12744
12745                wrapped_text
12746            };
12747
12748            // TODO: should always use char-based diff while still supporting cursor behavior that
12749            // matches vim.
12750            let mut diff_options = DiffOptions::default();
12751            if options.override_language_settings {
12752                diff_options.max_word_diff_len = 0;
12753                diff_options.max_word_diff_line_count = 0;
12754            } else {
12755                diff_options.max_word_diff_len = usize::MAX;
12756                diff_options.max_word_diff_line_count = usize::MAX;
12757            }
12758
12759            for (old_range, new_text) in
12760                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12761            {
12762                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12763                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12764                edits.push((edit_start..edit_end, new_text));
12765            }
12766
12767            rewrapped_row_ranges.push(start_row..=end_row);
12768        }
12769
12770        self.buffer
12771            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12772    }
12773
12774    pub fn cut_common(
12775        &mut self,
12776        cut_no_selection_line: bool,
12777        window: &mut Window,
12778        cx: &mut Context<Self>,
12779    ) -> ClipboardItem {
12780        let mut text = String::new();
12781        let buffer = self.buffer.read(cx).snapshot(cx);
12782        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12783        let mut clipboard_selections = Vec::with_capacity(selections.len());
12784        {
12785            let max_point = buffer.max_point();
12786            let mut is_first = true;
12787            let mut prev_selection_was_entire_line = false;
12788            for selection in &mut selections {
12789                let is_entire_line =
12790                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12791                if is_entire_line {
12792                    selection.start = Point::new(selection.start.row, 0);
12793                    if !selection.is_empty() && selection.end.column == 0 {
12794                        selection.end = cmp::min(max_point, selection.end);
12795                    } else {
12796                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12797                    }
12798                    selection.goal = SelectionGoal::None;
12799                }
12800                if is_first {
12801                    is_first = false;
12802                } else if !prev_selection_was_entire_line {
12803                    text += "\n";
12804                }
12805                prev_selection_was_entire_line = is_entire_line;
12806                let mut len = 0;
12807                for chunk in buffer.text_for_range(selection.start..selection.end) {
12808                    text.push_str(chunk);
12809                    len += chunk.len();
12810                }
12811                clipboard_selections.push(ClipboardSelection {
12812                    len,
12813                    is_entire_line,
12814                    first_line_indent: buffer
12815                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12816                        .len,
12817                });
12818            }
12819        }
12820
12821        self.transact(window, cx, |this, window, cx| {
12822            this.change_selections(Default::default(), window, cx, |s| {
12823                s.select(selections);
12824            });
12825            this.insert("", window, cx);
12826        });
12827        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12828    }
12829
12830    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12832        let item = self.cut_common(true, window, cx);
12833        cx.write_to_clipboard(item);
12834    }
12835
12836    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12838        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12839            s.move_with(|snapshot, sel| {
12840                if sel.is_empty() {
12841                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12842                }
12843                if sel.is_empty() {
12844                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12845                }
12846            });
12847        });
12848        let item = self.cut_common(false, window, cx);
12849        cx.set_global(KillRing(item))
12850    }
12851
12852    pub fn kill_ring_yank(
12853        &mut self,
12854        _: &KillRingYank,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12859        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12860            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12861                (kill_ring.text().to_string(), kill_ring.metadata_json())
12862            } else {
12863                return;
12864            }
12865        } else {
12866            return;
12867        };
12868        self.do_paste(&text, metadata, false, window, cx);
12869    }
12870
12871    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12872        self.do_copy(true, cx);
12873    }
12874
12875    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12876        self.do_copy(false, cx);
12877    }
12878
12879    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12880        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12881        let buffer = self.buffer.read(cx).read(cx);
12882        let mut text = String::new();
12883
12884        let mut clipboard_selections = Vec::with_capacity(selections.len());
12885        {
12886            let max_point = buffer.max_point();
12887            let mut is_first = true;
12888            let mut prev_selection_was_entire_line = false;
12889            for selection in &selections {
12890                let mut start = selection.start;
12891                let mut end = selection.end;
12892                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12893                let mut add_trailing_newline = false;
12894                if is_entire_line {
12895                    start = Point::new(start.row, 0);
12896                    let next_line_start = Point::new(end.row + 1, 0);
12897                    if next_line_start <= max_point {
12898                        end = next_line_start;
12899                    } else {
12900                        // We're on the last line without a trailing newline.
12901                        // Copy to the end of the line and add a newline afterwards.
12902                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12903                        add_trailing_newline = true;
12904                    }
12905                }
12906
12907                let mut trimmed_selections = Vec::new();
12908                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12909                    let row = MultiBufferRow(start.row);
12910                    let first_indent = buffer.indent_size_for_line(row);
12911                    if first_indent.len == 0 || start.column > first_indent.len {
12912                        trimmed_selections.push(start..end);
12913                    } else {
12914                        trimmed_selections.push(
12915                            Point::new(row.0, first_indent.len)
12916                                ..Point::new(row.0, buffer.line_len(row)),
12917                        );
12918                        for row in start.row + 1..=end.row {
12919                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12920                            if row == end.row {
12921                                line_len = end.column;
12922                            }
12923                            if line_len == 0 {
12924                                trimmed_selections
12925                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12926                                continue;
12927                            }
12928                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12929                            if row_indent_size.len >= first_indent.len {
12930                                trimmed_selections.push(
12931                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12932                                );
12933                            } else {
12934                                trimmed_selections.clear();
12935                                trimmed_selections.push(start..end);
12936                                break;
12937                            }
12938                        }
12939                    }
12940                } else {
12941                    trimmed_selections.push(start..end);
12942                }
12943
12944                for trimmed_range in trimmed_selections {
12945                    if is_first {
12946                        is_first = false;
12947                    } else if !prev_selection_was_entire_line {
12948                        text += "\n";
12949                    }
12950                    prev_selection_was_entire_line = is_entire_line;
12951                    let mut len = 0;
12952                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12953                        text.push_str(chunk);
12954                        len += chunk.len();
12955                    }
12956                    if add_trailing_newline {
12957                        text.push('\n');
12958                        len += 1;
12959                    }
12960                    clipboard_selections.push(ClipboardSelection {
12961                        len,
12962                        is_entire_line,
12963                        first_line_indent: buffer
12964                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12965                            .len,
12966                    });
12967                }
12968            }
12969        }
12970
12971        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12972            text,
12973            clipboard_selections,
12974        ));
12975    }
12976
12977    pub fn do_paste(
12978        &mut self,
12979        text: &String,
12980        clipboard_selections: Option<Vec<ClipboardSelection>>,
12981        handle_entire_lines: bool,
12982        window: &mut Window,
12983        cx: &mut Context<Self>,
12984    ) {
12985        if self.read_only(cx) {
12986            return;
12987        }
12988
12989        let clipboard_text = Cow::Borrowed(text.as_str());
12990
12991        self.transact(window, cx, |this, window, cx| {
12992            let had_active_edit_prediction = this.has_active_edit_prediction();
12993            let display_map = this.display_snapshot(cx);
12994            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12995            let cursor_offset = this
12996                .selections
12997                .last::<MultiBufferOffset>(&display_map)
12998                .head();
12999
13000            if let Some(mut clipboard_selections) = clipboard_selections {
13001                let all_selections_were_entire_line =
13002                    clipboard_selections.iter().all(|s| s.is_entire_line);
13003                let first_selection_indent_column =
13004                    clipboard_selections.first().map(|s| s.first_line_indent);
13005                if clipboard_selections.len() != old_selections.len() {
13006                    clipboard_selections.drain(..);
13007                }
13008                let mut auto_indent_on_paste = true;
13009
13010                this.buffer.update(cx, |buffer, cx| {
13011                    let snapshot = buffer.read(cx);
13012                    auto_indent_on_paste = snapshot
13013                        .language_settings_at(cursor_offset, cx)
13014                        .auto_indent_on_paste;
13015
13016                    let mut start_offset = 0;
13017                    let mut edits = Vec::new();
13018                    let mut original_indent_columns = Vec::new();
13019                    for (ix, selection) in old_selections.iter().enumerate() {
13020                        let to_insert;
13021                        let entire_line;
13022                        let original_indent_column;
13023                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13024                            let end_offset = start_offset + clipboard_selection.len;
13025                            to_insert = &clipboard_text[start_offset..end_offset];
13026                            entire_line = clipboard_selection.is_entire_line;
13027                            start_offset = if entire_line {
13028                                end_offset
13029                            } else {
13030                                end_offset + 1
13031                            };
13032                            original_indent_column = Some(clipboard_selection.first_line_indent);
13033                        } else {
13034                            to_insert = &*clipboard_text;
13035                            entire_line = all_selections_were_entire_line;
13036                            original_indent_column = first_selection_indent_column
13037                        }
13038
13039                        let (range, to_insert) =
13040                            if selection.is_empty() && handle_entire_lines && entire_line {
13041                                // If the corresponding selection was empty when this slice of the
13042                                // clipboard text was written, then the entire line containing the
13043                                // selection was copied. If this selection is also currently empty,
13044                                // then paste the line before the current line of the buffer.
13045                                let column = selection.start.to_point(&snapshot).column as usize;
13046                                let line_start = selection.start - column;
13047                                (line_start..line_start, Cow::Borrowed(to_insert))
13048                            } else {
13049                                let language = snapshot.language_at(selection.head());
13050                                let range = selection.range();
13051                                if let Some(language) = language
13052                                    && language.name() == "Markdown".into()
13053                                {
13054                                    edit_for_markdown_paste(
13055                                        &snapshot,
13056                                        range,
13057                                        to_insert,
13058                                        url::Url::parse(to_insert).ok(),
13059                                    )
13060                                } else {
13061                                    (range, Cow::Borrowed(to_insert))
13062                                }
13063                            };
13064
13065                        edits.push((range, to_insert));
13066                        original_indent_columns.push(original_indent_column);
13067                    }
13068                    drop(snapshot);
13069
13070                    buffer.edit(
13071                        edits,
13072                        if auto_indent_on_paste {
13073                            Some(AutoindentMode::Block {
13074                                original_indent_columns,
13075                            })
13076                        } else {
13077                            None
13078                        },
13079                        cx,
13080                    );
13081                });
13082
13083                let selections = this
13084                    .selections
13085                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13086                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13087            } else {
13088                let url = url::Url::parse(&clipboard_text).ok();
13089
13090                let auto_indent_mode = if !clipboard_text.is_empty() {
13091                    Some(AutoindentMode::Block {
13092                        original_indent_columns: Vec::new(),
13093                    })
13094                } else {
13095                    None
13096                };
13097
13098                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13099                    let snapshot = buffer.snapshot(cx);
13100
13101                    let anchors = old_selections
13102                        .iter()
13103                        .map(|s| {
13104                            let anchor = snapshot.anchor_after(s.head());
13105                            s.map(|_| anchor)
13106                        })
13107                        .collect::<Vec<_>>();
13108
13109                    let mut edits = Vec::new();
13110
13111                    for selection in old_selections.iter() {
13112                        let language = snapshot.language_at(selection.head());
13113                        let range = selection.range();
13114
13115                        let (edit_range, edit_text) = if let Some(language) = language
13116                            && language.name() == "Markdown".into()
13117                        {
13118                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13119                        } else {
13120                            (range, clipboard_text.clone())
13121                        };
13122
13123                        edits.push((edit_range, edit_text));
13124                    }
13125
13126                    drop(snapshot);
13127                    buffer.edit(edits, auto_indent_mode, cx);
13128
13129                    anchors
13130                });
13131
13132                this.change_selections(Default::default(), window, cx, |s| {
13133                    s.select_anchors(selection_anchors);
13134                });
13135            }
13136
13137            //   🤔                 |    ..     | show_in_menu |
13138            // | ..                  |   true        true
13139            // | had_edit_prediction |   false       true
13140
13141            let trigger_in_words =
13142                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13143
13144            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13145        });
13146    }
13147
13148    pub fn diff_clipboard_with_selection(
13149        &mut self,
13150        _: &DiffClipboardWithSelection,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        let selections = self
13155            .selections
13156            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13157
13158        if selections.is_empty() {
13159            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13160            return;
13161        };
13162
13163        let clipboard_text = match cx.read_from_clipboard() {
13164            Some(item) => match item.entries().first() {
13165                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13166                _ => None,
13167            },
13168            None => None,
13169        };
13170
13171        let Some(clipboard_text) = clipboard_text else {
13172            log::warn!("Clipboard doesn't contain text.");
13173            return;
13174        };
13175
13176        window.dispatch_action(
13177            Box::new(DiffClipboardWithSelectionData {
13178                clipboard_text,
13179                editor: cx.entity(),
13180            }),
13181            cx,
13182        );
13183    }
13184
13185    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13186        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13187        if let Some(item) = cx.read_from_clipboard() {
13188            let entries = item.entries();
13189
13190            match entries.first() {
13191                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13192                // of all the pasted entries.
13193                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13194                    .do_paste(
13195                        clipboard_string.text(),
13196                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13197                        true,
13198                        window,
13199                        cx,
13200                    ),
13201                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13202            }
13203        }
13204    }
13205
13206    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13207        if self.read_only(cx) {
13208            return;
13209        }
13210
13211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13212
13213        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13214            if let Some((selections, _)) =
13215                self.selection_history.transaction(transaction_id).cloned()
13216            {
13217                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13218                    s.select_anchors(selections.to_vec());
13219                });
13220            } else {
13221                log::error!(
13222                    "No entry in selection_history found for undo. \
13223                     This may correspond to a bug where undo does not update the selection. \
13224                     If this is occurring, please add details to \
13225                     https://github.com/zed-industries/zed/issues/22692"
13226                );
13227            }
13228            self.request_autoscroll(Autoscroll::fit(), cx);
13229            self.unmark_text(window, cx);
13230            self.refresh_edit_prediction(true, false, window, cx);
13231            cx.emit(EditorEvent::Edited { transaction_id });
13232            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13233        }
13234    }
13235
13236    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13237        if self.read_only(cx) {
13238            return;
13239        }
13240
13241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13242
13243        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13244            if let Some((_, Some(selections))) =
13245                self.selection_history.transaction(transaction_id).cloned()
13246            {
13247                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13248                    s.select_anchors(selections.to_vec());
13249                });
13250            } else {
13251                log::error!(
13252                    "No entry in selection_history found for redo. \
13253                     This may correspond to a bug where undo does not update the selection. \
13254                     If this is occurring, please add details to \
13255                     https://github.com/zed-industries/zed/issues/22692"
13256                );
13257            }
13258            self.request_autoscroll(Autoscroll::fit(), cx);
13259            self.unmark_text(window, cx);
13260            self.refresh_edit_prediction(true, false, window, cx);
13261            cx.emit(EditorEvent::Edited { transaction_id });
13262        }
13263    }
13264
13265    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13266        self.buffer
13267            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13268    }
13269
13270    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13271        self.buffer
13272            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13273    }
13274
13275    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13277        self.change_selections(Default::default(), window, cx, |s| {
13278            s.move_with(|map, selection| {
13279                let cursor = if selection.is_empty() {
13280                    movement::left(map, selection.start)
13281                } else {
13282                    selection.start
13283                };
13284                selection.collapse_to(cursor, SelectionGoal::None);
13285            });
13286        })
13287    }
13288
13289    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13291        self.change_selections(Default::default(), window, cx, |s| {
13292            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13293        })
13294    }
13295
13296    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13298        self.change_selections(Default::default(), window, cx, |s| {
13299            s.move_with(|map, selection| {
13300                let cursor = if selection.is_empty() {
13301                    movement::right(map, selection.end)
13302                } else {
13303                    selection.end
13304                };
13305                selection.collapse_to(cursor, SelectionGoal::None)
13306            });
13307        })
13308    }
13309
13310    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13312        self.change_selections(Default::default(), window, cx, |s| {
13313            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13314        });
13315    }
13316
13317    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13318        if self.take_rename(true, window, cx).is_some() {
13319            return;
13320        }
13321
13322        if self.mode.is_single_line() {
13323            cx.propagate();
13324            return;
13325        }
13326
13327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13328
13329        let text_layout_details = &self.text_layout_details(window);
13330        let selection_count = self.selections.count();
13331        let first_selection = self.selections.first_anchor();
13332
13333        self.change_selections(Default::default(), window, cx, |s| {
13334            s.move_with(|map, selection| {
13335                if !selection.is_empty() {
13336                    selection.goal = SelectionGoal::None;
13337                }
13338                let (cursor, goal) = movement::up(
13339                    map,
13340                    selection.start,
13341                    selection.goal,
13342                    false,
13343                    text_layout_details,
13344                );
13345                selection.collapse_to(cursor, goal);
13346            });
13347        });
13348
13349        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13350        {
13351            cx.propagate();
13352        }
13353    }
13354
13355    pub fn move_up_by_lines(
13356        &mut self,
13357        action: &MoveUpByLines,
13358        window: &mut Window,
13359        cx: &mut Context<Self>,
13360    ) {
13361        if self.take_rename(true, window, cx).is_some() {
13362            return;
13363        }
13364
13365        if self.mode.is_single_line() {
13366            cx.propagate();
13367            return;
13368        }
13369
13370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13371
13372        let text_layout_details = &self.text_layout_details(window);
13373
13374        self.change_selections(Default::default(), window, cx, |s| {
13375            s.move_with(|map, selection| {
13376                if !selection.is_empty() {
13377                    selection.goal = SelectionGoal::None;
13378                }
13379                let (cursor, goal) = movement::up_by_rows(
13380                    map,
13381                    selection.start,
13382                    action.lines,
13383                    selection.goal,
13384                    false,
13385                    text_layout_details,
13386                );
13387                selection.collapse_to(cursor, goal);
13388            });
13389        })
13390    }
13391
13392    pub fn move_down_by_lines(
13393        &mut self,
13394        action: &MoveDownByLines,
13395        window: &mut Window,
13396        cx: &mut Context<Self>,
13397    ) {
13398        if self.take_rename(true, window, cx).is_some() {
13399            return;
13400        }
13401
13402        if self.mode.is_single_line() {
13403            cx.propagate();
13404            return;
13405        }
13406
13407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13408
13409        let text_layout_details = &self.text_layout_details(window);
13410
13411        self.change_selections(Default::default(), window, cx, |s| {
13412            s.move_with(|map, selection| {
13413                if !selection.is_empty() {
13414                    selection.goal = SelectionGoal::None;
13415                }
13416                let (cursor, goal) = movement::down_by_rows(
13417                    map,
13418                    selection.start,
13419                    action.lines,
13420                    selection.goal,
13421                    false,
13422                    text_layout_details,
13423                );
13424                selection.collapse_to(cursor, goal);
13425            });
13426        })
13427    }
13428
13429    pub fn select_down_by_lines(
13430        &mut self,
13431        action: &SelectDownByLines,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        let text_layout_details = &self.text_layout_details(window);
13437        self.change_selections(Default::default(), window, cx, |s| {
13438            s.move_heads_with(|map, head, goal| {
13439                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13440            })
13441        })
13442    }
13443
13444    pub fn select_up_by_lines(
13445        &mut self,
13446        action: &SelectUpByLines,
13447        window: &mut Window,
13448        cx: &mut Context<Self>,
13449    ) {
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13451        let text_layout_details = &self.text_layout_details(window);
13452        self.change_selections(Default::default(), window, cx, |s| {
13453            s.move_heads_with(|map, head, goal| {
13454                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13455            })
13456        })
13457    }
13458
13459    pub fn select_page_up(
13460        &mut self,
13461        _: &SelectPageUp,
13462        window: &mut Window,
13463        cx: &mut Context<Self>,
13464    ) {
13465        let Some(row_count) = self.visible_row_count() else {
13466            return;
13467        };
13468
13469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13470
13471        let text_layout_details = &self.text_layout_details(window);
13472
13473        self.change_selections(Default::default(), window, cx, |s| {
13474            s.move_heads_with(|map, head, goal| {
13475                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13476            })
13477        })
13478    }
13479
13480    pub fn move_page_up(
13481        &mut self,
13482        action: &MovePageUp,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        if self.take_rename(true, window, cx).is_some() {
13487            return;
13488        }
13489
13490        if self
13491            .context_menu
13492            .borrow_mut()
13493            .as_mut()
13494            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13495            .unwrap_or(false)
13496        {
13497            return;
13498        }
13499
13500        if matches!(self.mode, EditorMode::SingleLine) {
13501            cx.propagate();
13502            return;
13503        }
13504
13505        let Some(row_count) = self.visible_row_count() else {
13506            return;
13507        };
13508
13509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13510
13511        let effects = if action.center_cursor {
13512            SelectionEffects::scroll(Autoscroll::center())
13513        } else {
13514            SelectionEffects::default()
13515        };
13516
13517        let text_layout_details = &self.text_layout_details(window);
13518
13519        self.change_selections(effects, window, cx, |s| {
13520            s.move_with(|map, selection| {
13521                if !selection.is_empty() {
13522                    selection.goal = SelectionGoal::None;
13523                }
13524                let (cursor, goal) = movement::up_by_rows(
13525                    map,
13526                    selection.end,
13527                    row_count,
13528                    selection.goal,
13529                    false,
13530                    text_layout_details,
13531                );
13532                selection.collapse_to(cursor, goal);
13533            });
13534        });
13535    }
13536
13537    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13539        let text_layout_details = &self.text_layout_details(window);
13540        self.change_selections(Default::default(), window, cx, |s| {
13541            s.move_heads_with(|map, head, goal| {
13542                movement::up(map, head, goal, false, text_layout_details)
13543            })
13544        })
13545    }
13546
13547    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13548        self.take_rename(true, window, cx);
13549
13550        if self.mode.is_single_line() {
13551            cx.propagate();
13552            return;
13553        }
13554
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13556
13557        let text_layout_details = &self.text_layout_details(window);
13558        let selection_count = self.selections.count();
13559        let first_selection = self.selections.first_anchor();
13560
13561        self.change_selections(Default::default(), window, cx, |s| {
13562            s.move_with(|map, selection| {
13563                if !selection.is_empty() {
13564                    selection.goal = SelectionGoal::None;
13565                }
13566                let (cursor, goal) = movement::down(
13567                    map,
13568                    selection.end,
13569                    selection.goal,
13570                    false,
13571                    text_layout_details,
13572                );
13573                selection.collapse_to(cursor, goal);
13574            });
13575        });
13576
13577        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13578        {
13579            cx.propagate();
13580        }
13581    }
13582
13583    pub fn select_page_down(
13584        &mut self,
13585        _: &SelectPageDown,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        let Some(row_count) = self.visible_row_count() else {
13590            return;
13591        };
13592
13593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13594
13595        let text_layout_details = &self.text_layout_details(window);
13596
13597        self.change_selections(Default::default(), window, cx, |s| {
13598            s.move_heads_with(|map, head, goal| {
13599                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13600            })
13601        })
13602    }
13603
13604    pub fn move_page_down(
13605        &mut self,
13606        action: &MovePageDown,
13607        window: &mut Window,
13608        cx: &mut Context<Self>,
13609    ) {
13610        if self.take_rename(true, window, cx).is_some() {
13611            return;
13612        }
13613
13614        if self
13615            .context_menu
13616            .borrow_mut()
13617            .as_mut()
13618            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13619            .unwrap_or(false)
13620        {
13621            return;
13622        }
13623
13624        if matches!(self.mode, EditorMode::SingleLine) {
13625            cx.propagate();
13626            return;
13627        }
13628
13629        let Some(row_count) = self.visible_row_count() else {
13630            return;
13631        };
13632
13633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13634
13635        let effects = if action.center_cursor {
13636            SelectionEffects::scroll(Autoscroll::center())
13637        } else {
13638            SelectionEffects::default()
13639        };
13640
13641        let text_layout_details = &self.text_layout_details(window);
13642        self.change_selections(effects, window, cx, |s| {
13643            s.move_with(|map, selection| {
13644                if !selection.is_empty() {
13645                    selection.goal = SelectionGoal::None;
13646                }
13647                let (cursor, goal) = movement::down_by_rows(
13648                    map,
13649                    selection.end,
13650                    row_count,
13651                    selection.goal,
13652                    false,
13653                    text_layout_details,
13654                );
13655                selection.collapse_to(cursor, goal);
13656            });
13657        });
13658    }
13659
13660    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        let text_layout_details = &self.text_layout_details(window);
13663        self.change_selections(Default::default(), window, cx, |s| {
13664            s.move_heads_with(|map, head, goal| {
13665                movement::down(map, head, goal, false, text_layout_details)
13666            })
13667        });
13668    }
13669
13670    pub fn context_menu_first(
13671        &mut self,
13672        _: &ContextMenuFirst,
13673        window: &mut Window,
13674        cx: &mut Context<Self>,
13675    ) {
13676        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13677            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13678        }
13679    }
13680
13681    pub fn context_menu_prev(
13682        &mut self,
13683        _: &ContextMenuPrevious,
13684        window: &mut Window,
13685        cx: &mut Context<Self>,
13686    ) {
13687        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13688            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13689        }
13690    }
13691
13692    pub fn context_menu_next(
13693        &mut self,
13694        _: &ContextMenuNext,
13695        window: &mut Window,
13696        cx: &mut Context<Self>,
13697    ) {
13698        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13699            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13700        }
13701    }
13702
13703    pub fn context_menu_last(
13704        &mut self,
13705        _: &ContextMenuLast,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13710            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13711        }
13712    }
13713
13714    pub fn signature_help_prev(
13715        &mut self,
13716        _: &SignatureHelpPrevious,
13717        _: &mut Window,
13718        cx: &mut Context<Self>,
13719    ) {
13720        if let Some(popover) = self.signature_help_state.popover_mut() {
13721            if popover.current_signature == 0 {
13722                popover.current_signature = popover.signatures.len() - 1;
13723            } else {
13724                popover.current_signature -= 1;
13725            }
13726            cx.notify();
13727        }
13728    }
13729
13730    pub fn signature_help_next(
13731        &mut self,
13732        _: &SignatureHelpNext,
13733        _: &mut Window,
13734        cx: &mut Context<Self>,
13735    ) {
13736        if let Some(popover) = self.signature_help_state.popover_mut() {
13737            if popover.current_signature + 1 == popover.signatures.len() {
13738                popover.current_signature = 0;
13739            } else {
13740                popover.current_signature += 1;
13741            }
13742            cx.notify();
13743        }
13744    }
13745
13746    pub fn move_to_previous_word_start(
13747        &mut self,
13748        _: &MoveToPreviousWordStart,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.move_cursors_with(|map, head, _| {
13755                (
13756                    movement::previous_word_start(map, head),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn move_to_previous_subword_start(
13764        &mut self,
13765        _: &MoveToPreviousSubwordStart,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13770        self.change_selections(Default::default(), window, cx, |s| {
13771            s.move_cursors_with(|map, head, _| {
13772                (
13773                    movement::previous_subword_start(map, head),
13774                    SelectionGoal::None,
13775                )
13776            });
13777        })
13778    }
13779
13780    pub fn select_to_previous_word_start(
13781        &mut self,
13782        _: &SelectToPreviousWordStart,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) {
13786        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13787        self.change_selections(Default::default(), window, cx, |s| {
13788            s.move_heads_with(|map, head, _| {
13789                (
13790                    movement::previous_word_start(map, head),
13791                    SelectionGoal::None,
13792                )
13793            });
13794        })
13795    }
13796
13797    pub fn select_to_previous_subword_start(
13798        &mut self,
13799        _: &SelectToPreviousSubwordStart,
13800        window: &mut Window,
13801        cx: &mut Context<Self>,
13802    ) {
13803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13804        self.change_selections(Default::default(), window, cx, |s| {
13805            s.move_heads_with(|map, head, _| {
13806                (
13807                    movement::previous_subword_start(map, head),
13808                    SelectionGoal::None,
13809                )
13810            });
13811        })
13812    }
13813
13814    pub fn delete_to_previous_word_start(
13815        &mut self,
13816        action: &DeleteToPreviousWordStart,
13817        window: &mut Window,
13818        cx: &mut Context<Self>,
13819    ) {
13820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13821        self.transact(window, cx, |this, window, cx| {
13822            this.select_autoclose_pair(window, cx);
13823            this.change_selections(Default::default(), window, cx, |s| {
13824                s.move_with(|map, selection| {
13825                    if selection.is_empty() {
13826                        let mut cursor = if action.ignore_newlines {
13827                            movement::previous_word_start(map, selection.head())
13828                        } else {
13829                            movement::previous_word_start_or_newline(map, selection.head())
13830                        };
13831                        cursor = movement::adjust_greedy_deletion(
13832                            map,
13833                            selection.head(),
13834                            cursor,
13835                            action.ignore_brackets,
13836                        );
13837                        selection.set_head(cursor, SelectionGoal::None);
13838                    }
13839                });
13840            });
13841            this.insert("", window, cx);
13842        });
13843    }
13844
13845    pub fn delete_to_previous_subword_start(
13846        &mut self,
13847        _: &DeleteToPreviousSubwordStart,
13848        window: &mut Window,
13849        cx: &mut Context<Self>,
13850    ) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13852        self.transact(window, cx, |this, window, cx| {
13853            this.select_autoclose_pair(window, cx);
13854            this.change_selections(Default::default(), window, cx, |s| {
13855                s.move_with(|map, selection| {
13856                    if selection.is_empty() {
13857                        let mut cursor = movement::previous_subword_start(map, selection.head());
13858                        cursor =
13859                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13860                        selection.set_head(cursor, SelectionGoal::None);
13861                    }
13862                });
13863            });
13864            this.insert("", window, cx);
13865        });
13866    }
13867
13868    pub fn move_to_next_word_end(
13869        &mut self,
13870        _: &MoveToNextWordEnd,
13871        window: &mut Window,
13872        cx: &mut Context<Self>,
13873    ) {
13874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13875        self.change_selections(Default::default(), window, cx, |s| {
13876            s.move_cursors_with(|map, head, _| {
13877                (movement::next_word_end(map, head), SelectionGoal::None)
13878            });
13879        })
13880    }
13881
13882    pub fn move_to_next_subword_end(
13883        &mut self,
13884        _: &MoveToNextSubwordEnd,
13885        window: &mut Window,
13886        cx: &mut Context<Self>,
13887    ) {
13888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13889        self.change_selections(Default::default(), window, cx, |s| {
13890            s.move_cursors_with(|map, head, _| {
13891                (movement::next_subword_end(map, head), SelectionGoal::None)
13892            });
13893        })
13894    }
13895
13896    pub fn select_to_next_word_end(
13897        &mut self,
13898        _: &SelectToNextWordEnd,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13903        self.change_selections(Default::default(), window, cx, |s| {
13904            s.move_heads_with(|map, head, _| {
13905                (movement::next_word_end(map, head), SelectionGoal::None)
13906            });
13907        })
13908    }
13909
13910    pub fn select_to_next_subword_end(
13911        &mut self,
13912        _: &SelectToNextSubwordEnd,
13913        window: &mut Window,
13914        cx: &mut Context<Self>,
13915    ) {
13916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13917        self.change_selections(Default::default(), window, cx, |s| {
13918            s.move_heads_with(|map, head, _| {
13919                (movement::next_subword_end(map, head), SelectionGoal::None)
13920            });
13921        })
13922    }
13923
13924    pub fn delete_to_next_word_end(
13925        &mut self,
13926        action: &DeleteToNextWordEnd,
13927        window: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) {
13930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13931        self.transact(window, cx, |this, window, cx| {
13932            this.change_selections(Default::default(), window, cx, |s| {
13933                s.move_with(|map, selection| {
13934                    if selection.is_empty() {
13935                        let mut cursor = if action.ignore_newlines {
13936                            movement::next_word_end(map, selection.head())
13937                        } else {
13938                            movement::next_word_end_or_newline(map, selection.head())
13939                        };
13940                        cursor = movement::adjust_greedy_deletion(
13941                            map,
13942                            selection.head(),
13943                            cursor,
13944                            action.ignore_brackets,
13945                        );
13946                        selection.set_head(cursor, SelectionGoal::None);
13947                    }
13948                });
13949            });
13950            this.insert("", window, cx);
13951        });
13952    }
13953
13954    pub fn delete_to_next_subword_end(
13955        &mut self,
13956        _: &DeleteToNextSubwordEnd,
13957        window: &mut Window,
13958        cx: &mut Context<Self>,
13959    ) {
13960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13961        self.transact(window, cx, |this, window, cx| {
13962            this.change_selections(Default::default(), window, cx, |s| {
13963                s.move_with(|map, selection| {
13964                    if selection.is_empty() {
13965                        let mut cursor = movement::next_subword_end(map, selection.head());
13966                        cursor =
13967                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13968                        selection.set_head(cursor, SelectionGoal::None);
13969                    }
13970                });
13971            });
13972            this.insert("", window, cx);
13973        });
13974    }
13975
13976    pub fn move_to_beginning_of_line(
13977        &mut self,
13978        action: &MoveToBeginningOfLine,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13983        self.change_selections(Default::default(), window, cx, |s| {
13984            s.move_cursors_with(|map, head, _| {
13985                (
13986                    movement::indented_line_beginning(
13987                        map,
13988                        head,
13989                        action.stop_at_soft_wraps,
13990                        action.stop_at_indent,
13991                    ),
13992                    SelectionGoal::None,
13993                )
13994            });
13995        })
13996    }
13997
13998    pub fn select_to_beginning_of_line(
13999        &mut self,
14000        action: &SelectToBeginningOfLine,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) {
14004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14005        self.change_selections(Default::default(), window, cx, |s| {
14006            s.move_heads_with(|map, head, _| {
14007                (
14008                    movement::indented_line_beginning(
14009                        map,
14010                        head,
14011                        action.stop_at_soft_wraps,
14012                        action.stop_at_indent,
14013                    ),
14014                    SelectionGoal::None,
14015                )
14016            });
14017        });
14018    }
14019
14020    pub fn delete_to_beginning_of_line(
14021        &mut self,
14022        action: &DeleteToBeginningOfLine,
14023        window: &mut Window,
14024        cx: &mut Context<Self>,
14025    ) {
14026        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14027        self.transact(window, cx, |this, window, cx| {
14028            this.change_selections(Default::default(), window, cx, |s| {
14029                s.move_with(|_, selection| {
14030                    selection.reversed = true;
14031                });
14032            });
14033
14034            this.select_to_beginning_of_line(
14035                &SelectToBeginningOfLine {
14036                    stop_at_soft_wraps: false,
14037                    stop_at_indent: action.stop_at_indent,
14038                },
14039                window,
14040                cx,
14041            );
14042            this.backspace(&Backspace, window, cx);
14043        });
14044    }
14045
14046    pub fn move_to_end_of_line(
14047        &mut self,
14048        action: &MoveToEndOfLine,
14049        window: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14053        self.change_selections(Default::default(), window, cx, |s| {
14054            s.move_cursors_with(|map, head, _| {
14055                (
14056                    movement::line_end(map, head, action.stop_at_soft_wraps),
14057                    SelectionGoal::None,
14058                )
14059            });
14060        })
14061    }
14062
14063    pub fn select_to_end_of_line(
14064        &mut self,
14065        action: &SelectToEndOfLine,
14066        window: &mut Window,
14067        cx: &mut Context<Self>,
14068    ) {
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.move_heads_with(|map, head, _| {
14072                (
14073                    movement::line_end(map, head, action.stop_at_soft_wraps),
14074                    SelectionGoal::None,
14075                )
14076            });
14077        })
14078    }
14079
14080    pub fn delete_to_end_of_line(
14081        &mut self,
14082        _: &DeleteToEndOfLine,
14083        window: &mut Window,
14084        cx: &mut Context<Self>,
14085    ) {
14086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14087        self.transact(window, cx, |this, window, cx| {
14088            this.select_to_end_of_line(
14089                &SelectToEndOfLine {
14090                    stop_at_soft_wraps: false,
14091                },
14092                window,
14093                cx,
14094            );
14095            this.delete(&Delete, window, cx);
14096        });
14097    }
14098
14099    pub fn cut_to_end_of_line(
14100        &mut self,
14101        action: &CutToEndOfLine,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) {
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14106        self.transact(window, cx, |this, window, cx| {
14107            this.select_to_end_of_line(
14108                &SelectToEndOfLine {
14109                    stop_at_soft_wraps: false,
14110                },
14111                window,
14112                cx,
14113            );
14114            if !action.stop_at_newlines {
14115                this.change_selections(Default::default(), window, cx, |s| {
14116                    s.move_with(|_, sel| {
14117                        if sel.is_empty() {
14118                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14119                        }
14120                    });
14121                });
14122            }
14123            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14124            let item = this.cut_common(false, window, cx);
14125            cx.write_to_clipboard(item);
14126        });
14127    }
14128
14129    pub fn move_to_start_of_paragraph(
14130        &mut self,
14131        _: &MoveToStartOfParagraph,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        if matches!(self.mode, EditorMode::SingleLine) {
14136            cx.propagate();
14137            return;
14138        }
14139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14140        self.change_selections(Default::default(), window, cx, |s| {
14141            s.move_with(|map, selection| {
14142                selection.collapse_to(
14143                    movement::start_of_paragraph(map, selection.head(), 1),
14144                    SelectionGoal::None,
14145                )
14146            });
14147        })
14148    }
14149
14150    pub fn move_to_end_of_paragraph(
14151        &mut self,
14152        _: &MoveToEndOfParagraph,
14153        window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        if matches!(self.mode, EditorMode::SingleLine) {
14157            cx.propagate();
14158            return;
14159        }
14160        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14161        self.change_selections(Default::default(), window, cx, |s| {
14162            s.move_with(|map, selection| {
14163                selection.collapse_to(
14164                    movement::end_of_paragraph(map, selection.head(), 1),
14165                    SelectionGoal::None,
14166                )
14167            });
14168        })
14169    }
14170
14171    pub fn select_to_start_of_paragraph(
14172        &mut self,
14173        _: &SelectToStartOfParagraph,
14174        window: &mut Window,
14175        cx: &mut Context<Self>,
14176    ) {
14177        if matches!(self.mode, EditorMode::SingleLine) {
14178            cx.propagate();
14179            return;
14180        }
14181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14182        self.change_selections(Default::default(), window, cx, |s| {
14183            s.move_heads_with(|map, head, _| {
14184                (
14185                    movement::start_of_paragraph(map, head, 1),
14186                    SelectionGoal::None,
14187                )
14188            });
14189        })
14190    }
14191
14192    pub fn select_to_end_of_paragraph(
14193        &mut self,
14194        _: &SelectToEndOfParagraph,
14195        window: &mut Window,
14196        cx: &mut Context<Self>,
14197    ) {
14198        if matches!(self.mode, EditorMode::SingleLine) {
14199            cx.propagate();
14200            return;
14201        }
14202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14203        self.change_selections(Default::default(), window, cx, |s| {
14204            s.move_heads_with(|map, head, _| {
14205                (
14206                    movement::end_of_paragraph(map, head, 1),
14207                    SelectionGoal::None,
14208                )
14209            });
14210        })
14211    }
14212
14213    pub fn move_to_start_of_excerpt(
14214        &mut self,
14215        _: &MoveToStartOfExcerpt,
14216        window: &mut Window,
14217        cx: &mut Context<Self>,
14218    ) {
14219        if matches!(self.mode, EditorMode::SingleLine) {
14220            cx.propagate();
14221            return;
14222        }
14223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14224        self.change_selections(Default::default(), window, cx, |s| {
14225            s.move_with(|map, selection| {
14226                selection.collapse_to(
14227                    movement::start_of_excerpt(
14228                        map,
14229                        selection.head(),
14230                        workspace::searchable::Direction::Prev,
14231                    ),
14232                    SelectionGoal::None,
14233                )
14234            });
14235        })
14236    }
14237
14238    pub fn move_to_start_of_next_excerpt(
14239        &mut self,
14240        _: &MoveToStartOfNextExcerpt,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) {
14244        if matches!(self.mode, EditorMode::SingleLine) {
14245            cx.propagate();
14246            return;
14247        }
14248
14249        self.change_selections(Default::default(), window, cx, |s| {
14250            s.move_with(|map, selection| {
14251                selection.collapse_to(
14252                    movement::start_of_excerpt(
14253                        map,
14254                        selection.head(),
14255                        workspace::searchable::Direction::Next,
14256                    ),
14257                    SelectionGoal::None,
14258                )
14259            });
14260        })
14261    }
14262
14263    pub fn move_to_end_of_excerpt(
14264        &mut self,
14265        _: &MoveToEndOfExcerpt,
14266        window: &mut Window,
14267        cx: &mut Context<Self>,
14268    ) {
14269        if matches!(self.mode, EditorMode::SingleLine) {
14270            cx.propagate();
14271            return;
14272        }
14273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14274        self.change_selections(Default::default(), window, cx, |s| {
14275            s.move_with(|map, selection| {
14276                selection.collapse_to(
14277                    movement::end_of_excerpt(
14278                        map,
14279                        selection.head(),
14280                        workspace::searchable::Direction::Next,
14281                    ),
14282                    SelectionGoal::None,
14283                )
14284            });
14285        })
14286    }
14287
14288    pub fn move_to_end_of_previous_excerpt(
14289        &mut self,
14290        _: &MoveToEndOfPreviousExcerpt,
14291        window: &mut Window,
14292        cx: &mut Context<Self>,
14293    ) {
14294        if matches!(self.mode, EditorMode::SingleLine) {
14295            cx.propagate();
14296            return;
14297        }
14298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14299        self.change_selections(Default::default(), window, cx, |s| {
14300            s.move_with(|map, selection| {
14301                selection.collapse_to(
14302                    movement::end_of_excerpt(
14303                        map,
14304                        selection.head(),
14305                        workspace::searchable::Direction::Prev,
14306                    ),
14307                    SelectionGoal::None,
14308                )
14309            });
14310        })
14311    }
14312
14313    pub fn select_to_start_of_excerpt(
14314        &mut self,
14315        _: &SelectToStartOfExcerpt,
14316        window: &mut Window,
14317        cx: &mut Context<Self>,
14318    ) {
14319        if matches!(self.mode, EditorMode::SingleLine) {
14320            cx.propagate();
14321            return;
14322        }
14323        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14324        self.change_selections(Default::default(), window, cx, |s| {
14325            s.move_heads_with(|map, head, _| {
14326                (
14327                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14328                    SelectionGoal::None,
14329                )
14330            });
14331        })
14332    }
14333
14334    pub fn select_to_start_of_next_excerpt(
14335        &mut self,
14336        _: &SelectToStartOfNextExcerpt,
14337        window: &mut Window,
14338        cx: &mut Context<Self>,
14339    ) {
14340        if matches!(self.mode, EditorMode::SingleLine) {
14341            cx.propagate();
14342            return;
14343        }
14344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14345        self.change_selections(Default::default(), window, cx, |s| {
14346            s.move_heads_with(|map, head, _| {
14347                (
14348                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14349                    SelectionGoal::None,
14350                )
14351            });
14352        })
14353    }
14354
14355    pub fn select_to_end_of_excerpt(
14356        &mut self,
14357        _: &SelectToEndOfExcerpt,
14358        window: &mut Window,
14359        cx: &mut Context<Self>,
14360    ) {
14361        if matches!(self.mode, EditorMode::SingleLine) {
14362            cx.propagate();
14363            return;
14364        }
14365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14366        self.change_selections(Default::default(), window, cx, |s| {
14367            s.move_heads_with(|map, head, _| {
14368                (
14369                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14370                    SelectionGoal::None,
14371                )
14372            });
14373        })
14374    }
14375
14376    pub fn select_to_end_of_previous_excerpt(
14377        &mut self,
14378        _: &SelectToEndOfPreviousExcerpt,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        if matches!(self.mode, EditorMode::SingleLine) {
14383            cx.propagate();
14384            return;
14385        }
14386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14387        self.change_selections(Default::default(), window, cx, |s| {
14388            s.move_heads_with(|map, head, _| {
14389                (
14390                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14391                    SelectionGoal::None,
14392                )
14393            });
14394        })
14395    }
14396
14397    pub fn move_to_beginning(
14398        &mut self,
14399        _: &MoveToBeginning,
14400        window: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) {
14403        if matches!(self.mode, EditorMode::SingleLine) {
14404            cx.propagate();
14405            return;
14406        }
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        self.change_selections(Default::default(), window, cx, |s| {
14409            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14410        });
14411    }
14412
14413    pub fn select_to_beginning(
14414        &mut self,
14415        _: &SelectToBeginning,
14416        window: &mut Window,
14417        cx: &mut Context<Self>,
14418    ) {
14419        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14420        selection.set_head(Point::zero(), SelectionGoal::None);
14421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14422        self.change_selections(Default::default(), window, cx, |s| {
14423            s.select(vec![selection]);
14424        });
14425    }
14426
14427    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14428        if matches!(self.mode, EditorMode::SingleLine) {
14429            cx.propagate();
14430            return;
14431        }
14432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14433        let cursor = self.buffer.read(cx).read(cx).len();
14434        self.change_selections(Default::default(), window, cx, |s| {
14435            s.select_ranges(vec![cursor..cursor])
14436        });
14437    }
14438
14439    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14440        self.nav_history = nav_history;
14441    }
14442
14443    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14444        self.nav_history.as_ref()
14445    }
14446
14447    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14448        self.push_to_nav_history(
14449            self.selections.newest_anchor().head(),
14450            None,
14451            false,
14452            true,
14453            cx,
14454        );
14455    }
14456
14457    fn push_to_nav_history(
14458        &mut self,
14459        cursor_anchor: Anchor,
14460        new_position: Option<Point>,
14461        is_deactivate: bool,
14462        always: bool,
14463        cx: &mut Context<Self>,
14464    ) {
14465        if let Some(nav_history) = self.nav_history.as_mut() {
14466            let buffer = self.buffer.read(cx).read(cx);
14467            let cursor_position = cursor_anchor.to_point(&buffer);
14468            let scroll_state = self.scroll_manager.anchor();
14469            let scroll_top_row = scroll_state.top_row(&buffer);
14470            drop(buffer);
14471
14472            if let Some(new_position) = new_position {
14473                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14474                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14475                    return;
14476                }
14477            }
14478
14479            nav_history.push(
14480                Some(NavigationData {
14481                    cursor_anchor,
14482                    cursor_position,
14483                    scroll_anchor: scroll_state,
14484                    scroll_top_row,
14485                }),
14486                cx,
14487            );
14488            cx.emit(EditorEvent::PushedToNavHistory {
14489                anchor: cursor_anchor,
14490                is_deactivate,
14491            })
14492        }
14493    }
14494
14495    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14497        let buffer = self.buffer.read(cx).snapshot(cx);
14498        let mut selection = self
14499            .selections
14500            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14501        selection.set_head(buffer.len(), SelectionGoal::None);
14502        self.change_selections(Default::default(), window, cx, |s| {
14503            s.select(vec![selection]);
14504        });
14505    }
14506
14507    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14509        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14510            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14511        });
14512    }
14513
14514    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14517        let mut selections = self.selections.all::<Point>(&display_map);
14518        let max_point = display_map.buffer_snapshot().max_point();
14519        for selection in &mut selections {
14520            let rows = selection.spanned_rows(true, &display_map);
14521            selection.start = Point::new(rows.start.0, 0);
14522            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14523            selection.reversed = false;
14524        }
14525        self.change_selections(Default::default(), window, cx, |s| {
14526            s.select(selections);
14527        });
14528    }
14529
14530    pub fn split_selection_into_lines(
14531        &mut self,
14532        action: &SplitSelectionIntoLines,
14533        window: &mut Window,
14534        cx: &mut Context<Self>,
14535    ) {
14536        let selections = self
14537            .selections
14538            .all::<Point>(&self.display_snapshot(cx))
14539            .into_iter()
14540            .map(|selection| selection.start..selection.end)
14541            .collect::<Vec<_>>();
14542        self.unfold_ranges(&selections, true, true, cx);
14543
14544        let mut new_selection_ranges = Vec::new();
14545        {
14546            let buffer = self.buffer.read(cx).read(cx);
14547            for selection in selections {
14548                for row in selection.start.row..selection.end.row {
14549                    let line_start = Point::new(row, 0);
14550                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14551
14552                    if action.keep_selections {
14553                        // Keep the selection range for each line
14554                        let selection_start = if row == selection.start.row {
14555                            selection.start
14556                        } else {
14557                            line_start
14558                        };
14559                        new_selection_ranges.push(selection_start..line_end);
14560                    } else {
14561                        // Collapse to cursor at end of line
14562                        new_selection_ranges.push(line_end..line_end);
14563                    }
14564                }
14565
14566                let is_multiline_selection = selection.start.row != selection.end.row;
14567                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14568                // so this action feels more ergonomic when paired with other selection operations
14569                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14570                if !should_skip_last {
14571                    if action.keep_selections {
14572                        if is_multiline_selection {
14573                            let line_start = Point::new(selection.end.row, 0);
14574                            new_selection_ranges.push(line_start..selection.end);
14575                        } else {
14576                            new_selection_ranges.push(selection.start..selection.end);
14577                        }
14578                    } else {
14579                        new_selection_ranges.push(selection.end..selection.end);
14580                    }
14581                }
14582            }
14583        }
14584        self.change_selections(Default::default(), window, cx, |s| {
14585            s.select_ranges(new_selection_ranges);
14586        });
14587    }
14588
14589    pub fn add_selection_above(
14590        &mut self,
14591        action: &AddSelectionAbove,
14592        window: &mut Window,
14593        cx: &mut Context<Self>,
14594    ) {
14595        self.add_selection(true, action.skip_soft_wrap, window, cx);
14596    }
14597
14598    pub fn add_selection_below(
14599        &mut self,
14600        action: &AddSelectionBelow,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) {
14604        self.add_selection(false, action.skip_soft_wrap, window, cx);
14605    }
14606
14607    fn add_selection(
14608        &mut self,
14609        above: bool,
14610        skip_soft_wrap: bool,
14611        window: &mut Window,
14612        cx: &mut Context<Self>,
14613    ) {
14614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14615
14616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14617        let all_selections = self.selections.all::<Point>(&display_map);
14618        let text_layout_details = self.text_layout_details(window);
14619
14620        let (mut columnar_selections, new_selections_to_columnarize) = {
14621            if let Some(state) = self.add_selections_state.as_ref() {
14622                let columnar_selection_ids: HashSet<_> = state
14623                    .groups
14624                    .iter()
14625                    .flat_map(|group| group.stack.iter())
14626                    .copied()
14627                    .collect();
14628
14629                all_selections
14630                    .into_iter()
14631                    .partition(|s| columnar_selection_ids.contains(&s.id))
14632            } else {
14633                (Vec::new(), all_selections)
14634            }
14635        };
14636
14637        let mut state = self
14638            .add_selections_state
14639            .take()
14640            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14641
14642        for selection in new_selections_to_columnarize {
14643            let range = selection.display_range(&display_map).sorted();
14644            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14645            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14646            let positions = start_x.min(end_x)..start_x.max(end_x);
14647            let mut stack = Vec::new();
14648            for row in range.start.row().0..=range.end.row().0 {
14649                if let Some(selection) = self.selections.build_columnar_selection(
14650                    &display_map,
14651                    DisplayRow(row),
14652                    &positions,
14653                    selection.reversed,
14654                    &text_layout_details,
14655                ) {
14656                    stack.push(selection.id);
14657                    columnar_selections.push(selection);
14658                }
14659            }
14660            if !stack.is_empty() {
14661                if above {
14662                    stack.reverse();
14663                }
14664                state.groups.push(AddSelectionsGroup { above, stack });
14665            }
14666        }
14667
14668        let mut final_selections = Vec::new();
14669        let end_row = if above {
14670            DisplayRow(0)
14671        } else {
14672            display_map.max_point().row()
14673        };
14674
14675        let mut last_added_item_per_group = HashMap::default();
14676        for group in state.groups.iter_mut() {
14677            if let Some(last_id) = group.stack.last() {
14678                last_added_item_per_group.insert(*last_id, group);
14679            }
14680        }
14681
14682        for selection in columnar_selections {
14683            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14684                if above == group.above {
14685                    let range = selection.display_range(&display_map).sorted();
14686                    debug_assert_eq!(range.start.row(), range.end.row());
14687                    let mut row = range.start.row();
14688                    let positions =
14689                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14690                            Pixels::from(start)..Pixels::from(end)
14691                        } else {
14692                            let start_x =
14693                                display_map.x_for_display_point(range.start, &text_layout_details);
14694                            let end_x =
14695                                display_map.x_for_display_point(range.end, &text_layout_details);
14696                            start_x.min(end_x)..start_x.max(end_x)
14697                        };
14698
14699                    let mut maybe_new_selection = None;
14700                    let direction = if above { -1 } else { 1 };
14701
14702                    while row != end_row {
14703                        if skip_soft_wrap {
14704                            row = display_map
14705                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14706                                .row();
14707                        } else if above {
14708                            row.0 -= 1;
14709                        } else {
14710                            row.0 += 1;
14711                        }
14712
14713                        if let Some(new_selection) = self.selections.build_columnar_selection(
14714                            &display_map,
14715                            row,
14716                            &positions,
14717                            selection.reversed,
14718                            &text_layout_details,
14719                        ) {
14720                            maybe_new_selection = Some(new_selection);
14721                            break;
14722                        }
14723                    }
14724
14725                    if let Some(new_selection) = maybe_new_selection {
14726                        group.stack.push(new_selection.id);
14727                        if above {
14728                            final_selections.push(new_selection);
14729                            final_selections.push(selection);
14730                        } else {
14731                            final_selections.push(selection);
14732                            final_selections.push(new_selection);
14733                        }
14734                    } else {
14735                        final_selections.push(selection);
14736                    }
14737                } else {
14738                    group.stack.pop();
14739                }
14740            } else {
14741                final_selections.push(selection);
14742            }
14743        }
14744
14745        self.change_selections(Default::default(), window, cx, |s| {
14746            s.select(final_selections);
14747        });
14748
14749        let final_selection_ids: HashSet<_> = self
14750            .selections
14751            .all::<Point>(&display_map)
14752            .iter()
14753            .map(|s| s.id)
14754            .collect();
14755        state.groups.retain_mut(|group| {
14756            // selections might get merged above so we remove invalid items from stacks
14757            group.stack.retain(|id| final_selection_ids.contains(id));
14758
14759            // single selection in stack can be treated as initial state
14760            group.stack.len() > 1
14761        });
14762
14763        if !state.groups.is_empty() {
14764            self.add_selections_state = Some(state);
14765        }
14766    }
14767
14768    fn select_match_ranges(
14769        &mut self,
14770        range: Range<MultiBufferOffset>,
14771        reversed: bool,
14772        replace_newest: bool,
14773        auto_scroll: Option<Autoscroll>,
14774        window: &mut Window,
14775        cx: &mut Context<Editor>,
14776    ) {
14777        self.unfold_ranges(
14778            std::slice::from_ref(&range),
14779            false,
14780            auto_scroll.is_some(),
14781            cx,
14782        );
14783        let effects = if let Some(scroll) = auto_scroll {
14784            SelectionEffects::scroll(scroll)
14785        } else {
14786            SelectionEffects::no_scroll()
14787        };
14788        self.change_selections(effects, window, cx, |s| {
14789            if replace_newest {
14790                s.delete(s.newest_anchor().id);
14791            }
14792            if reversed {
14793                s.insert_range(range.end..range.start);
14794            } else {
14795                s.insert_range(range);
14796            }
14797        });
14798    }
14799
14800    pub fn select_next_match_internal(
14801        &mut self,
14802        display_map: &DisplaySnapshot,
14803        replace_newest: bool,
14804        autoscroll: Option<Autoscroll>,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) -> Result<()> {
14808        let buffer = display_map.buffer_snapshot();
14809        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14810        if let Some(mut select_next_state) = self.select_next_state.take() {
14811            let query = &select_next_state.query;
14812            if !select_next_state.done {
14813                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14814                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14815                let mut next_selected_range = None;
14816
14817                let bytes_after_last_selection =
14818                    buffer.bytes_in_range(last_selection.end..buffer.len());
14819                let bytes_before_first_selection =
14820                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14821                let query_matches = query
14822                    .stream_find_iter(bytes_after_last_selection)
14823                    .map(|result| (last_selection.end, result))
14824                    .chain(
14825                        query
14826                            .stream_find_iter(bytes_before_first_selection)
14827                            .map(|result| (MultiBufferOffset(0), result)),
14828                    );
14829
14830                for (start_offset, query_match) in query_matches {
14831                    let query_match = query_match.unwrap(); // can only fail due to I/O
14832                    let offset_range =
14833                        start_offset + query_match.start()..start_offset + query_match.end();
14834
14835                    if !select_next_state.wordwise
14836                        || (!buffer.is_inside_word(offset_range.start, None)
14837                            && !buffer.is_inside_word(offset_range.end, None))
14838                    {
14839                        let idx = selections
14840                            .partition_point(|selection| selection.end <= offset_range.start);
14841                        let overlaps = selections
14842                            .get(idx)
14843                            .map_or(false, |selection| selection.start < offset_range.end);
14844
14845                        if !overlaps {
14846                            next_selected_range = Some(offset_range);
14847                            break;
14848                        }
14849                    }
14850                }
14851
14852                if let Some(next_selected_range) = next_selected_range {
14853                    self.select_match_ranges(
14854                        next_selected_range,
14855                        last_selection.reversed,
14856                        replace_newest,
14857                        autoscroll,
14858                        window,
14859                        cx,
14860                    );
14861                } else {
14862                    select_next_state.done = true;
14863                }
14864            }
14865
14866            self.select_next_state = Some(select_next_state);
14867        } else {
14868            let mut only_carets = true;
14869            let mut same_text_selected = true;
14870            let mut selected_text = None;
14871
14872            let mut selections_iter = selections.iter().peekable();
14873            while let Some(selection) = selections_iter.next() {
14874                if selection.start != selection.end {
14875                    only_carets = false;
14876                }
14877
14878                if same_text_selected {
14879                    if selected_text.is_none() {
14880                        selected_text =
14881                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14882                    }
14883
14884                    if let Some(next_selection) = selections_iter.peek() {
14885                        if next_selection.len() == selection.len() {
14886                            let next_selected_text = buffer
14887                                .text_for_range(next_selection.range())
14888                                .collect::<String>();
14889                            if Some(next_selected_text) != selected_text {
14890                                same_text_selected = false;
14891                                selected_text = None;
14892                            }
14893                        } else {
14894                            same_text_selected = false;
14895                            selected_text = None;
14896                        }
14897                    }
14898                }
14899            }
14900
14901            if only_carets {
14902                for selection in &mut selections {
14903                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14904                    selection.start = word_range.start;
14905                    selection.end = word_range.end;
14906                    selection.goal = SelectionGoal::None;
14907                    selection.reversed = false;
14908                    self.select_match_ranges(
14909                        selection.start..selection.end,
14910                        selection.reversed,
14911                        replace_newest,
14912                        autoscroll,
14913                        window,
14914                        cx,
14915                    );
14916                }
14917
14918                if selections.len() == 1 {
14919                    let selection = selections
14920                        .last()
14921                        .expect("ensured that there's only one selection");
14922                    let query = buffer
14923                        .text_for_range(selection.start..selection.end)
14924                        .collect::<String>();
14925                    let is_empty = query.is_empty();
14926                    let select_state = SelectNextState {
14927                        query: self.build_query(&[query], cx)?,
14928                        wordwise: true,
14929                        done: is_empty,
14930                    };
14931                    self.select_next_state = Some(select_state);
14932                } else {
14933                    self.select_next_state = None;
14934                }
14935            } else if let Some(selected_text) = selected_text {
14936                self.select_next_state = Some(SelectNextState {
14937                    query: self.build_query(&[selected_text], cx)?,
14938                    wordwise: false,
14939                    done: false,
14940                });
14941                self.select_next_match_internal(
14942                    display_map,
14943                    replace_newest,
14944                    autoscroll,
14945                    window,
14946                    cx,
14947                )?;
14948            }
14949        }
14950        Ok(())
14951    }
14952
14953    pub fn select_all_matches(
14954        &mut self,
14955        _action: &SelectAllMatches,
14956        window: &mut Window,
14957        cx: &mut Context<Self>,
14958    ) -> Result<()> {
14959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14960
14961        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14962
14963        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14964        let Some(select_next_state) = self.select_next_state.as_mut() else {
14965            return Ok(());
14966        };
14967        if select_next_state.done {
14968            return Ok(());
14969        }
14970
14971        let mut new_selections = Vec::new();
14972
14973        let reversed = self
14974            .selections
14975            .oldest::<MultiBufferOffset>(&display_map)
14976            .reversed;
14977        let buffer = display_map.buffer_snapshot();
14978        let query_matches = select_next_state
14979            .query
14980            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14981
14982        for query_match in query_matches.into_iter() {
14983            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14984            let offset_range = if reversed {
14985                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14986            } else {
14987                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14988            };
14989
14990            if !select_next_state.wordwise
14991                || (!buffer.is_inside_word(offset_range.start, None)
14992                    && !buffer.is_inside_word(offset_range.end, None))
14993            {
14994                new_selections.push(offset_range.start..offset_range.end);
14995            }
14996        }
14997
14998        select_next_state.done = true;
14999
15000        if new_selections.is_empty() {
15001            log::error!("bug: new_selections is empty in select_all_matches");
15002            return Ok(());
15003        }
15004
15005        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15006        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15007            selections.select_ranges(new_selections)
15008        });
15009
15010        Ok(())
15011    }
15012
15013    pub fn select_next(
15014        &mut self,
15015        action: &SelectNext,
15016        window: &mut Window,
15017        cx: &mut Context<Self>,
15018    ) -> Result<()> {
15019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15020        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15021        self.select_next_match_internal(
15022            &display_map,
15023            action.replace_newest,
15024            Some(Autoscroll::newest()),
15025            window,
15026            cx,
15027        )?;
15028        Ok(())
15029    }
15030
15031    pub fn select_previous(
15032        &mut self,
15033        action: &SelectPrevious,
15034        window: &mut Window,
15035        cx: &mut Context<Self>,
15036    ) -> Result<()> {
15037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15038        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15039        let buffer = display_map.buffer_snapshot();
15040        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15041        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15042            let query = &select_prev_state.query;
15043            if !select_prev_state.done {
15044                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15045                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15046                let mut next_selected_range = None;
15047                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15048                let bytes_before_last_selection =
15049                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15050                let bytes_after_first_selection =
15051                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15052                let query_matches = query
15053                    .stream_find_iter(bytes_before_last_selection)
15054                    .map(|result| (last_selection.start, result))
15055                    .chain(
15056                        query
15057                            .stream_find_iter(bytes_after_first_selection)
15058                            .map(|result| (buffer.len(), result)),
15059                    );
15060                for (end_offset, query_match) in query_matches {
15061                    let query_match = query_match.unwrap(); // can only fail due to I/O
15062                    let offset_range =
15063                        end_offset - query_match.end()..end_offset - query_match.start();
15064
15065                    if !select_prev_state.wordwise
15066                        || (!buffer.is_inside_word(offset_range.start, None)
15067                            && !buffer.is_inside_word(offset_range.end, None))
15068                    {
15069                        next_selected_range = Some(offset_range);
15070                        break;
15071                    }
15072                }
15073
15074                if let Some(next_selected_range) = next_selected_range {
15075                    self.select_match_ranges(
15076                        next_selected_range,
15077                        last_selection.reversed,
15078                        action.replace_newest,
15079                        Some(Autoscroll::newest()),
15080                        window,
15081                        cx,
15082                    );
15083                } else {
15084                    select_prev_state.done = true;
15085                }
15086            }
15087
15088            self.select_prev_state = Some(select_prev_state);
15089        } else {
15090            let mut only_carets = true;
15091            let mut same_text_selected = true;
15092            let mut selected_text = None;
15093
15094            let mut selections_iter = selections.iter().peekable();
15095            while let Some(selection) = selections_iter.next() {
15096                if selection.start != selection.end {
15097                    only_carets = false;
15098                }
15099
15100                if same_text_selected {
15101                    if selected_text.is_none() {
15102                        selected_text =
15103                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15104                    }
15105
15106                    if let Some(next_selection) = selections_iter.peek() {
15107                        if next_selection.len() == selection.len() {
15108                            let next_selected_text = buffer
15109                                .text_for_range(next_selection.range())
15110                                .collect::<String>();
15111                            if Some(next_selected_text) != selected_text {
15112                                same_text_selected = false;
15113                                selected_text = None;
15114                            }
15115                        } else {
15116                            same_text_selected = false;
15117                            selected_text = None;
15118                        }
15119                    }
15120                }
15121            }
15122
15123            if only_carets {
15124                for selection in &mut selections {
15125                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15126                    selection.start = word_range.start;
15127                    selection.end = word_range.end;
15128                    selection.goal = SelectionGoal::None;
15129                    selection.reversed = false;
15130                    self.select_match_ranges(
15131                        selection.start..selection.end,
15132                        selection.reversed,
15133                        action.replace_newest,
15134                        Some(Autoscroll::newest()),
15135                        window,
15136                        cx,
15137                    );
15138                }
15139                if selections.len() == 1 {
15140                    let selection = selections
15141                        .last()
15142                        .expect("ensured that there's only one selection");
15143                    let query = buffer
15144                        .text_for_range(selection.start..selection.end)
15145                        .collect::<String>();
15146                    let is_empty = query.is_empty();
15147                    let select_state = SelectNextState {
15148                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15149                        wordwise: true,
15150                        done: is_empty,
15151                    };
15152                    self.select_prev_state = Some(select_state);
15153                } else {
15154                    self.select_prev_state = None;
15155                }
15156            } else if let Some(selected_text) = selected_text {
15157                self.select_prev_state = Some(SelectNextState {
15158                    query: self
15159                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15160                    wordwise: false,
15161                    done: false,
15162                });
15163                self.select_previous(action, window, cx)?;
15164            }
15165        }
15166        Ok(())
15167    }
15168
15169    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15170    /// setting the case sensitivity based on the global
15171    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15172    /// editor's settings.
15173    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15174    where
15175        I: IntoIterator<Item = P>,
15176        P: AsRef<[u8]>,
15177    {
15178        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15179            || EditorSettings::get_global(cx).search.case_sensitive,
15180            |value| value,
15181        );
15182
15183        let mut builder = AhoCorasickBuilder::new();
15184        builder.ascii_case_insensitive(!case_sensitive);
15185        builder.build(patterns)
15186    }
15187
15188    pub fn find_next_match(
15189        &mut self,
15190        _: &FindNextMatch,
15191        window: &mut Window,
15192        cx: &mut Context<Self>,
15193    ) -> Result<()> {
15194        let selections = self.selections.disjoint_anchors_arc();
15195        match selections.first() {
15196            Some(first) if selections.len() >= 2 => {
15197                self.change_selections(Default::default(), window, cx, |s| {
15198                    s.select_ranges([first.range()]);
15199                });
15200            }
15201            _ => self.select_next(
15202                &SelectNext {
15203                    replace_newest: true,
15204                },
15205                window,
15206                cx,
15207            )?,
15208        }
15209        Ok(())
15210    }
15211
15212    pub fn find_previous_match(
15213        &mut self,
15214        _: &FindPreviousMatch,
15215        window: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) -> Result<()> {
15218        let selections = self.selections.disjoint_anchors_arc();
15219        match selections.last() {
15220            Some(last) if selections.len() >= 2 => {
15221                self.change_selections(Default::default(), window, cx, |s| {
15222                    s.select_ranges([last.range()]);
15223                });
15224            }
15225            _ => self.select_previous(
15226                &SelectPrevious {
15227                    replace_newest: true,
15228                },
15229                window,
15230                cx,
15231            )?,
15232        }
15233        Ok(())
15234    }
15235
15236    pub fn toggle_comments(
15237        &mut self,
15238        action: &ToggleComments,
15239        window: &mut Window,
15240        cx: &mut Context<Self>,
15241    ) {
15242        if self.read_only(cx) {
15243            return;
15244        }
15245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15246        let text_layout_details = &self.text_layout_details(window);
15247        self.transact(window, cx, |this, window, cx| {
15248            let mut selections = this
15249                .selections
15250                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15251            let mut edits = Vec::new();
15252            let mut selection_edit_ranges = Vec::new();
15253            let mut last_toggled_row = None;
15254            let snapshot = this.buffer.read(cx).read(cx);
15255            let empty_str: Arc<str> = Arc::default();
15256            let mut suffixes_inserted = Vec::new();
15257            let ignore_indent = action.ignore_indent;
15258
15259            fn comment_prefix_range(
15260                snapshot: &MultiBufferSnapshot,
15261                row: MultiBufferRow,
15262                comment_prefix: &str,
15263                comment_prefix_whitespace: &str,
15264                ignore_indent: bool,
15265            ) -> Range<Point> {
15266                let indent_size = if ignore_indent {
15267                    0
15268                } else {
15269                    snapshot.indent_size_for_line(row).len
15270                };
15271
15272                let start = Point::new(row.0, indent_size);
15273
15274                let mut line_bytes = snapshot
15275                    .bytes_in_range(start..snapshot.max_point())
15276                    .flatten()
15277                    .copied();
15278
15279                // If this line currently begins with the line comment prefix, then record
15280                // the range containing the prefix.
15281                if line_bytes
15282                    .by_ref()
15283                    .take(comment_prefix.len())
15284                    .eq(comment_prefix.bytes())
15285                {
15286                    // Include any whitespace that matches the comment prefix.
15287                    let matching_whitespace_len = line_bytes
15288                        .zip(comment_prefix_whitespace.bytes())
15289                        .take_while(|(a, b)| a == b)
15290                        .count() as u32;
15291                    let end = Point::new(
15292                        start.row,
15293                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15294                    );
15295                    start..end
15296                } else {
15297                    start..start
15298                }
15299            }
15300
15301            fn comment_suffix_range(
15302                snapshot: &MultiBufferSnapshot,
15303                row: MultiBufferRow,
15304                comment_suffix: &str,
15305                comment_suffix_has_leading_space: bool,
15306            ) -> Range<Point> {
15307                let end = Point::new(row.0, snapshot.line_len(row));
15308                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15309
15310                let mut line_end_bytes = snapshot
15311                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15312                    .flatten()
15313                    .copied();
15314
15315                let leading_space_len = if suffix_start_column > 0
15316                    && line_end_bytes.next() == Some(b' ')
15317                    && comment_suffix_has_leading_space
15318                {
15319                    1
15320                } else {
15321                    0
15322                };
15323
15324                // If this line currently begins with the line comment prefix, then record
15325                // the range containing the prefix.
15326                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15327                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15328                    start..end
15329                } else {
15330                    end..end
15331                }
15332            }
15333
15334            // TODO: Handle selections that cross excerpts
15335            for selection in &mut selections {
15336                let start_column = snapshot
15337                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15338                    .len;
15339                let language = if let Some(language) =
15340                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15341                {
15342                    language
15343                } else {
15344                    continue;
15345                };
15346
15347                selection_edit_ranges.clear();
15348
15349                // If multiple selections contain a given row, avoid processing that
15350                // row more than once.
15351                let mut start_row = MultiBufferRow(selection.start.row);
15352                if last_toggled_row == Some(start_row) {
15353                    start_row = start_row.next_row();
15354                }
15355                let end_row =
15356                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15357                        MultiBufferRow(selection.end.row - 1)
15358                    } else {
15359                        MultiBufferRow(selection.end.row)
15360                    };
15361                last_toggled_row = Some(end_row);
15362
15363                if start_row > end_row {
15364                    continue;
15365                }
15366
15367                // If the language has line comments, toggle those.
15368                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15369
15370                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15371                if ignore_indent {
15372                    full_comment_prefixes = full_comment_prefixes
15373                        .into_iter()
15374                        .map(|s| Arc::from(s.trim_end()))
15375                        .collect();
15376                }
15377
15378                if !full_comment_prefixes.is_empty() {
15379                    let first_prefix = full_comment_prefixes
15380                        .first()
15381                        .expect("prefixes is non-empty");
15382                    let prefix_trimmed_lengths = full_comment_prefixes
15383                        .iter()
15384                        .map(|p| p.trim_end_matches(' ').len())
15385                        .collect::<SmallVec<[usize; 4]>>();
15386
15387                    let mut all_selection_lines_are_comments = true;
15388
15389                    for row in start_row.0..=end_row.0 {
15390                        let row = MultiBufferRow(row);
15391                        if start_row < end_row && snapshot.is_line_blank(row) {
15392                            continue;
15393                        }
15394
15395                        let prefix_range = full_comment_prefixes
15396                            .iter()
15397                            .zip(prefix_trimmed_lengths.iter().copied())
15398                            .map(|(prefix, trimmed_prefix_len)| {
15399                                comment_prefix_range(
15400                                    snapshot.deref(),
15401                                    row,
15402                                    &prefix[..trimmed_prefix_len],
15403                                    &prefix[trimmed_prefix_len..],
15404                                    ignore_indent,
15405                                )
15406                            })
15407                            .max_by_key(|range| range.end.column - range.start.column)
15408                            .expect("prefixes is non-empty");
15409
15410                        if prefix_range.is_empty() {
15411                            all_selection_lines_are_comments = false;
15412                        }
15413
15414                        selection_edit_ranges.push(prefix_range);
15415                    }
15416
15417                    if all_selection_lines_are_comments {
15418                        edits.extend(
15419                            selection_edit_ranges
15420                                .iter()
15421                                .cloned()
15422                                .map(|range| (range, empty_str.clone())),
15423                        );
15424                    } else {
15425                        let min_column = selection_edit_ranges
15426                            .iter()
15427                            .map(|range| range.start.column)
15428                            .min()
15429                            .unwrap_or(0);
15430                        edits.extend(selection_edit_ranges.iter().map(|range| {
15431                            let position = Point::new(range.start.row, min_column);
15432                            (position..position, first_prefix.clone())
15433                        }));
15434                    }
15435                } else if let Some(BlockCommentConfig {
15436                    start: full_comment_prefix,
15437                    end: comment_suffix,
15438                    ..
15439                }) = language.block_comment()
15440                {
15441                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15442                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15443                    let prefix_range = comment_prefix_range(
15444                        snapshot.deref(),
15445                        start_row,
15446                        comment_prefix,
15447                        comment_prefix_whitespace,
15448                        ignore_indent,
15449                    );
15450                    let suffix_range = comment_suffix_range(
15451                        snapshot.deref(),
15452                        end_row,
15453                        comment_suffix.trim_start_matches(' '),
15454                        comment_suffix.starts_with(' '),
15455                    );
15456
15457                    if prefix_range.is_empty() || suffix_range.is_empty() {
15458                        edits.push((
15459                            prefix_range.start..prefix_range.start,
15460                            full_comment_prefix.clone(),
15461                        ));
15462                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15463                        suffixes_inserted.push((end_row, comment_suffix.len()));
15464                    } else {
15465                        edits.push((prefix_range, empty_str.clone()));
15466                        edits.push((suffix_range, empty_str.clone()));
15467                    }
15468                } else {
15469                    continue;
15470                }
15471            }
15472
15473            drop(snapshot);
15474            this.buffer.update(cx, |buffer, cx| {
15475                buffer.edit(edits, None, cx);
15476            });
15477
15478            // Adjust selections so that they end before any comment suffixes that
15479            // were inserted.
15480            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15481            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15482            let snapshot = this.buffer.read(cx).read(cx);
15483            for selection in &mut selections {
15484                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15485                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15486                        Ordering::Less => {
15487                            suffixes_inserted.next();
15488                            continue;
15489                        }
15490                        Ordering::Greater => break,
15491                        Ordering::Equal => {
15492                            if selection.end.column == snapshot.line_len(row) {
15493                                if selection.is_empty() {
15494                                    selection.start.column -= suffix_len as u32;
15495                                }
15496                                selection.end.column -= suffix_len as u32;
15497                            }
15498                            break;
15499                        }
15500                    }
15501                }
15502            }
15503
15504            drop(snapshot);
15505            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15506
15507            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15508            let selections_on_single_row = selections.windows(2).all(|selections| {
15509                selections[0].start.row == selections[1].start.row
15510                    && selections[0].end.row == selections[1].end.row
15511                    && selections[0].start.row == selections[0].end.row
15512            });
15513            let selections_selecting = selections
15514                .iter()
15515                .any(|selection| selection.start != selection.end);
15516            let advance_downwards = action.advance_downwards
15517                && selections_on_single_row
15518                && !selections_selecting
15519                && !matches!(this.mode, EditorMode::SingleLine);
15520
15521            if advance_downwards {
15522                let snapshot = this.buffer.read(cx).snapshot(cx);
15523
15524                this.change_selections(Default::default(), window, cx, |s| {
15525                    s.move_cursors_with(|display_snapshot, display_point, _| {
15526                        let mut point = display_point.to_point(display_snapshot);
15527                        point.row += 1;
15528                        point = snapshot.clip_point(point, Bias::Left);
15529                        let display_point = point.to_display_point(display_snapshot);
15530                        let goal = SelectionGoal::HorizontalPosition(
15531                            display_snapshot
15532                                .x_for_display_point(display_point, text_layout_details)
15533                                .into(),
15534                        );
15535                        (display_point, goal)
15536                    })
15537                });
15538            }
15539        });
15540    }
15541
15542    pub fn select_enclosing_symbol(
15543        &mut self,
15544        _: &SelectEnclosingSymbol,
15545        window: &mut Window,
15546        cx: &mut Context<Self>,
15547    ) {
15548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15549
15550        let buffer = self.buffer.read(cx).snapshot(cx);
15551        let old_selections = self
15552            .selections
15553            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15554            .into_boxed_slice();
15555
15556        fn update_selection(
15557            selection: &Selection<MultiBufferOffset>,
15558            buffer_snap: &MultiBufferSnapshot,
15559        ) -> Option<Selection<MultiBufferOffset>> {
15560            let cursor = selection.head();
15561            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15562            for symbol in symbols.iter().rev() {
15563                let start = symbol.range.start.to_offset(buffer_snap);
15564                let end = symbol.range.end.to_offset(buffer_snap);
15565                let new_range = start..end;
15566                if start < selection.start || end > selection.end {
15567                    return Some(Selection {
15568                        id: selection.id,
15569                        start: new_range.start,
15570                        end: new_range.end,
15571                        goal: SelectionGoal::None,
15572                        reversed: selection.reversed,
15573                    });
15574                }
15575            }
15576            None
15577        }
15578
15579        let mut selected_larger_symbol = false;
15580        let new_selections = old_selections
15581            .iter()
15582            .map(|selection| match update_selection(selection, &buffer) {
15583                Some(new_selection) => {
15584                    if new_selection.range() != selection.range() {
15585                        selected_larger_symbol = true;
15586                    }
15587                    new_selection
15588                }
15589                None => selection.clone(),
15590            })
15591            .collect::<Vec<_>>();
15592
15593        if selected_larger_symbol {
15594            self.change_selections(Default::default(), window, cx, |s| {
15595                s.select(new_selections);
15596            });
15597        }
15598    }
15599
15600    pub fn select_larger_syntax_node(
15601        &mut self,
15602        _: &SelectLargerSyntaxNode,
15603        window: &mut Window,
15604        cx: &mut Context<Self>,
15605    ) {
15606        let Some(visible_row_count) = self.visible_row_count() else {
15607            return;
15608        };
15609        let old_selections: Box<[_]> = self
15610            .selections
15611            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15612            .into();
15613        if old_selections.is_empty() {
15614            return;
15615        }
15616
15617        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15618
15619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15620        let buffer = self.buffer.read(cx).snapshot(cx);
15621
15622        let mut selected_larger_node = false;
15623        let mut new_selections = old_selections
15624            .iter()
15625            .map(|selection| {
15626                let old_range = selection.start..selection.end;
15627
15628                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15629                    // manually select word at selection
15630                    if ["string_content", "inline"].contains(&node.kind()) {
15631                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15632                        // ignore if word is already selected
15633                        if !word_range.is_empty() && old_range != word_range {
15634                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15635                            // only select word if start and end point belongs to same word
15636                            if word_range == last_word_range {
15637                                selected_larger_node = true;
15638                                return Selection {
15639                                    id: selection.id,
15640                                    start: word_range.start,
15641                                    end: word_range.end,
15642                                    goal: SelectionGoal::None,
15643                                    reversed: selection.reversed,
15644                                };
15645                            }
15646                        }
15647                    }
15648                }
15649
15650                let mut new_range = old_range.clone();
15651                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15652                    new_range = range;
15653                    if !node.is_named() {
15654                        continue;
15655                    }
15656                    if !display_map.intersects_fold(new_range.start)
15657                        && !display_map.intersects_fold(new_range.end)
15658                    {
15659                        break;
15660                    }
15661                }
15662
15663                selected_larger_node |= new_range != old_range;
15664                Selection {
15665                    id: selection.id,
15666                    start: new_range.start,
15667                    end: new_range.end,
15668                    goal: SelectionGoal::None,
15669                    reversed: selection.reversed,
15670                }
15671            })
15672            .collect::<Vec<_>>();
15673
15674        if !selected_larger_node {
15675            return; // don't put this call in the history
15676        }
15677
15678        // scroll based on transformation done to the last selection created by the user
15679        let (last_old, last_new) = old_selections
15680            .last()
15681            .zip(new_selections.last().cloned())
15682            .expect("old_selections isn't empty");
15683
15684        // revert selection
15685        let is_selection_reversed = {
15686            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15687            new_selections.last_mut().expect("checked above").reversed =
15688                should_newest_selection_be_reversed;
15689            should_newest_selection_be_reversed
15690        };
15691
15692        if selected_larger_node {
15693            self.select_syntax_node_history.disable_clearing = true;
15694            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15695                s.select(new_selections.clone());
15696            });
15697            self.select_syntax_node_history.disable_clearing = false;
15698        }
15699
15700        let start_row = last_new.start.to_display_point(&display_map).row().0;
15701        let end_row = last_new.end.to_display_point(&display_map).row().0;
15702        let selection_height = end_row - start_row + 1;
15703        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15704
15705        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15706        let scroll_behavior = if fits_on_the_screen {
15707            self.request_autoscroll(Autoscroll::fit(), cx);
15708            SelectSyntaxNodeScrollBehavior::FitSelection
15709        } else if is_selection_reversed {
15710            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15711            SelectSyntaxNodeScrollBehavior::CursorTop
15712        } else {
15713            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15714            SelectSyntaxNodeScrollBehavior::CursorBottom
15715        };
15716
15717        self.select_syntax_node_history.push((
15718            old_selections,
15719            scroll_behavior,
15720            is_selection_reversed,
15721        ));
15722    }
15723
15724    pub fn select_smaller_syntax_node(
15725        &mut self,
15726        _: &SelectSmallerSyntaxNode,
15727        window: &mut Window,
15728        cx: &mut Context<Self>,
15729    ) {
15730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15731
15732        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15733            self.select_syntax_node_history.pop()
15734        {
15735            if let Some(selection) = selections.last_mut() {
15736                selection.reversed = is_selection_reversed;
15737            }
15738
15739            self.select_syntax_node_history.disable_clearing = true;
15740            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15741                s.select(selections.to_vec());
15742            });
15743            self.select_syntax_node_history.disable_clearing = false;
15744
15745            match scroll_behavior {
15746                SelectSyntaxNodeScrollBehavior::CursorTop => {
15747                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15748                }
15749                SelectSyntaxNodeScrollBehavior::FitSelection => {
15750                    self.request_autoscroll(Autoscroll::fit(), cx);
15751                }
15752                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15753                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15754                }
15755            }
15756        }
15757    }
15758
15759    pub fn unwrap_syntax_node(
15760        &mut self,
15761        _: &UnwrapSyntaxNode,
15762        window: &mut Window,
15763        cx: &mut Context<Self>,
15764    ) {
15765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15766
15767        let buffer = self.buffer.read(cx).snapshot(cx);
15768        let selections = self
15769            .selections
15770            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15771            .into_iter()
15772            // subtracting the offset requires sorting
15773            .sorted_by_key(|i| i.start);
15774
15775        let full_edits = selections
15776            .into_iter()
15777            .filter_map(|selection| {
15778                let child = if selection.is_empty()
15779                    && let Some((_, ancestor_range)) =
15780                        buffer.syntax_ancestor(selection.start..selection.end)
15781                {
15782                    ancestor_range
15783                } else {
15784                    selection.range()
15785                };
15786
15787                let mut parent = child.clone();
15788                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15789                    parent = ancestor_range;
15790                    if parent.start < child.start || parent.end > child.end {
15791                        break;
15792                    }
15793                }
15794
15795                if parent == child {
15796                    return None;
15797                }
15798                let text = buffer.text_for_range(child).collect::<String>();
15799                Some((selection.id, parent, text))
15800            })
15801            .collect::<Vec<_>>();
15802        if full_edits.is_empty() {
15803            return;
15804        }
15805
15806        self.transact(window, cx, |this, window, cx| {
15807            this.buffer.update(cx, |buffer, cx| {
15808                buffer.edit(
15809                    full_edits
15810                        .iter()
15811                        .map(|(_, p, t)| (p.clone(), t.clone()))
15812                        .collect::<Vec<_>>(),
15813                    None,
15814                    cx,
15815                );
15816            });
15817            this.change_selections(Default::default(), window, cx, |s| {
15818                let mut offset = 0;
15819                let mut selections = vec![];
15820                for (id, parent, text) in full_edits {
15821                    let start = parent.start - offset;
15822                    offset += (parent.end - parent.start) - text.len();
15823                    selections.push(Selection {
15824                        id,
15825                        start,
15826                        end: start + text.len(),
15827                        reversed: false,
15828                        goal: Default::default(),
15829                    });
15830                }
15831                s.select(selections);
15832            });
15833        });
15834    }
15835
15836    pub fn select_next_syntax_node(
15837        &mut self,
15838        _: &SelectNextSyntaxNode,
15839        window: &mut Window,
15840        cx: &mut Context<Self>,
15841    ) {
15842        let old_selections: Box<[_]> = self
15843            .selections
15844            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15845            .into();
15846        if old_selections.is_empty() {
15847            return;
15848        }
15849
15850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15851
15852        let buffer = self.buffer.read(cx).snapshot(cx);
15853        let mut selected_sibling = false;
15854
15855        let new_selections = old_selections
15856            .iter()
15857            .map(|selection| {
15858                let old_range = selection.start..selection.end;
15859
15860                let old_range =
15861                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15862                let excerpt = buffer.excerpt_containing(old_range.clone());
15863
15864                if let Some(mut excerpt) = excerpt
15865                    && let Some(node) = excerpt
15866                        .buffer()
15867                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15868                {
15869                    let new_range = excerpt.map_range_from_buffer(
15870                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15871                    );
15872                    selected_sibling = true;
15873                    Selection {
15874                        id: selection.id,
15875                        start: new_range.start,
15876                        end: new_range.end,
15877                        goal: SelectionGoal::None,
15878                        reversed: selection.reversed,
15879                    }
15880                } else {
15881                    selection.clone()
15882                }
15883            })
15884            .collect::<Vec<_>>();
15885
15886        if selected_sibling {
15887            self.change_selections(
15888                SelectionEffects::scroll(Autoscroll::fit()),
15889                window,
15890                cx,
15891                |s| {
15892                    s.select(new_selections);
15893                },
15894            );
15895        }
15896    }
15897
15898    pub fn select_prev_syntax_node(
15899        &mut self,
15900        _: &SelectPreviousSyntaxNode,
15901        window: &mut Window,
15902        cx: &mut Context<Self>,
15903    ) {
15904        let old_selections: Box<[_]> = self
15905            .selections
15906            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15907            .into();
15908        if old_selections.is_empty() {
15909            return;
15910        }
15911
15912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15913
15914        let buffer = self.buffer.read(cx).snapshot(cx);
15915        let mut selected_sibling = false;
15916
15917        let new_selections = old_selections
15918            .iter()
15919            .map(|selection| {
15920                let old_range = selection.start..selection.end;
15921                let old_range =
15922                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15923                let excerpt = buffer.excerpt_containing(old_range.clone());
15924
15925                if let Some(mut excerpt) = excerpt
15926                    && let Some(node) = excerpt
15927                        .buffer()
15928                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15929                {
15930                    let new_range = excerpt.map_range_from_buffer(
15931                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15932                    );
15933                    selected_sibling = true;
15934                    Selection {
15935                        id: selection.id,
15936                        start: new_range.start,
15937                        end: new_range.end,
15938                        goal: SelectionGoal::None,
15939                        reversed: selection.reversed,
15940                    }
15941                } else {
15942                    selection.clone()
15943                }
15944            })
15945            .collect::<Vec<_>>();
15946
15947        if selected_sibling {
15948            self.change_selections(
15949                SelectionEffects::scroll(Autoscroll::fit()),
15950                window,
15951                cx,
15952                |s| {
15953                    s.select(new_selections);
15954                },
15955            );
15956        }
15957    }
15958
15959    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15960        if !EditorSettings::get_global(cx).gutter.runnables {
15961            self.clear_tasks();
15962            return Task::ready(());
15963        }
15964        let project = self.project().map(Entity::downgrade);
15965        let task_sources = self.lsp_task_sources(cx);
15966        let multi_buffer = self.buffer.downgrade();
15967        cx.spawn_in(window, async move |editor, cx| {
15968            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15969            let Some(project) = project.and_then(|p| p.upgrade()) else {
15970                return;
15971            };
15972            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15973                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15974            }) else {
15975                return;
15976            };
15977
15978            let hide_runnables = project
15979                .update(cx, |project, _| project.is_via_collab())
15980                .unwrap_or(true);
15981            if hide_runnables {
15982                return;
15983            }
15984            let new_rows =
15985                cx.background_spawn({
15986                    let snapshot = display_snapshot.clone();
15987                    async move {
15988                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15989                    }
15990                })
15991                    .await;
15992            let Ok(lsp_tasks) =
15993                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15994            else {
15995                return;
15996            };
15997            let lsp_tasks = lsp_tasks.await;
15998
15999            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16000                lsp_tasks
16001                    .into_iter()
16002                    .flat_map(|(kind, tasks)| {
16003                        tasks.into_iter().filter_map(move |(location, task)| {
16004                            Some((kind.clone(), location?, task))
16005                        })
16006                    })
16007                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16008                        let buffer = location.target.buffer;
16009                        let buffer_snapshot = buffer.read(cx).snapshot();
16010                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16011                            |(excerpt_id, snapshot, _)| {
16012                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16013                                    display_snapshot
16014                                        .buffer_snapshot()
16015                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16016                                } else {
16017                                    None
16018                                }
16019                            },
16020                        );
16021                        if let Some(offset) = offset {
16022                            let task_buffer_range =
16023                                location.target.range.to_point(&buffer_snapshot);
16024                            let context_buffer_range =
16025                                task_buffer_range.to_offset(&buffer_snapshot);
16026                            let context_range = BufferOffset(context_buffer_range.start)
16027                                ..BufferOffset(context_buffer_range.end);
16028
16029                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16030                                .or_insert_with(|| RunnableTasks {
16031                                    templates: Vec::new(),
16032                                    offset,
16033                                    column: task_buffer_range.start.column,
16034                                    extra_variables: HashMap::default(),
16035                                    context_range,
16036                                })
16037                                .templates
16038                                .push((kind, task.original_task().clone()));
16039                        }
16040
16041                        acc
16042                    })
16043            }) else {
16044                return;
16045            };
16046
16047            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16048                buffer.language_settings(cx).tasks.prefer_lsp
16049            }) else {
16050                return;
16051            };
16052
16053            let rows = Self::runnable_rows(
16054                project,
16055                display_snapshot,
16056                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16057                new_rows,
16058                cx.clone(),
16059            )
16060            .await;
16061            editor
16062                .update(cx, |editor, _| {
16063                    editor.clear_tasks();
16064                    for (key, mut value) in rows {
16065                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16066                            value.templates.extend(lsp_tasks.templates);
16067                        }
16068
16069                        editor.insert_tasks(key, value);
16070                    }
16071                    for (key, value) in lsp_tasks_by_rows {
16072                        editor.insert_tasks(key, value);
16073                    }
16074                })
16075                .ok();
16076        })
16077    }
16078    fn fetch_runnable_ranges(
16079        snapshot: &DisplaySnapshot,
16080        range: Range<Anchor>,
16081    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16082        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16083    }
16084
16085    fn runnable_rows(
16086        project: Entity<Project>,
16087        snapshot: DisplaySnapshot,
16088        prefer_lsp: bool,
16089        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16090        cx: AsyncWindowContext,
16091    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16092        cx.spawn(async move |cx| {
16093            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16094            for (run_range, mut runnable) in runnable_ranges {
16095                let Some(tasks) = cx
16096                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16097                    .ok()
16098                else {
16099                    continue;
16100                };
16101                let mut tasks = tasks.await;
16102
16103                if prefer_lsp {
16104                    tasks.retain(|(task_kind, _)| {
16105                        !matches!(task_kind, TaskSourceKind::Language { .. })
16106                    });
16107                }
16108                if tasks.is_empty() {
16109                    continue;
16110                }
16111
16112                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16113                let Some(row) = snapshot
16114                    .buffer_snapshot()
16115                    .buffer_line_for_row(MultiBufferRow(point.row))
16116                    .map(|(_, range)| range.start.row)
16117                else {
16118                    continue;
16119                };
16120
16121                let context_range =
16122                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16123                runnable_rows.push((
16124                    (runnable.buffer_id, row),
16125                    RunnableTasks {
16126                        templates: tasks,
16127                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16128                        context_range,
16129                        column: point.column,
16130                        extra_variables: runnable.extra_captures,
16131                    },
16132                ));
16133            }
16134            runnable_rows
16135        })
16136    }
16137
16138    fn templates_with_tags(
16139        project: &Entity<Project>,
16140        runnable: &mut Runnable,
16141        cx: &mut App,
16142    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16143        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16144            let (worktree_id, file) = project
16145                .buffer_for_id(runnable.buffer, cx)
16146                .and_then(|buffer| buffer.read(cx).file())
16147                .map(|file| (file.worktree_id(cx), file.clone()))
16148                .unzip();
16149
16150            (
16151                project.task_store().read(cx).task_inventory().cloned(),
16152                worktree_id,
16153                file,
16154            )
16155        });
16156
16157        let tags = mem::take(&mut runnable.tags);
16158        let language = runnable.language.clone();
16159        cx.spawn(async move |cx| {
16160            let mut templates_with_tags = Vec::new();
16161            if let Some(inventory) = inventory {
16162                for RunnableTag(tag) in tags {
16163                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16164                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16165                    }) else {
16166                        return templates_with_tags;
16167                    };
16168                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16169                        move |(_, template)| {
16170                            template.tags.iter().any(|source_tag| source_tag == &tag)
16171                        },
16172                    ));
16173                }
16174            }
16175            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16176
16177            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16178                // Strongest source wins; if we have worktree tag binding, prefer that to
16179                // global and language bindings;
16180                // if we have a global binding, prefer that to language binding.
16181                let first_mismatch = templates_with_tags
16182                    .iter()
16183                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16184                if let Some(index) = first_mismatch {
16185                    templates_with_tags.truncate(index);
16186                }
16187            }
16188
16189            templates_with_tags
16190        })
16191    }
16192
16193    pub fn move_to_enclosing_bracket(
16194        &mut self,
16195        _: &MoveToEnclosingBracket,
16196        window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16200        self.change_selections(Default::default(), window, cx, |s| {
16201            s.move_offsets_with(|snapshot, selection| {
16202                let Some(enclosing_bracket_ranges) =
16203                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16204                else {
16205                    return;
16206                };
16207
16208                let mut best_length = usize::MAX;
16209                let mut best_inside = false;
16210                let mut best_in_bracket_range = false;
16211                let mut best_destination = None;
16212                for (open, close) in enclosing_bracket_ranges {
16213                    let close = close.to_inclusive();
16214                    let length = *close.end() - open.start;
16215                    let inside = selection.start >= open.end && selection.end <= *close.start();
16216                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16217                        || close.contains(&selection.head());
16218
16219                    // If best is next to a bracket and current isn't, skip
16220                    if !in_bracket_range && best_in_bracket_range {
16221                        continue;
16222                    }
16223
16224                    // Prefer smaller lengths unless best is inside and current isn't
16225                    if length > best_length && (best_inside || !inside) {
16226                        continue;
16227                    }
16228
16229                    best_length = length;
16230                    best_inside = inside;
16231                    best_in_bracket_range = in_bracket_range;
16232                    best_destination = Some(
16233                        if close.contains(&selection.start) && close.contains(&selection.end) {
16234                            if inside { open.end } else { open.start }
16235                        } else if inside {
16236                            *close.start()
16237                        } else {
16238                            *close.end()
16239                        },
16240                    );
16241                }
16242
16243                if let Some(destination) = best_destination {
16244                    selection.collapse_to(destination, SelectionGoal::None);
16245                }
16246            })
16247        });
16248    }
16249
16250    pub fn undo_selection(
16251        &mut self,
16252        _: &UndoSelection,
16253        window: &mut Window,
16254        cx: &mut Context<Self>,
16255    ) {
16256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16257        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16258            self.selection_history.mode = SelectionHistoryMode::Undoing;
16259            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16260                this.end_selection(window, cx);
16261                this.change_selections(
16262                    SelectionEffects::scroll(Autoscroll::newest()),
16263                    window,
16264                    cx,
16265                    |s| s.select_anchors(entry.selections.to_vec()),
16266                );
16267            });
16268            self.selection_history.mode = SelectionHistoryMode::Normal;
16269
16270            self.select_next_state = entry.select_next_state;
16271            self.select_prev_state = entry.select_prev_state;
16272            self.add_selections_state = entry.add_selections_state;
16273        }
16274    }
16275
16276    pub fn redo_selection(
16277        &mut self,
16278        _: &RedoSelection,
16279        window: &mut Window,
16280        cx: &mut Context<Self>,
16281    ) {
16282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16283        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16284            self.selection_history.mode = SelectionHistoryMode::Redoing;
16285            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16286                this.end_selection(window, cx);
16287                this.change_selections(
16288                    SelectionEffects::scroll(Autoscroll::newest()),
16289                    window,
16290                    cx,
16291                    |s| s.select_anchors(entry.selections.to_vec()),
16292                );
16293            });
16294            self.selection_history.mode = SelectionHistoryMode::Normal;
16295
16296            self.select_next_state = entry.select_next_state;
16297            self.select_prev_state = entry.select_prev_state;
16298            self.add_selections_state = entry.add_selections_state;
16299        }
16300    }
16301
16302    pub fn expand_excerpts(
16303        &mut self,
16304        action: &ExpandExcerpts,
16305        _: &mut Window,
16306        cx: &mut Context<Self>,
16307    ) {
16308        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16309    }
16310
16311    pub fn expand_excerpts_down(
16312        &mut self,
16313        action: &ExpandExcerptsDown,
16314        _: &mut Window,
16315        cx: &mut Context<Self>,
16316    ) {
16317        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16318    }
16319
16320    pub fn expand_excerpts_up(
16321        &mut self,
16322        action: &ExpandExcerptsUp,
16323        _: &mut Window,
16324        cx: &mut Context<Self>,
16325    ) {
16326        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16327    }
16328
16329    pub fn expand_excerpts_for_direction(
16330        &mut self,
16331        lines: u32,
16332        direction: ExpandExcerptDirection,
16333
16334        cx: &mut Context<Self>,
16335    ) {
16336        let selections = self.selections.disjoint_anchors_arc();
16337
16338        let lines = if lines == 0 {
16339            EditorSettings::get_global(cx).expand_excerpt_lines
16340        } else {
16341            lines
16342        };
16343
16344        self.buffer.update(cx, |buffer, cx| {
16345            let snapshot = buffer.snapshot(cx);
16346            let mut excerpt_ids = selections
16347                .iter()
16348                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16349                .collect::<Vec<_>>();
16350            excerpt_ids.sort();
16351            excerpt_ids.dedup();
16352            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16353        })
16354    }
16355
16356    pub fn expand_excerpt(
16357        &mut self,
16358        excerpt: ExcerptId,
16359        direction: ExpandExcerptDirection,
16360        window: &mut Window,
16361        cx: &mut Context<Self>,
16362    ) {
16363        let current_scroll_position = self.scroll_position(cx);
16364        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16365        let mut scroll = None;
16366
16367        if direction == ExpandExcerptDirection::Down {
16368            let multi_buffer = self.buffer.read(cx);
16369            let snapshot = multi_buffer.snapshot(cx);
16370            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16371                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16372                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16373            {
16374                let buffer_snapshot = buffer.read(cx).snapshot();
16375                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16376                let last_row = buffer_snapshot.max_point().row;
16377                let lines_below = last_row.saturating_sub(excerpt_end_row);
16378                if lines_below >= lines_to_expand {
16379                    scroll = Some(
16380                        current_scroll_position
16381                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16382                    );
16383                }
16384            }
16385        }
16386        if direction == ExpandExcerptDirection::Up
16387            && self
16388                .buffer
16389                .read(cx)
16390                .snapshot(cx)
16391                .excerpt_before(excerpt)
16392                .is_none()
16393        {
16394            scroll = Some(current_scroll_position);
16395        }
16396
16397        self.buffer.update(cx, |buffer, cx| {
16398            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16399        });
16400
16401        if let Some(new_scroll_position) = scroll {
16402            self.set_scroll_position(new_scroll_position, window, cx);
16403        }
16404    }
16405
16406    pub fn go_to_singleton_buffer_point(
16407        &mut self,
16408        point: Point,
16409        window: &mut Window,
16410        cx: &mut Context<Self>,
16411    ) {
16412        self.go_to_singleton_buffer_range(point..point, window, cx);
16413    }
16414
16415    pub fn go_to_singleton_buffer_range(
16416        &mut self,
16417        range: Range<Point>,
16418        window: &mut Window,
16419        cx: &mut Context<Self>,
16420    ) {
16421        let multibuffer = self.buffer().read(cx);
16422        let Some(buffer) = multibuffer.as_singleton() else {
16423            return;
16424        };
16425        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16426            return;
16427        };
16428        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16429            return;
16430        };
16431        self.change_selections(
16432            SelectionEffects::default().nav_history(true),
16433            window,
16434            cx,
16435            |s| s.select_anchor_ranges([start..end]),
16436        );
16437    }
16438
16439    pub fn go_to_diagnostic(
16440        &mut self,
16441        action: &GoToDiagnostic,
16442        window: &mut Window,
16443        cx: &mut Context<Self>,
16444    ) {
16445        if !self.diagnostics_enabled() {
16446            return;
16447        }
16448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16449        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16450    }
16451
16452    pub fn go_to_prev_diagnostic(
16453        &mut self,
16454        action: &GoToPreviousDiagnostic,
16455        window: &mut Window,
16456        cx: &mut Context<Self>,
16457    ) {
16458        if !self.diagnostics_enabled() {
16459            return;
16460        }
16461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16462        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16463    }
16464
16465    pub fn go_to_diagnostic_impl(
16466        &mut self,
16467        direction: Direction,
16468        severity: GoToDiagnosticSeverityFilter,
16469        window: &mut Window,
16470        cx: &mut Context<Self>,
16471    ) {
16472        let buffer = self.buffer.read(cx).snapshot(cx);
16473        let selection = self
16474            .selections
16475            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16476
16477        let mut active_group_id = None;
16478        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16479            && active_group.active_range.start.to_offset(&buffer) == selection.start
16480        {
16481            active_group_id = Some(active_group.group_id);
16482        }
16483
16484        fn filtered<'a>(
16485            severity: GoToDiagnosticSeverityFilter,
16486            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16487        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16488            diagnostics
16489                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16490                .filter(|entry| entry.range.start != entry.range.end)
16491                .filter(|entry| !entry.diagnostic.is_unnecessary)
16492        }
16493
16494        let before = filtered(
16495            severity,
16496            buffer
16497                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16498                .filter(|entry| entry.range.start <= selection.start),
16499        );
16500        let after = filtered(
16501            severity,
16502            buffer
16503                .diagnostics_in_range(selection.start..buffer.len())
16504                .filter(|entry| entry.range.start >= selection.start),
16505        );
16506
16507        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16508        if direction == Direction::Prev {
16509            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16510            {
16511                for diagnostic in prev_diagnostics.into_iter().rev() {
16512                    if diagnostic.range.start != selection.start
16513                        || active_group_id
16514                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16515                    {
16516                        found = Some(diagnostic);
16517                        break 'outer;
16518                    }
16519                }
16520            }
16521        } else {
16522            for diagnostic in after.chain(before) {
16523                if diagnostic.range.start != selection.start
16524                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16525                {
16526                    found = Some(diagnostic);
16527                    break;
16528                }
16529            }
16530        }
16531        let Some(next_diagnostic) = found else {
16532            return;
16533        };
16534
16535        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16536        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16537            return;
16538        };
16539        let snapshot = self.snapshot(window, cx);
16540        if snapshot.intersects_fold(next_diagnostic.range.start) {
16541            self.unfold_ranges(
16542                std::slice::from_ref(&next_diagnostic.range),
16543                true,
16544                false,
16545                cx,
16546            );
16547        }
16548        self.change_selections(Default::default(), window, cx, |s| {
16549            s.select_ranges(vec![
16550                next_diagnostic.range.start..next_diagnostic.range.start,
16551            ])
16552        });
16553        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16554        self.refresh_edit_prediction(false, true, window, cx);
16555    }
16556
16557    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16559        let snapshot = self.snapshot(window, cx);
16560        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16561        self.go_to_hunk_before_or_after_position(
16562            &snapshot,
16563            selection.head(),
16564            Direction::Next,
16565            window,
16566            cx,
16567        );
16568    }
16569
16570    pub fn go_to_hunk_before_or_after_position(
16571        &mut self,
16572        snapshot: &EditorSnapshot,
16573        position: Point,
16574        direction: Direction,
16575        window: &mut Window,
16576        cx: &mut Context<Editor>,
16577    ) {
16578        let row = if direction == Direction::Next {
16579            self.hunk_after_position(snapshot, position)
16580                .map(|hunk| hunk.row_range.start)
16581        } else {
16582            self.hunk_before_position(snapshot, position)
16583        };
16584
16585        if let Some(row) = row {
16586            let destination = Point::new(row.0, 0);
16587            let autoscroll = Autoscroll::center();
16588
16589            self.unfold_ranges(&[destination..destination], false, false, cx);
16590            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16591                s.select_ranges([destination..destination]);
16592            });
16593        }
16594    }
16595
16596    fn hunk_after_position(
16597        &mut self,
16598        snapshot: &EditorSnapshot,
16599        position: Point,
16600    ) -> Option<MultiBufferDiffHunk> {
16601        snapshot
16602            .buffer_snapshot()
16603            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16604            .find(|hunk| hunk.row_range.start.0 > position.row)
16605            .or_else(|| {
16606                snapshot
16607                    .buffer_snapshot()
16608                    .diff_hunks_in_range(Point::zero()..position)
16609                    .find(|hunk| hunk.row_range.end.0 < position.row)
16610            })
16611    }
16612
16613    fn go_to_prev_hunk(
16614        &mut self,
16615        _: &GoToPreviousHunk,
16616        window: &mut Window,
16617        cx: &mut Context<Self>,
16618    ) {
16619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16620        let snapshot = self.snapshot(window, cx);
16621        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16622        self.go_to_hunk_before_or_after_position(
16623            &snapshot,
16624            selection.head(),
16625            Direction::Prev,
16626            window,
16627            cx,
16628        );
16629    }
16630
16631    fn hunk_before_position(
16632        &mut self,
16633        snapshot: &EditorSnapshot,
16634        position: Point,
16635    ) -> Option<MultiBufferRow> {
16636        snapshot
16637            .buffer_snapshot()
16638            .diff_hunk_before(position)
16639            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16640    }
16641
16642    fn go_to_next_change(
16643        &mut self,
16644        _: &GoToNextChange,
16645        window: &mut Window,
16646        cx: &mut Context<Self>,
16647    ) {
16648        if let Some(selections) = self
16649            .change_list
16650            .next_change(1, Direction::Next)
16651            .map(|s| s.to_vec())
16652        {
16653            self.change_selections(Default::default(), window, cx, |s| {
16654                let map = s.display_snapshot();
16655                s.select_display_ranges(selections.iter().map(|a| {
16656                    let point = a.to_display_point(&map);
16657                    point..point
16658                }))
16659            })
16660        }
16661    }
16662
16663    fn go_to_previous_change(
16664        &mut self,
16665        _: &GoToPreviousChange,
16666        window: &mut Window,
16667        cx: &mut Context<Self>,
16668    ) {
16669        if let Some(selections) = self
16670            .change_list
16671            .next_change(1, Direction::Prev)
16672            .map(|s| s.to_vec())
16673        {
16674            self.change_selections(Default::default(), window, cx, |s| {
16675                let map = s.display_snapshot();
16676                s.select_display_ranges(selections.iter().map(|a| {
16677                    let point = a.to_display_point(&map);
16678                    point..point
16679                }))
16680            })
16681        }
16682    }
16683
16684    pub fn go_to_next_document_highlight(
16685        &mut self,
16686        _: &GoToNextDocumentHighlight,
16687        window: &mut Window,
16688        cx: &mut Context<Self>,
16689    ) {
16690        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16691    }
16692
16693    pub fn go_to_prev_document_highlight(
16694        &mut self,
16695        _: &GoToPreviousDocumentHighlight,
16696        window: &mut Window,
16697        cx: &mut Context<Self>,
16698    ) {
16699        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16700    }
16701
16702    pub fn go_to_document_highlight_before_or_after_position(
16703        &mut self,
16704        direction: Direction,
16705        window: &mut Window,
16706        cx: &mut Context<Editor>,
16707    ) {
16708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16709        let snapshot = self.snapshot(window, cx);
16710        let buffer = &snapshot.buffer_snapshot();
16711        let position = self
16712            .selections
16713            .newest::<Point>(&snapshot.display_snapshot)
16714            .head();
16715        let anchor_position = buffer.anchor_after(position);
16716
16717        // Get all document highlights (both read and write)
16718        let mut all_highlights = Vec::new();
16719
16720        if let Some((_, read_highlights)) = self
16721            .background_highlights
16722            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16723        {
16724            all_highlights.extend(read_highlights.iter());
16725        }
16726
16727        if let Some((_, write_highlights)) = self
16728            .background_highlights
16729            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16730        {
16731            all_highlights.extend(write_highlights.iter());
16732        }
16733
16734        if all_highlights.is_empty() {
16735            return;
16736        }
16737
16738        // Sort highlights by position
16739        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16740
16741        let target_highlight = match direction {
16742            Direction::Next => {
16743                // Find the first highlight after the current position
16744                all_highlights
16745                    .iter()
16746                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16747            }
16748            Direction::Prev => {
16749                // Find the last highlight before the current position
16750                all_highlights
16751                    .iter()
16752                    .rev()
16753                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16754            }
16755        };
16756
16757        if let Some(highlight) = target_highlight {
16758            let destination = highlight.start.to_point(buffer);
16759            let autoscroll = Autoscroll::center();
16760
16761            self.unfold_ranges(&[destination..destination], false, false, cx);
16762            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16763                s.select_ranges([destination..destination]);
16764            });
16765        }
16766    }
16767
16768    fn go_to_line<T: 'static>(
16769        &mut self,
16770        position: Anchor,
16771        highlight_color: Option<Hsla>,
16772        window: &mut Window,
16773        cx: &mut Context<Self>,
16774    ) {
16775        let snapshot = self.snapshot(window, cx).display_snapshot;
16776        let position = position.to_point(&snapshot.buffer_snapshot());
16777        let start = snapshot
16778            .buffer_snapshot()
16779            .clip_point(Point::new(position.row, 0), Bias::Left);
16780        let end = start + Point::new(1, 0);
16781        let start = snapshot.buffer_snapshot().anchor_before(start);
16782        let end = snapshot.buffer_snapshot().anchor_before(end);
16783
16784        self.highlight_rows::<T>(
16785            start..end,
16786            highlight_color
16787                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16788            Default::default(),
16789            cx,
16790        );
16791
16792        if self.buffer.read(cx).is_singleton() {
16793            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16794        }
16795    }
16796
16797    pub fn go_to_definition(
16798        &mut self,
16799        _: &GoToDefinition,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) -> Task<Result<Navigated>> {
16803        let definition =
16804            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16805        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16806        cx.spawn_in(window, async move |editor, cx| {
16807            if definition.await? == Navigated::Yes {
16808                return Ok(Navigated::Yes);
16809            }
16810            match fallback_strategy {
16811                GoToDefinitionFallback::None => Ok(Navigated::No),
16812                GoToDefinitionFallback::FindAllReferences => {
16813                    match editor.update_in(cx, |editor, window, cx| {
16814                        editor.find_all_references(&FindAllReferences, window, cx)
16815                    })? {
16816                        Some(references) => references.await,
16817                        None => Ok(Navigated::No),
16818                    }
16819                }
16820            }
16821        })
16822    }
16823
16824    pub fn go_to_declaration(
16825        &mut self,
16826        _: &GoToDeclaration,
16827        window: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) -> Task<Result<Navigated>> {
16830        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16831    }
16832
16833    pub fn go_to_declaration_split(
16834        &mut self,
16835        _: &GoToDeclaration,
16836        window: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) -> Task<Result<Navigated>> {
16839        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16840    }
16841
16842    pub fn go_to_implementation(
16843        &mut self,
16844        _: &GoToImplementation,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) -> Task<Result<Navigated>> {
16848        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16849    }
16850
16851    pub fn go_to_implementation_split(
16852        &mut self,
16853        _: &GoToImplementationSplit,
16854        window: &mut Window,
16855        cx: &mut Context<Self>,
16856    ) -> Task<Result<Navigated>> {
16857        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16858    }
16859
16860    pub fn go_to_type_definition(
16861        &mut self,
16862        _: &GoToTypeDefinition,
16863        window: &mut Window,
16864        cx: &mut Context<Self>,
16865    ) -> Task<Result<Navigated>> {
16866        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16867    }
16868
16869    pub fn go_to_definition_split(
16870        &mut self,
16871        _: &GoToDefinitionSplit,
16872        window: &mut Window,
16873        cx: &mut Context<Self>,
16874    ) -> Task<Result<Navigated>> {
16875        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16876    }
16877
16878    pub fn go_to_type_definition_split(
16879        &mut self,
16880        _: &GoToTypeDefinitionSplit,
16881        window: &mut Window,
16882        cx: &mut Context<Self>,
16883    ) -> Task<Result<Navigated>> {
16884        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16885    }
16886
16887    fn go_to_definition_of_kind(
16888        &mut self,
16889        kind: GotoDefinitionKind,
16890        split: bool,
16891        window: &mut Window,
16892        cx: &mut Context<Self>,
16893    ) -> Task<Result<Navigated>> {
16894        let Some(provider) = self.semantics_provider.clone() else {
16895            return Task::ready(Ok(Navigated::No));
16896        };
16897        let head = self
16898            .selections
16899            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16900            .head();
16901        let buffer = self.buffer.read(cx);
16902        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16903            return Task::ready(Ok(Navigated::No));
16904        };
16905        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16906            return Task::ready(Ok(Navigated::No));
16907        };
16908
16909        cx.spawn_in(window, async move |editor, cx| {
16910            let Some(definitions) = definitions.await? else {
16911                return Ok(Navigated::No);
16912            };
16913            let navigated = editor
16914                .update_in(cx, |editor, window, cx| {
16915                    editor.navigate_to_hover_links(
16916                        Some(kind),
16917                        definitions
16918                            .into_iter()
16919                            .filter(|location| {
16920                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16921                            })
16922                            .map(HoverLink::Text)
16923                            .collect::<Vec<_>>(),
16924                        split,
16925                        window,
16926                        cx,
16927                    )
16928                })?
16929                .await?;
16930            anyhow::Ok(navigated)
16931        })
16932    }
16933
16934    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16935        let selection = self.selections.newest_anchor();
16936        let head = selection.head();
16937        let tail = selection.tail();
16938
16939        let Some((buffer, start_position)) =
16940            self.buffer.read(cx).text_anchor_for_position(head, cx)
16941        else {
16942            return;
16943        };
16944
16945        let end_position = if head != tail {
16946            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16947                return;
16948            };
16949            Some(pos)
16950        } else {
16951            None
16952        };
16953
16954        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16955            let url = if let Some(end_pos) = end_position {
16956                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16957            } else {
16958                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16959            };
16960
16961            if let Some(url) = url {
16962                cx.update(|window, cx| {
16963                    if parse_zed_link(&url, cx).is_some() {
16964                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16965                    } else {
16966                        cx.open_url(&url);
16967                    }
16968                })?;
16969            }
16970
16971            anyhow::Ok(())
16972        });
16973
16974        url_finder.detach();
16975    }
16976
16977    pub fn open_selected_filename(
16978        &mut self,
16979        _: &OpenSelectedFilename,
16980        window: &mut Window,
16981        cx: &mut Context<Self>,
16982    ) {
16983        let Some(workspace) = self.workspace() else {
16984            return;
16985        };
16986
16987        let position = self.selections.newest_anchor().head();
16988
16989        let Some((buffer, buffer_position)) =
16990            self.buffer.read(cx).text_anchor_for_position(position, cx)
16991        else {
16992            return;
16993        };
16994
16995        let project = self.project.clone();
16996
16997        cx.spawn_in(window, async move |_, cx| {
16998            let result = find_file(&buffer, project, buffer_position, cx).await;
16999
17000            if let Some((_, path)) = result {
17001                workspace
17002                    .update_in(cx, |workspace, window, cx| {
17003                        workspace.open_resolved_path(path, window, cx)
17004                    })?
17005                    .await?;
17006            }
17007            anyhow::Ok(())
17008        })
17009        .detach();
17010    }
17011
17012    pub(crate) fn navigate_to_hover_links(
17013        &mut self,
17014        kind: Option<GotoDefinitionKind>,
17015        definitions: Vec<HoverLink>,
17016        split: bool,
17017        window: &mut Window,
17018        cx: &mut Context<Editor>,
17019    ) -> Task<Result<Navigated>> {
17020        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17021        let mut first_url_or_file = None;
17022        let definitions: Vec<_> = definitions
17023            .into_iter()
17024            .filter_map(|def| match def {
17025                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17026                HoverLink::InlayHint(lsp_location, server_id) => {
17027                    let computation =
17028                        self.compute_target_location(lsp_location, server_id, window, cx);
17029                    Some(cx.background_spawn(computation))
17030                }
17031                HoverLink::Url(url) => {
17032                    first_url_or_file = Some(Either::Left(url));
17033                    None
17034                }
17035                HoverLink::File(path) => {
17036                    first_url_or_file = Some(Either::Right(path));
17037                    None
17038                }
17039            })
17040            .collect();
17041
17042        let Some(workspace) = self.workspace() else {
17043            return Task::ready(Ok(Navigated::No));
17044        };
17045
17046        cx.spawn_in(window, async move |editor, cx| {
17047            let locations: Vec<Location> = future::join_all(definitions)
17048                .await
17049                .into_iter()
17050                .filter_map(|location| location.transpose())
17051                .collect::<Result<_>>()
17052                .context("location tasks")?;
17053            let mut locations = cx.update(|_, cx| {
17054                locations
17055                    .into_iter()
17056                    .map(|location| {
17057                        let buffer = location.buffer.read(cx);
17058                        (location.buffer, location.range.to_point(buffer))
17059                    })
17060                    .into_group_map()
17061            })?;
17062            let mut num_locations = 0;
17063            for ranges in locations.values_mut() {
17064                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17065                ranges.dedup();
17066                num_locations += ranges.len();
17067            }
17068
17069            if num_locations > 1 {
17070                let tab_kind = match kind {
17071                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17072                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17073                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17074                    Some(GotoDefinitionKind::Type) => "Types",
17075                };
17076                let title = editor
17077                    .update_in(cx, |_, _, cx| {
17078                        let target = locations
17079                            .iter()
17080                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17081                            .map(|(buffer, location)| {
17082                                buffer
17083                                    .read(cx)
17084                                    .text_for_range(location.clone())
17085                                    .collect::<String>()
17086                            })
17087                            .filter(|text| !text.contains('\n'))
17088                            .unique()
17089                            .take(3)
17090                            .join(", ");
17091                        if target.is_empty() {
17092                            tab_kind.to_owned()
17093                        } else {
17094                            format!("{tab_kind} for {target}")
17095                        }
17096                    })
17097                    .context("buffer title")?;
17098
17099                let opened = workspace
17100                    .update_in(cx, |workspace, window, cx| {
17101                        let allow_preview = PreviewTabsSettings::get_global(cx)
17102                            .enable_preview_multibuffer_from_code_navigation;
17103                        Self::open_locations_in_multibuffer(
17104                            workspace,
17105                            locations,
17106                            title,
17107                            split,
17108                            allow_preview,
17109                            MultibufferSelectionMode::First,
17110                            window,
17111                            cx,
17112                        )
17113                    })
17114                    .is_ok();
17115
17116                anyhow::Ok(Navigated::from_bool(opened))
17117            } else if num_locations == 0 {
17118                // If there is one url or file, open it directly
17119                match first_url_or_file {
17120                    Some(Either::Left(url)) => {
17121                        cx.update(|_, cx| cx.open_url(&url))?;
17122                        Ok(Navigated::Yes)
17123                    }
17124                    Some(Either::Right(path)) => {
17125                        // TODO(andrew): respect preview tab settings
17126                        //               `enable_keep_preview_on_code_navigation` and
17127                        //               `enable_preview_file_from_code_navigation`
17128                        workspace
17129                            .update_in(cx, |workspace, window, cx| {
17130                                workspace.open_resolved_path(path, window, cx)
17131                            })?
17132                            .await?;
17133                        Ok(Navigated::Yes)
17134                    }
17135                    None => Ok(Navigated::No),
17136                }
17137            } else {
17138                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17139                let target_range = target_ranges.first().unwrap().clone();
17140
17141                editor.update_in(cx, |editor, window, cx| {
17142                    let range = target_range.to_point(target_buffer.read(cx));
17143                    let range = editor.range_for_match(&range);
17144                    let range = collapse_multiline_range(range);
17145
17146                    if !split
17147                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17148                    {
17149                        editor.go_to_singleton_buffer_range(range, window, cx);
17150                    } else {
17151                        let pane = workspace.read(cx).active_pane().clone();
17152                        window.defer(cx, move |window, cx| {
17153                            let target_editor: Entity<Self> =
17154                                workspace.update(cx, |workspace, cx| {
17155                                    let pane = if split {
17156                                        workspace.adjacent_pane(window, cx)
17157                                    } else {
17158                                        workspace.active_pane().clone()
17159                                    };
17160
17161                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17162                                    let keep_old_preview = preview_tabs_settings
17163                                        .enable_keep_preview_on_code_navigation;
17164                                    let allow_new_preview = preview_tabs_settings
17165                                        .enable_preview_file_from_code_navigation;
17166
17167                                    workspace.open_project_item(
17168                                        pane,
17169                                        target_buffer.clone(),
17170                                        true,
17171                                        true,
17172                                        keep_old_preview,
17173                                        allow_new_preview,
17174                                        window,
17175                                        cx,
17176                                    )
17177                                });
17178                            target_editor.update(cx, |target_editor, cx| {
17179                                // When selecting a definition in a different buffer, disable the nav history
17180                                // to avoid creating a history entry at the previous cursor location.
17181                                pane.update(cx, |pane, _| pane.disable_history());
17182                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17183                                pane.update(cx, |pane, _| pane.enable_history());
17184                            });
17185                        });
17186                    }
17187                    Navigated::Yes
17188                })
17189            }
17190        })
17191    }
17192
17193    fn compute_target_location(
17194        &self,
17195        lsp_location: lsp::Location,
17196        server_id: LanguageServerId,
17197        window: &mut Window,
17198        cx: &mut Context<Self>,
17199    ) -> Task<anyhow::Result<Option<Location>>> {
17200        let Some(project) = self.project.clone() else {
17201            return Task::ready(Ok(None));
17202        };
17203
17204        cx.spawn_in(window, async move |editor, cx| {
17205            let location_task = editor.update(cx, |_, cx| {
17206                project.update(cx, |project, cx| {
17207                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17208                })
17209            })?;
17210            let location = Some({
17211                let target_buffer_handle = location_task.await.context("open local buffer")?;
17212                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17213                    let target_start = target_buffer
17214                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17215                    let target_end = target_buffer
17216                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17217                    target_buffer.anchor_after(target_start)
17218                        ..target_buffer.anchor_before(target_end)
17219                })?;
17220                Location {
17221                    buffer: target_buffer_handle,
17222                    range,
17223                }
17224            });
17225            Ok(location)
17226        })
17227    }
17228
17229    fn go_to_next_reference(
17230        &mut self,
17231        _: &GoToNextReference,
17232        window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17236        if let Some(task) = task {
17237            task.detach();
17238        };
17239    }
17240
17241    fn go_to_prev_reference(
17242        &mut self,
17243        _: &GoToPreviousReference,
17244        window: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) {
17247        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17248        if let Some(task) = task {
17249            task.detach();
17250        };
17251    }
17252
17253    pub fn go_to_reference_before_or_after_position(
17254        &mut self,
17255        direction: Direction,
17256        count: usize,
17257        window: &mut Window,
17258        cx: &mut Context<Self>,
17259    ) -> Option<Task<Result<()>>> {
17260        let selection = self.selections.newest_anchor();
17261        let head = selection.head();
17262
17263        let multi_buffer = self.buffer.read(cx);
17264
17265        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17266        let workspace = self.workspace()?;
17267        let project = workspace.read(cx).project().clone();
17268        let references =
17269            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17270        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17271            let Some(locations) = references.await? else {
17272                return Ok(());
17273            };
17274
17275            if locations.is_empty() {
17276                // totally normal - the cursor may be on something which is not
17277                // a symbol (e.g. a keyword)
17278                log::info!("no references found under cursor");
17279                return Ok(());
17280            }
17281
17282            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17283
17284            let (locations, current_location_index) =
17285                multi_buffer.update(cx, |multi_buffer, cx| {
17286                    let mut locations = locations
17287                        .into_iter()
17288                        .filter_map(|loc| {
17289                            let start = multi_buffer.buffer_anchor_to_anchor(
17290                                &loc.buffer,
17291                                loc.range.start,
17292                                cx,
17293                            )?;
17294                            let end = multi_buffer.buffer_anchor_to_anchor(
17295                                &loc.buffer,
17296                                loc.range.end,
17297                                cx,
17298                            )?;
17299                            Some(start..end)
17300                        })
17301                        .collect::<Vec<_>>();
17302
17303                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17304                    // There is an O(n) implementation, but given this list will be
17305                    // small (usually <100 items), the extra O(log(n)) factor isn't
17306                    // worth the (surprisingly large amount of) extra complexity.
17307                    locations
17308                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17309
17310                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17311
17312                    let current_location_index = locations.iter().position(|loc| {
17313                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17314                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17315                    });
17316
17317                    (locations, current_location_index)
17318                })?;
17319
17320            let Some(current_location_index) = current_location_index else {
17321                // This indicates something has gone wrong, because we already
17322                // handle the "no references" case above
17323                log::error!(
17324                    "failed to find current reference under cursor. Total references: {}",
17325                    locations.len()
17326                );
17327                return Ok(());
17328            };
17329
17330            let destination_location_index = match direction {
17331                Direction::Next => (current_location_index + count) % locations.len(),
17332                Direction::Prev => {
17333                    (current_location_index + locations.len() - count % locations.len())
17334                        % locations.len()
17335                }
17336            };
17337
17338            // TODO(cameron): is this needed?
17339            // the thinking is to avoid "jumping to the current location" (avoid
17340            // polluting "jumplist" in vim terms)
17341            if current_location_index == destination_location_index {
17342                return Ok(());
17343            }
17344
17345            let Range { start, end } = locations[destination_location_index];
17346
17347            editor.update_in(cx, |editor, window, cx| {
17348                let effects = SelectionEffects::default();
17349
17350                editor.unfold_ranges(&[start..end], false, false, cx);
17351                editor.change_selections(effects, window, cx, |s| {
17352                    s.select_ranges([start..start]);
17353                });
17354            })?;
17355
17356            Ok(())
17357        }))
17358    }
17359
17360    pub fn find_all_references(
17361        &mut self,
17362        _: &FindAllReferences,
17363        window: &mut Window,
17364        cx: &mut Context<Self>,
17365    ) -> Option<Task<Result<Navigated>>> {
17366        let selection = self
17367            .selections
17368            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17369        let multi_buffer = self.buffer.read(cx);
17370        let head = selection.head();
17371
17372        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17373        let head_anchor = multi_buffer_snapshot.anchor_at(
17374            head,
17375            if head < selection.tail() {
17376                Bias::Right
17377            } else {
17378                Bias::Left
17379            },
17380        );
17381
17382        match self
17383            .find_all_references_task_sources
17384            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17385        {
17386            Ok(_) => {
17387                log::info!(
17388                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17389                );
17390                return None;
17391            }
17392            Err(i) => {
17393                self.find_all_references_task_sources.insert(i, head_anchor);
17394            }
17395        }
17396
17397        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17398        let workspace = self.workspace()?;
17399        let project = workspace.read(cx).project().clone();
17400        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17401        Some(cx.spawn_in(window, async move |editor, cx| {
17402            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17403                if let Ok(i) = editor
17404                    .find_all_references_task_sources
17405                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17406                {
17407                    editor.find_all_references_task_sources.remove(i);
17408                }
17409            });
17410
17411            let Some(locations) = references.await? else {
17412                return anyhow::Ok(Navigated::No);
17413            };
17414            let mut locations = cx.update(|_, cx| {
17415                locations
17416                    .into_iter()
17417                    .map(|location| {
17418                        let buffer = location.buffer.read(cx);
17419                        (location.buffer, location.range.to_point(buffer))
17420                    })
17421                    .into_group_map()
17422            })?;
17423            if locations.is_empty() {
17424                return anyhow::Ok(Navigated::No);
17425            }
17426            for ranges in locations.values_mut() {
17427                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17428                ranges.dedup();
17429            }
17430
17431            workspace.update_in(cx, |workspace, window, cx| {
17432                let target = locations
17433                    .iter()
17434                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17435                    .map(|(buffer, location)| {
17436                        buffer
17437                            .read(cx)
17438                            .text_for_range(location.clone())
17439                            .collect::<String>()
17440                    })
17441                    .filter(|text| !text.contains('\n'))
17442                    .unique()
17443                    .take(3)
17444                    .join(", ");
17445                let title = if target.is_empty() {
17446                    "References".to_owned()
17447                } else {
17448                    format!("References to {target}")
17449                };
17450                let allow_preview = PreviewTabsSettings::get_global(cx)
17451                    .enable_preview_multibuffer_from_code_navigation;
17452                Self::open_locations_in_multibuffer(
17453                    workspace,
17454                    locations,
17455                    title,
17456                    false,
17457                    allow_preview,
17458                    MultibufferSelectionMode::First,
17459                    window,
17460                    cx,
17461                );
17462                Navigated::Yes
17463            })
17464        }))
17465    }
17466
17467    /// Opens a multibuffer with the given project locations in it
17468    pub fn open_locations_in_multibuffer(
17469        workspace: &mut Workspace,
17470        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17471        title: String,
17472        split: bool,
17473        allow_preview: bool,
17474        multibuffer_selection_mode: MultibufferSelectionMode,
17475        window: &mut Window,
17476        cx: &mut Context<Workspace>,
17477    ) {
17478        if locations.is_empty() {
17479            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17480            return;
17481        }
17482
17483        let capability = workspace.project().read(cx).capability();
17484        let mut ranges = <Vec<Range<Anchor>>>::new();
17485
17486        // a key to find existing multibuffer editors with the same set of locations
17487        // to prevent us from opening more and more multibuffer tabs for searches and the like
17488        let mut key = (title.clone(), vec![]);
17489        let excerpt_buffer = cx.new(|cx| {
17490            let key = &mut key.1;
17491            let mut multibuffer = MultiBuffer::new(capability);
17492            for (buffer, mut ranges_for_buffer) in locations {
17493                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17494                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17495                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17496                    PathKey::for_buffer(&buffer, cx),
17497                    buffer.clone(),
17498                    ranges_for_buffer,
17499                    multibuffer_context_lines(cx),
17500                    cx,
17501                );
17502                ranges.extend(new_ranges)
17503            }
17504
17505            multibuffer.with_title(title)
17506        });
17507        let existing = workspace.active_pane().update(cx, |pane, cx| {
17508            pane.items()
17509                .filter_map(|item| item.downcast::<Editor>())
17510                .find(|editor| {
17511                    editor
17512                        .read(cx)
17513                        .lookup_key
17514                        .as_ref()
17515                        .and_then(|it| {
17516                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17517                        })
17518                        .is_some_and(|it| *it == key)
17519                })
17520        });
17521        let was_existing = existing.is_some();
17522        let editor = existing.unwrap_or_else(|| {
17523            cx.new(|cx| {
17524                let mut editor = Editor::for_multibuffer(
17525                    excerpt_buffer,
17526                    Some(workspace.project().clone()),
17527                    window,
17528                    cx,
17529                );
17530                editor.lookup_key = Some(Box::new(key));
17531                editor
17532            })
17533        });
17534        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17535            MultibufferSelectionMode::First => {
17536                if let Some(first_range) = ranges.first() {
17537                    editor.change_selections(
17538                        SelectionEffects::no_scroll(),
17539                        window,
17540                        cx,
17541                        |selections| {
17542                            selections.clear_disjoint();
17543                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17544                        },
17545                    );
17546                }
17547                editor.highlight_background::<Self>(
17548                    &ranges,
17549                    |_, theme| theme.colors().editor_highlighted_line_background,
17550                    cx,
17551                );
17552            }
17553            MultibufferSelectionMode::All => {
17554                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17555                    selections.clear_disjoint();
17556                    selections.select_anchor_ranges(ranges);
17557                });
17558            }
17559        });
17560
17561        let item = Box::new(editor);
17562
17563        let pane = if split {
17564            workspace.adjacent_pane(window, cx)
17565        } else {
17566            workspace.active_pane().clone()
17567        };
17568        let activate_pane = split;
17569
17570        let mut destination_index = None;
17571        pane.update(cx, |pane, cx| {
17572            if allow_preview && !was_existing {
17573                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17574            }
17575            if was_existing && !allow_preview {
17576                pane.unpreview_item_if_preview(item.item_id());
17577            }
17578            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17579        });
17580    }
17581
17582    pub fn rename(
17583        &mut self,
17584        _: &Rename,
17585        window: &mut Window,
17586        cx: &mut Context<Self>,
17587    ) -> Option<Task<Result<()>>> {
17588        use language::ToOffset as _;
17589
17590        let provider = self.semantics_provider.clone()?;
17591        let selection = self.selections.newest_anchor().clone();
17592        let (cursor_buffer, cursor_buffer_position) = self
17593            .buffer
17594            .read(cx)
17595            .text_anchor_for_position(selection.head(), cx)?;
17596        let (tail_buffer, cursor_buffer_position_end) = self
17597            .buffer
17598            .read(cx)
17599            .text_anchor_for_position(selection.tail(), cx)?;
17600        if tail_buffer != cursor_buffer {
17601            return None;
17602        }
17603
17604        let snapshot = cursor_buffer.read(cx).snapshot();
17605        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17606        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17607        let prepare_rename = provider
17608            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17609            .unwrap_or_else(|| Task::ready(Ok(None)));
17610        drop(snapshot);
17611
17612        Some(cx.spawn_in(window, async move |this, cx| {
17613            let rename_range = if let Some(range) = prepare_rename.await? {
17614                Some(range)
17615            } else {
17616                this.update(cx, |this, cx| {
17617                    let buffer = this.buffer.read(cx).snapshot(cx);
17618                    let mut buffer_highlights = this
17619                        .document_highlights_for_position(selection.head(), &buffer)
17620                        .filter(|highlight| {
17621                            highlight.start.excerpt_id == selection.head().excerpt_id
17622                                && highlight.end.excerpt_id == selection.head().excerpt_id
17623                        });
17624                    buffer_highlights
17625                        .next()
17626                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17627                })?
17628            };
17629            if let Some(rename_range) = rename_range {
17630                this.update_in(cx, |this, window, cx| {
17631                    let snapshot = cursor_buffer.read(cx).snapshot();
17632                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17633                    let cursor_offset_in_rename_range =
17634                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17635                    let cursor_offset_in_rename_range_end =
17636                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17637
17638                    this.take_rename(false, window, cx);
17639                    let buffer = this.buffer.read(cx).read(cx);
17640                    let cursor_offset = selection.head().to_offset(&buffer);
17641                    let rename_start =
17642                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17643                    let rename_end = rename_start + rename_buffer_range.len();
17644                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17645                    let mut old_highlight_id = None;
17646                    let old_name: Arc<str> = buffer
17647                        .chunks(rename_start..rename_end, true)
17648                        .map(|chunk| {
17649                            if old_highlight_id.is_none() {
17650                                old_highlight_id = chunk.syntax_highlight_id;
17651                            }
17652                            chunk.text
17653                        })
17654                        .collect::<String>()
17655                        .into();
17656
17657                    drop(buffer);
17658
17659                    // Position the selection in the rename editor so that it matches the current selection.
17660                    this.show_local_selections = false;
17661                    let rename_editor = cx.new(|cx| {
17662                        let mut editor = Editor::single_line(window, cx);
17663                        editor.buffer.update(cx, |buffer, cx| {
17664                            buffer.edit(
17665                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17666                                None,
17667                                cx,
17668                            )
17669                        });
17670                        let cursor_offset_in_rename_range =
17671                            MultiBufferOffset(cursor_offset_in_rename_range);
17672                        let cursor_offset_in_rename_range_end =
17673                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17674                        let rename_selection_range = match cursor_offset_in_rename_range
17675                            .cmp(&cursor_offset_in_rename_range_end)
17676                        {
17677                            Ordering::Equal => {
17678                                editor.select_all(&SelectAll, window, cx);
17679                                return editor;
17680                            }
17681                            Ordering::Less => {
17682                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17683                            }
17684                            Ordering::Greater => {
17685                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17686                            }
17687                        };
17688                        if rename_selection_range.end.0 > old_name.len() {
17689                            editor.select_all(&SelectAll, window, cx);
17690                        } else {
17691                            editor.change_selections(Default::default(), window, cx, |s| {
17692                                s.select_ranges([rename_selection_range]);
17693                            });
17694                        }
17695                        editor
17696                    });
17697                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17698                        if e == &EditorEvent::Focused {
17699                            cx.emit(EditorEvent::FocusedIn)
17700                        }
17701                    })
17702                    .detach();
17703
17704                    let write_highlights =
17705                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17706                    let read_highlights =
17707                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17708                    let ranges = write_highlights
17709                        .iter()
17710                        .flat_map(|(_, ranges)| ranges.iter())
17711                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17712                        .cloned()
17713                        .collect();
17714
17715                    this.highlight_text::<Rename>(
17716                        ranges,
17717                        HighlightStyle {
17718                            fade_out: Some(0.6),
17719                            ..Default::default()
17720                        },
17721                        cx,
17722                    );
17723                    let rename_focus_handle = rename_editor.focus_handle(cx);
17724                    window.focus(&rename_focus_handle);
17725                    let block_id = this.insert_blocks(
17726                        [BlockProperties {
17727                            style: BlockStyle::Flex,
17728                            placement: BlockPlacement::Below(range.start),
17729                            height: Some(1),
17730                            render: Arc::new({
17731                                let rename_editor = rename_editor.clone();
17732                                move |cx: &mut BlockContext| {
17733                                    let mut text_style = cx.editor_style.text.clone();
17734                                    if let Some(highlight_style) = old_highlight_id
17735                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17736                                    {
17737                                        text_style = text_style.highlight(highlight_style);
17738                                    }
17739                                    div()
17740                                        .block_mouse_except_scroll()
17741                                        .pl(cx.anchor_x)
17742                                        .child(EditorElement::new(
17743                                            &rename_editor,
17744                                            EditorStyle {
17745                                                background: cx.theme().system().transparent,
17746                                                local_player: cx.editor_style.local_player,
17747                                                text: text_style,
17748                                                scrollbar_width: cx.editor_style.scrollbar_width,
17749                                                syntax: cx.editor_style.syntax.clone(),
17750                                                status: cx.editor_style.status.clone(),
17751                                                inlay_hints_style: HighlightStyle {
17752                                                    font_weight: Some(FontWeight::BOLD),
17753                                                    ..make_inlay_hints_style(cx.app)
17754                                                },
17755                                                edit_prediction_styles: make_suggestion_styles(
17756                                                    cx.app,
17757                                                ),
17758                                                ..EditorStyle::default()
17759                                            },
17760                                        ))
17761                                        .into_any_element()
17762                                }
17763                            }),
17764                            priority: 0,
17765                        }],
17766                        Some(Autoscroll::fit()),
17767                        cx,
17768                    )[0];
17769                    this.pending_rename = Some(RenameState {
17770                        range,
17771                        old_name,
17772                        editor: rename_editor,
17773                        block_id,
17774                    });
17775                })?;
17776            }
17777
17778            Ok(())
17779        }))
17780    }
17781
17782    pub fn confirm_rename(
17783        &mut self,
17784        _: &ConfirmRename,
17785        window: &mut Window,
17786        cx: &mut Context<Self>,
17787    ) -> Option<Task<Result<()>>> {
17788        let rename = self.take_rename(false, window, cx)?;
17789        let workspace = self.workspace()?.downgrade();
17790        let (buffer, start) = self
17791            .buffer
17792            .read(cx)
17793            .text_anchor_for_position(rename.range.start, cx)?;
17794        let (end_buffer, _) = self
17795            .buffer
17796            .read(cx)
17797            .text_anchor_for_position(rename.range.end, cx)?;
17798        if buffer != end_buffer {
17799            return None;
17800        }
17801
17802        let old_name = rename.old_name;
17803        let new_name = rename.editor.read(cx).text(cx);
17804
17805        let rename = self.semantics_provider.as_ref()?.perform_rename(
17806            &buffer,
17807            start,
17808            new_name.clone(),
17809            cx,
17810        )?;
17811
17812        Some(cx.spawn_in(window, async move |editor, cx| {
17813            let project_transaction = rename.await?;
17814            Self::open_project_transaction(
17815                &editor,
17816                workspace,
17817                project_transaction,
17818                format!("Rename: {}{}", old_name, new_name),
17819                cx,
17820            )
17821            .await?;
17822
17823            editor.update(cx, |editor, cx| {
17824                editor.refresh_document_highlights(cx);
17825            })?;
17826            Ok(())
17827        }))
17828    }
17829
17830    fn take_rename(
17831        &mut self,
17832        moving_cursor: bool,
17833        window: &mut Window,
17834        cx: &mut Context<Self>,
17835    ) -> Option<RenameState> {
17836        let rename = self.pending_rename.take()?;
17837        if rename.editor.focus_handle(cx).is_focused(window) {
17838            window.focus(&self.focus_handle);
17839        }
17840
17841        self.remove_blocks(
17842            [rename.block_id].into_iter().collect(),
17843            Some(Autoscroll::fit()),
17844            cx,
17845        );
17846        self.clear_highlights::<Rename>(cx);
17847        self.show_local_selections = true;
17848
17849        if moving_cursor {
17850            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17851                editor
17852                    .selections
17853                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17854                    .head()
17855            });
17856
17857            // Update the selection to match the position of the selection inside
17858            // the rename editor.
17859            let snapshot = self.buffer.read(cx).read(cx);
17860            let rename_range = rename.range.to_offset(&snapshot);
17861            let cursor_in_editor = snapshot
17862                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17863                .min(rename_range.end);
17864            drop(snapshot);
17865
17866            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17867                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17868            });
17869        } else {
17870            self.refresh_document_highlights(cx);
17871        }
17872
17873        Some(rename)
17874    }
17875
17876    pub fn pending_rename(&self) -> Option<&RenameState> {
17877        self.pending_rename.as_ref()
17878    }
17879
17880    fn format(
17881        &mut self,
17882        _: &Format,
17883        window: &mut Window,
17884        cx: &mut Context<Self>,
17885    ) -> Option<Task<Result<()>>> {
17886        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17887
17888        let project = match &self.project {
17889            Some(project) => project.clone(),
17890            None => return None,
17891        };
17892
17893        Some(self.perform_format(
17894            project,
17895            FormatTrigger::Manual,
17896            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17897            window,
17898            cx,
17899        ))
17900    }
17901
17902    fn format_selections(
17903        &mut self,
17904        _: &FormatSelections,
17905        window: &mut Window,
17906        cx: &mut Context<Self>,
17907    ) -> Option<Task<Result<()>>> {
17908        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17909
17910        let project = match &self.project {
17911            Some(project) => project.clone(),
17912            None => return None,
17913        };
17914
17915        let ranges = self
17916            .selections
17917            .all_adjusted(&self.display_snapshot(cx))
17918            .into_iter()
17919            .map(|selection| selection.range())
17920            .collect_vec();
17921
17922        Some(self.perform_format(
17923            project,
17924            FormatTrigger::Manual,
17925            FormatTarget::Ranges(ranges),
17926            window,
17927            cx,
17928        ))
17929    }
17930
17931    fn perform_format(
17932        &mut self,
17933        project: Entity<Project>,
17934        trigger: FormatTrigger,
17935        target: FormatTarget,
17936        window: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) -> Task<Result<()>> {
17939        let buffer = self.buffer.clone();
17940        let (buffers, target) = match target {
17941            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17942            FormatTarget::Ranges(selection_ranges) => {
17943                let multi_buffer = buffer.read(cx);
17944                let snapshot = multi_buffer.read(cx);
17945                let mut buffers = HashSet::default();
17946                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17947                    BTreeMap::new();
17948                for selection_range in selection_ranges {
17949                    for (buffer, buffer_range, _) in
17950                        snapshot.range_to_buffer_ranges(selection_range)
17951                    {
17952                        let buffer_id = buffer.remote_id();
17953                        let start = buffer.anchor_before(buffer_range.start);
17954                        let end = buffer.anchor_after(buffer_range.end);
17955                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17956                        buffer_id_to_ranges
17957                            .entry(buffer_id)
17958                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17959                            .or_insert_with(|| vec![start..end]);
17960                    }
17961                }
17962                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17963            }
17964        };
17965
17966        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17967        let selections_prev = transaction_id_prev
17968            .and_then(|transaction_id_prev| {
17969                // default to selections as they were after the last edit, if we have them,
17970                // instead of how they are now.
17971                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17972                // will take you back to where you made the last edit, instead of staying where you scrolled
17973                self.selection_history
17974                    .transaction(transaction_id_prev)
17975                    .map(|t| t.0.clone())
17976            })
17977            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17978
17979        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17980        let format = project.update(cx, |project, cx| {
17981            project.format(buffers, target, true, trigger, cx)
17982        });
17983
17984        cx.spawn_in(window, async move |editor, cx| {
17985            let transaction = futures::select_biased! {
17986                transaction = format.log_err().fuse() => transaction,
17987                () = timeout => {
17988                    log::warn!("timed out waiting for formatting");
17989                    None
17990                }
17991            };
17992
17993            buffer
17994                .update(cx, |buffer, cx| {
17995                    if let Some(transaction) = transaction
17996                        && !buffer.is_singleton()
17997                    {
17998                        buffer.push_transaction(&transaction.0, cx);
17999                    }
18000                    cx.notify();
18001                })
18002                .ok();
18003
18004            if let Some(transaction_id_now) =
18005                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18006            {
18007                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18008                if has_new_transaction {
18009                    _ = editor.update(cx, |editor, _| {
18010                        editor
18011                            .selection_history
18012                            .insert_transaction(transaction_id_now, selections_prev);
18013                    });
18014                }
18015            }
18016
18017            Ok(())
18018        })
18019    }
18020
18021    fn organize_imports(
18022        &mut self,
18023        _: &OrganizeImports,
18024        window: &mut Window,
18025        cx: &mut Context<Self>,
18026    ) -> Option<Task<Result<()>>> {
18027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18028        let project = match &self.project {
18029            Some(project) => project.clone(),
18030            None => return None,
18031        };
18032        Some(self.perform_code_action_kind(
18033            project,
18034            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18035            window,
18036            cx,
18037        ))
18038    }
18039
18040    fn perform_code_action_kind(
18041        &mut self,
18042        project: Entity<Project>,
18043        kind: CodeActionKind,
18044        window: &mut Window,
18045        cx: &mut Context<Self>,
18046    ) -> Task<Result<()>> {
18047        let buffer = self.buffer.clone();
18048        let buffers = buffer.read(cx).all_buffers();
18049        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18050        let apply_action = project.update(cx, |project, cx| {
18051            project.apply_code_action_kind(buffers, kind, true, cx)
18052        });
18053        cx.spawn_in(window, async move |_, cx| {
18054            let transaction = futures::select_biased! {
18055                () = timeout => {
18056                    log::warn!("timed out waiting for executing code action");
18057                    None
18058                }
18059                transaction = apply_action.log_err().fuse() => transaction,
18060            };
18061            buffer
18062                .update(cx, |buffer, cx| {
18063                    // check if we need this
18064                    if let Some(transaction) = transaction
18065                        && !buffer.is_singleton()
18066                    {
18067                        buffer.push_transaction(&transaction.0, cx);
18068                    }
18069                    cx.notify();
18070                })
18071                .ok();
18072            Ok(())
18073        })
18074    }
18075
18076    pub fn restart_language_server(
18077        &mut self,
18078        _: &RestartLanguageServer,
18079        _: &mut Window,
18080        cx: &mut Context<Self>,
18081    ) {
18082        if let Some(project) = self.project.clone() {
18083            self.buffer.update(cx, |multi_buffer, cx| {
18084                project.update(cx, |project, cx| {
18085                    project.restart_language_servers_for_buffers(
18086                        multi_buffer.all_buffers().into_iter().collect(),
18087                        HashSet::default(),
18088                        cx,
18089                    );
18090                });
18091            })
18092        }
18093    }
18094
18095    pub fn stop_language_server(
18096        &mut self,
18097        _: &StopLanguageServer,
18098        _: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        if let Some(project) = self.project.clone() {
18102            self.buffer.update(cx, |multi_buffer, cx| {
18103                project.update(cx, |project, cx| {
18104                    project.stop_language_servers_for_buffers(
18105                        multi_buffer.all_buffers().into_iter().collect(),
18106                        HashSet::default(),
18107                        cx,
18108                    );
18109                });
18110            });
18111            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18112        }
18113    }
18114
18115    fn cancel_language_server_work(
18116        workspace: &mut Workspace,
18117        _: &actions::CancelLanguageServerWork,
18118        _: &mut Window,
18119        cx: &mut Context<Workspace>,
18120    ) {
18121        let project = workspace.project();
18122        let buffers = workspace
18123            .active_item(cx)
18124            .and_then(|item| item.act_as::<Editor>(cx))
18125            .map_or(HashSet::default(), |editor| {
18126                editor.read(cx).buffer.read(cx).all_buffers()
18127            });
18128        project.update(cx, |project, cx| {
18129            project.cancel_language_server_work_for_buffers(buffers, cx);
18130        });
18131    }
18132
18133    fn show_character_palette(
18134        &mut self,
18135        _: &ShowCharacterPalette,
18136        window: &mut Window,
18137        _: &mut Context<Self>,
18138    ) {
18139        window.show_character_palette();
18140    }
18141
18142    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18143        if !self.diagnostics_enabled() {
18144            return;
18145        }
18146
18147        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18148            let buffer = self.buffer.read(cx).snapshot(cx);
18149            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18150            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18151            let is_valid = buffer
18152                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18153                .any(|entry| {
18154                    entry.diagnostic.is_primary
18155                        && !entry.range.is_empty()
18156                        && entry.range.start == primary_range_start
18157                        && entry.diagnostic.message == active_diagnostics.active_message
18158                });
18159
18160            if !is_valid {
18161                self.dismiss_diagnostics(cx);
18162            }
18163        }
18164    }
18165
18166    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18167        match &self.active_diagnostics {
18168            ActiveDiagnostic::Group(group) => Some(group),
18169            _ => None,
18170        }
18171    }
18172
18173    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18174        if !self.diagnostics_enabled() {
18175            return;
18176        }
18177        self.dismiss_diagnostics(cx);
18178        self.active_diagnostics = ActiveDiagnostic::All;
18179    }
18180
18181    fn activate_diagnostics(
18182        &mut self,
18183        buffer_id: BufferId,
18184        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18185        window: &mut Window,
18186        cx: &mut Context<Self>,
18187    ) {
18188        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18189            return;
18190        }
18191        self.dismiss_diagnostics(cx);
18192        let snapshot = self.snapshot(window, cx);
18193        let buffer = self.buffer.read(cx).snapshot(cx);
18194        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18195            return;
18196        };
18197
18198        let diagnostic_group = buffer
18199            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18200            .collect::<Vec<_>>();
18201
18202        let language_registry = self
18203            .project()
18204            .map(|project| project.read(cx).languages().clone());
18205
18206        let blocks = renderer.render_group(
18207            diagnostic_group,
18208            buffer_id,
18209            snapshot,
18210            cx.weak_entity(),
18211            language_registry,
18212            cx,
18213        );
18214
18215        let blocks = self.display_map.update(cx, |display_map, cx| {
18216            display_map.insert_blocks(blocks, cx).into_iter().collect()
18217        });
18218        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18219            active_range: buffer.anchor_before(diagnostic.range.start)
18220                ..buffer.anchor_after(diagnostic.range.end),
18221            active_message: diagnostic.diagnostic.message.clone(),
18222            group_id: diagnostic.diagnostic.group_id,
18223            blocks,
18224        });
18225        cx.notify();
18226    }
18227
18228    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18229        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18230            return;
18231        };
18232
18233        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18234        if let ActiveDiagnostic::Group(group) = prev {
18235            self.display_map.update(cx, |display_map, cx| {
18236                display_map.remove_blocks(group.blocks, cx);
18237            });
18238            cx.notify();
18239        }
18240    }
18241
18242    /// Disable inline diagnostics rendering for this editor.
18243    pub fn disable_inline_diagnostics(&mut self) {
18244        self.inline_diagnostics_enabled = false;
18245        self.inline_diagnostics_update = Task::ready(());
18246        self.inline_diagnostics.clear();
18247    }
18248
18249    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18250        self.diagnostics_enabled = false;
18251        self.dismiss_diagnostics(cx);
18252        self.inline_diagnostics_update = Task::ready(());
18253        self.inline_diagnostics.clear();
18254    }
18255
18256    pub fn disable_word_completions(&mut self) {
18257        self.word_completions_enabled = false;
18258    }
18259
18260    pub fn diagnostics_enabled(&self) -> bool {
18261        self.diagnostics_enabled && self.mode.is_full()
18262    }
18263
18264    pub fn inline_diagnostics_enabled(&self) -> bool {
18265        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18266    }
18267
18268    pub fn show_inline_diagnostics(&self) -> bool {
18269        self.show_inline_diagnostics
18270    }
18271
18272    pub fn toggle_inline_diagnostics(
18273        &mut self,
18274        _: &ToggleInlineDiagnostics,
18275        window: &mut Window,
18276        cx: &mut Context<Editor>,
18277    ) {
18278        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18279        self.refresh_inline_diagnostics(false, window, cx);
18280    }
18281
18282    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18283        self.diagnostics_max_severity = severity;
18284        self.display_map.update(cx, |display_map, _| {
18285            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18286        });
18287    }
18288
18289    pub fn toggle_diagnostics(
18290        &mut self,
18291        _: &ToggleDiagnostics,
18292        window: &mut Window,
18293        cx: &mut Context<Editor>,
18294    ) {
18295        if !self.diagnostics_enabled() {
18296            return;
18297        }
18298
18299        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18300            EditorSettings::get_global(cx)
18301                .diagnostics_max_severity
18302                .filter(|severity| severity != &DiagnosticSeverity::Off)
18303                .unwrap_or(DiagnosticSeverity::Hint)
18304        } else {
18305            DiagnosticSeverity::Off
18306        };
18307        self.set_max_diagnostics_severity(new_severity, cx);
18308        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18309            self.active_diagnostics = ActiveDiagnostic::None;
18310            self.inline_diagnostics_update = Task::ready(());
18311            self.inline_diagnostics.clear();
18312        } else {
18313            self.refresh_inline_diagnostics(false, window, cx);
18314        }
18315
18316        cx.notify();
18317    }
18318
18319    pub fn toggle_minimap(
18320        &mut self,
18321        _: &ToggleMinimap,
18322        window: &mut Window,
18323        cx: &mut Context<Editor>,
18324    ) {
18325        if self.supports_minimap(cx) {
18326            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18327        }
18328    }
18329
18330    fn refresh_inline_diagnostics(
18331        &mut self,
18332        debounce: bool,
18333        window: &mut Window,
18334        cx: &mut Context<Self>,
18335    ) {
18336        let max_severity = ProjectSettings::get_global(cx)
18337            .diagnostics
18338            .inline
18339            .max_severity
18340            .unwrap_or(self.diagnostics_max_severity);
18341
18342        if !self.inline_diagnostics_enabled()
18343            || !self.diagnostics_enabled()
18344            || !self.show_inline_diagnostics
18345            || max_severity == DiagnosticSeverity::Off
18346        {
18347            self.inline_diagnostics_update = Task::ready(());
18348            self.inline_diagnostics.clear();
18349            return;
18350        }
18351
18352        let debounce_ms = ProjectSettings::get_global(cx)
18353            .diagnostics
18354            .inline
18355            .update_debounce_ms;
18356        let debounce = if debounce && debounce_ms > 0 {
18357            Some(Duration::from_millis(debounce_ms))
18358        } else {
18359            None
18360        };
18361        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18362            if let Some(debounce) = debounce {
18363                cx.background_executor().timer(debounce).await;
18364            }
18365            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18366                editor
18367                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18368                    .ok()
18369            }) else {
18370                return;
18371            };
18372
18373            let new_inline_diagnostics = cx
18374                .background_spawn(async move {
18375                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18376                    for diagnostic_entry in
18377                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18378                    {
18379                        let message = diagnostic_entry
18380                            .diagnostic
18381                            .message
18382                            .split_once('\n')
18383                            .map(|(line, _)| line)
18384                            .map(SharedString::new)
18385                            .unwrap_or_else(|| {
18386                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18387                            });
18388                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18389                        let (Ok(i) | Err(i)) = inline_diagnostics
18390                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18391                        inline_diagnostics.insert(
18392                            i,
18393                            (
18394                                start_anchor,
18395                                InlineDiagnostic {
18396                                    message,
18397                                    group_id: diagnostic_entry.diagnostic.group_id,
18398                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18399                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18400                                    severity: diagnostic_entry.diagnostic.severity,
18401                                },
18402                            ),
18403                        );
18404                    }
18405                    inline_diagnostics
18406                })
18407                .await;
18408
18409            editor
18410                .update(cx, |editor, cx| {
18411                    editor.inline_diagnostics = new_inline_diagnostics;
18412                    cx.notify();
18413                })
18414                .ok();
18415        });
18416    }
18417
18418    fn pull_diagnostics(
18419        &mut self,
18420        buffer_id: Option<BufferId>,
18421        window: &Window,
18422        cx: &mut Context<Self>,
18423    ) -> Option<()> {
18424        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18425            return None;
18426        }
18427        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18428            .diagnostics
18429            .lsp_pull_diagnostics;
18430        if !pull_diagnostics_settings.enabled {
18431            return None;
18432        }
18433        let project = self.project()?.downgrade();
18434
18435        let mut edited_buffer_ids = HashSet::default();
18436        let mut edited_worktree_ids = HashSet::default();
18437        let edited_buffers = match buffer_id {
18438            Some(buffer_id) => {
18439                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18440                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18441                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18442                edited_worktree_ids.insert(worktree_id);
18443                vec![buffer]
18444            }
18445            None => self
18446                .buffer()
18447                .read(cx)
18448                .all_buffers()
18449                .into_iter()
18450                .filter(|buffer| {
18451                    let buffer = buffer.read(cx);
18452                    match buffer.file().map(|f| f.worktree_id(cx)) {
18453                        Some(worktree_id) => {
18454                            edited_buffer_ids.insert(buffer.remote_id());
18455                            edited_worktree_ids.insert(worktree_id);
18456                            true
18457                        }
18458                        None => false,
18459                    }
18460                })
18461                .collect::<Vec<_>>(),
18462        };
18463
18464        if edited_buffers.is_empty() {
18465            self.pull_diagnostics_task = Task::ready(());
18466            self.pull_diagnostics_background_task = Task::ready(());
18467            return None;
18468        }
18469
18470        let mut already_used_buffers = HashSet::default();
18471        let related_open_buffers = self
18472            .workspace
18473            .as_ref()
18474            .and_then(|(workspace, _)| workspace.upgrade())
18475            .into_iter()
18476            .flat_map(|workspace| workspace.read(cx).panes())
18477            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18478            .filter(|editor| editor != &cx.entity())
18479            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18480            .filter(|buffer| {
18481                let buffer = buffer.read(cx);
18482                let buffer_id = buffer.remote_id();
18483                if already_used_buffers.insert(buffer_id) {
18484                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18485                        return !edited_buffer_ids.contains(&buffer_id)
18486                            && !edited_worktree_ids.contains(&worktree_id);
18487                    }
18488                }
18489                false
18490            })
18491            .collect::<Vec<_>>();
18492
18493        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18494        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18495            if buffers.is_empty() {
18496                return Task::ready(());
18497            }
18498            let project_weak = project.clone();
18499            cx.spawn_in(window, async move |_, cx| {
18500                cx.background_executor().timer(delay).await;
18501
18502                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18503                    buffers
18504                        .into_iter()
18505                        .filter_map(|buffer| {
18506                            project_weak
18507                                .update(cx, |project, cx| {
18508                                    project.lsp_store().update(cx, |lsp_store, cx| {
18509                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18510                                    })
18511                                })
18512                                .ok()
18513                        })
18514                        .collect::<FuturesUnordered<_>>()
18515                }) else {
18516                    return;
18517                };
18518
18519                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18520                    if let Err(e) = pull_task {
18521                        log::error!("Failed to update project diagnostics: {e:#}");
18522                    }
18523                }
18524            })
18525        };
18526
18527        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18528        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18529
18530        Some(())
18531    }
18532
18533    pub fn set_selections_from_remote(
18534        &mut self,
18535        selections: Vec<Selection<Anchor>>,
18536        pending_selection: Option<Selection<Anchor>>,
18537        window: &mut Window,
18538        cx: &mut Context<Self>,
18539    ) {
18540        let old_cursor_position = self.selections.newest_anchor().head();
18541        self.selections
18542            .change_with(&self.display_snapshot(cx), |s| {
18543                s.select_anchors(selections);
18544                if let Some(pending_selection) = pending_selection {
18545                    s.set_pending(pending_selection, SelectMode::Character);
18546                } else {
18547                    s.clear_pending();
18548                }
18549            });
18550        self.selections_did_change(
18551            false,
18552            &old_cursor_position,
18553            SelectionEffects::default(),
18554            window,
18555            cx,
18556        );
18557    }
18558
18559    pub fn transact(
18560        &mut self,
18561        window: &mut Window,
18562        cx: &mut Context<Self>,
18563        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18564    ) -> Option<TransactionId> {
18565        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18566            this.start_transaction_at(Instant::now(), window, cx);
18567            update(this, window, cx);
18568            this.end_transaction_at(Instant::now(), cx)
18569        })
18570    }
18571
18572    pub fn start_transaction_at(
18573        &mut self,
18574        now: Instant,
18575        window: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) -> Option<TransactionId> {
18578        self.end_selection(window, cx);
18579        if let Some(tx_id) = self
18580            .buffer
18581            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18582        {
18583            self.selection_history
18584                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18585            cx.emit(EditorEvent::TransactionBegun {
18586                transaction_id: tx_id,
18587            });
18588            Some(tx_id)
18589        } else {
18590            None
18591        }
18592    }
18593
18594    pub fn end_transaction_at(
18595        &mut self,
18596        now: Instant,
18597        cx: &mut Context<Self>,
18598    ) -> Option<TransactionId> {
18599        if let Some(transaction_id) = self
18600            .buffer
18601            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18602        {
18603            if let Some((_, end_selections)) =
18604                self.selection_history.transaction_mut(transaction_id)
18605            {
18606                *end_selections = Some(self.selections.disjoint_anchors_arc());
18607            } else {
18608                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18609            }
18610
18611            cx.emit(EditorEvent::Edited { transaction_id });
18612            Some(transaction_id)
18613        } else {
18614            None
18615        }
18616    }
18617
18618    pub fn modify_transaction_selection_history(
18619        &mut self,
18620        transaction_id: TransactionId,
18621        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18622    ) -> bool {
18623        self.selection_history
18624            .transaction_mut(transaction_id)
18625            .map(modify)
18626            .is_some()
18627    }
18628
18629    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18630        if self.selection_mark_mode {
18631            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18632                s.move_with(|_, sel| {
18633                    sel.collapse_to(sel.head(), SelectionGoal::None);
18634                });
18635            })
18636        }
18637        self.selection_mark_mode = true;
18638        cx.notify();
18639    }
18640
18641    pub fn swap_selection_ends(
18642        &mut self,
18643        _: &actions::SwapSelectionEnds,
18644        window: &mut Window,
18645        cx: &mut Context<Self>,
18646    ) {
18647        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18648            s.move_with(|_, sel| {
18649                if sel.start != sel.end {
18650                    sel.reversed = !sel.reversed
18651                }
18652            });
18653        });
18654        self.request_autoscroll(Autoscroll::newest(), cx);
18655        cx.notify();
18656    }
18657
18658    pub fn toggle_focus(
18659        workspace: &mut Workspace,
18660        _: &actions::ToggleFocus,
18661        window: &mut Window,
18662        cx: &mut Context<Workspace>,
18663    ) {
18664        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18665            return;
18666        };
18667        workspace.activate_item(&item, true, true, window, cx);
18668    }
18669
18670    pub fn toggle_fold(
18671        &mut self,
18672        _: &actions::ToggleFold,
18673        window: &mut Window,
18674        cx: &mut Context<Self>,
18675    ) {
18676        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18677            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18678            let selection = self.selections.newest::<Point>(&display_map);
18679
18680            let range = if selection.is_empty() {
18681                let point = selection.head().to_display_point(&display_map);
18682                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18683                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18684                    .to_point(&display_map);
18685                start..end
18686            } else {
18687                selection.range()
18688            };
18689            if display_map.folds_in_range(range).next().is_some() {
18690                self.unfold_lines(&Default::default(), window, cx)
18691            } else {
18692                self.fold(&Default::default(), window, cx)
18693            }
18694        } else {
18695            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18696            let buffer_ids: HashSet<_> = self
18697                .selections
18698                .disjoint_anchor_ranges()
18699                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18700                .collect();
18701
18702            let should_unfold = buffer_ids
18703                .iter()
18704                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18705
18706            for buffer_id in buffer_ids {
18707                if should_unfold {
18708                    self.unfold_buffer(buffer_id, cx);
18709                } else {
18710                    self.fold_buffer(buffer_id, cx);
18711                }
18712            }
18713        }
18714    }
18715
18716    pub fn toggle_fold_recursive(
18717        &mut self,
18718        _: &actions::ToggleFoldRecursive,
18719        window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18723
18724        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18725        let range = if selection.is_empty() {
18726            let point = selection.head().to_display_point(&display_map);
18727            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18728            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18729                .to_point(&display_map);
18730            start..end
18731        } else {
18732            selection.range()
18733        };
18734        if display_map.folds_in_range(range).next().is_some() {
18735            self.unfold_recursive(&Default::default(), window, cx)
18736        } else {
18737            self.fold_recursive(&Default::default(), window, cx)
18738        }
18739    }
18740
18741    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18742        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18743            let mut to_fold = Vec::new();
18744            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18745            let selections = self.selections.all_adjusted(&display_map);
18746
18747            for selection in selections {
18748                let range = selection.range().sorted();
18749                let buffer_start_row = range.start.row;
18750
18751                if range.start.row != range.end.row {
18752                    let mut found = false;
18753                    let mut row = range.start.row;
18754                    while row <= range.end.row {
18755                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18756                        {
18757                            found = true;
18758                            row = crease.range().end.row + 1;
18759                            to_fold.push(crease);
18760                        } else {
18761                            row += 1
18762                        }
18763                    }
18764                    if found {
18765                        continue;
18766                    }
18767                }
18768
18769                for row in (0..=range.start.row).rev() {
18770                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18771                        && crease.range().end.row >= buffer_start_row
18772                    {
18773                        to_fold.push(crease);
18774                        if row <= range.start.row {
18775                            break;
18776                        }
18777                    }
18778                }
18779            }
18780
18781            self.fold_creases(to_fold, true, window, cx);
18782        } else {
18783            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18784            let buffer_ids = self
18785                .selections
18786                .disjoint_anchor_ranges()
18787                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18788                .collect::<HashSet<_>>();
18789            for buffer_id in buffer_ids {
18790                self.fold_buffer(buffer_id, cx);
18791            }
18792        }
18793    }
18794
18795    pub fn toggle_fold_all(
18796        &mut self,
18797        _: &actions::ToggleFoldAll,
18798        window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        if self.buffer.read(cx).is_singleton() {
18802            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18803            let has_folds = display_map
18804                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18805                .next()
18806                .is_some();
18807
18808            if has_folds {
18809                self.unfold_all(&actions::UnfoldAll, window, cx);
18810            } else {
18811                self.fold_all(&actions::FoldAll, window, cx);
18812            }
18813        } else {
18814            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18815            let should_unfold = buffer_ids
18816                .iter()
18817                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18818
18819            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18820                editor
18821                    .update_in(cx, |editor, _, cx| {
18822                        for buffer_id in buffer_ids {
18823                            if should_unfold {
18824                                editor.unfold_buffer(buffer_id, cx);
18825                            } else {
18826                                editor.fold_buffer(buffer_id, cx);
18827                            }
18828                        }
18829                    })
18830                    .ok();
18831            });
18832        }
18833    }
18834
18835    fn fold_at_level(
18836        &mut self,
18837        fold_at: &FoldAtLevel,
18838        window: &mut Window,
18839        cx: &mut Context<Self>,
18840    ) {
18841        if !self.buffer.read(cx).is_singleton() {
18842            return;
18843        }
18844
18845        let fold_at_level = fold_at.0;
18846        let snapshot = self.buffer.read(cx).snapshot(cx);
18847        let mut to_fold = Vec::new();
18848        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18849
18850        let row_ranges_to_keep: Vec<Range<u32>> = self
18851            .selections
18852            .all::<Point>(&self.display_snapshot(cx))
18853            .into_iter()
18854            .map(|sel| sel.start.row..sel.end.row)
18855            .collect();
18856
18857        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18858            while start_row < end_row {
18859                match self
18860                    .snapshot(window, cx)
18861                    .crease_for_buffer_row(MultiBufferRow(start_row))
18862                {
18863                    Some(crease) => {
18864                        let nested_start_row = crease.range().start.row + 1;
18865                        let nested_end_row = crease.range().end.row;
18866
18867                        if current_level < fold_at_level {
18868                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18869                        } else if current_level == fold_at_level {
18870                            // Fold iff there is no selection completely contained within the fold region
18871                            if !row_ranges_to_keep.iter().any(|selection| {
18872                                selection.end >= nested_start_row
18873                                    && selection.start <= nested_end_row
18874                            }) {
18875                                to_fold.push(crease);
18876                            }
18877                        }
18878
18879                        start_row = nested_end_row + 1;
18880                    }
18881                    None => start_row += 1,
18882                }
18883            }
18884        }
18885
18886        self.fold_creases(to_fold, true, window, cx);
18887    }
18888
18889    pub fn fold_at_level_1(
18890        &mut self,
18891        _: &actions::FoldAtLevel1,
18892        window: &mut Window,
18893        cx: &mut Context<Self>,
18894    ) {
18895        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18896    }
18897
18898    pub fn fold_at_level_2(
18899        &mut self,
18900        _: &actions::FoldAtLevel2,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18905    }
18906
18907    pub fn fold_at_level_3(
18908        &mut self,
18909        _: &actions::FoldAtLevel3,
18910        window: &mut Window,
18911        cx: &mut Context<Self>,
18912    ) {
18913        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18914    }
18915
18916    pub fn fold_at_level_4(
18917        &mut self,
18918        _: &actions::FoldAtLevel4,
18919        window: &mut Window,
18920        cx: &mut Context<Self>,
18921    ) {
18922        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18923    }
18924
18925    pub fn fold_at_level_5(
18926        &mut self,
18927        _: &actions::FoldAtLevel5,
18928        window: &mut Window,
18929        cx: &mut Context<Self>,
18930    ) {
18931        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18932    }
18933
18934    pub fn fold_at_level_6(
18935        &mut self,
18936        _: &actions::FoldAtLevel6,
18937        window: &mut Window,
18938        cx: &mut Context<Self>,
18939    ) {
18940        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18941    }
18942
18943    pub fn fold_at_level_7(
18944        &mut self,
18945        _: &actions::FoldAtLevel7,
18946        window: &mut Window,
18947        cx: &mut Context<Self>,
18948    ) {
18949        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18950    }
18951
18952    pub fn fold_at_level_8(
18953        &mut self,
18954        _: &actions::FoldAtLevel8,
18955        window: &mut Window,
18956        cx: &mut Context<Self>,
18957    ) {
18958        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18959    }
18960
18961    pub fn fold_at_level_9(
18962        &mut self,
18963        _: &actions::FoldAtLevel9,
18964        window: &mut Window,
18965        cx: &mut Context<Self>,
18966    ) {
18967        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18968    }
18969
18970    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18971        if self.buffer.read(cx).is_singleton() {
18972            let mut fold_ranges = Vec::new();
18973            let snapshot = self.buffer.read(cx).snapshot(cx);
18974
18975            for row in 0..snapshot.max_row().0 {
18976                if let Some(foldable_range) = self
18977                    .snapshot(window, cx)
18978                    .crease_for_buffer_row(MultiBufferRow(row))
18979                {
18980                    fold_ranges.push(foldable_range);
18981                }
18982            }
18983
18984            self.fold_creases(fold_ranges, true, window, cx);
18985        } else {
18986            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18987                editor
18988                    .update_in(cx, |editor, _, cx| {
18989                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18990                            editor.fold_buffer(buffer_id, cx);
18991                        }
18992                    })
18993                    .ok();
18994            });
18995        }
18996    }
18997
18998    pub fn fold_function_bodies(
18999        &mut self,
19000        _: &actions::FoldFunctionBodies,
19001        window: &mut Window,
19002        cx: &mut Context<Self>,
19003    ) {
19004        let snapshot = self.buffer.read(cx).snapshot(cx);
19005
19006        let ranges = snapshot
19007            .text_object_ranges(
19008                MultiBufferOffset(0)..snapshot.len(),
19009                TreeSitterOptions::default(),
19010            )
19011            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19012            .collect::<Vec<_>>();
19013
19014        let creases = ranges
19015            .into_iter()
19016            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19017            .collect();
19018
19019        self.fold_creases(creases, true, window, cx);
19020    }
19021
19022    pub fn fold_recursive(
19023        &mut self,
19024        _: &actions::FoldRecursive,
19025        window: &mut Window,
19026        cx: &mut Context<Self>,
19027    ) {
19028        let mut to_fold = Vec::new();
19029        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19030        let selections = self.selections.all_adjusted(&display_map);
19031
19032        for selection in selections {
19033            let range = selection.range().sorted();
19034            let buffer_start_row = range.start.row;
19035
19036            if range.start.row != range.end.row {
19037                let mut found = false;
19038                for row in range.start.row..=range.end.row {
19039                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19040                        found = true;
19041                        to_fold.push(crease);
19042                    }
19043                }
19044                if found {
19045                    continue;
19046                }
19047            }
19048
19049            for row in (0..=range.start.row).rev() {
19050                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19051                    if crease.range().end.row >= buffer_start_row {
19052                        to_fold.push(crease);
19053                    } else {
19054                        break;
19055                    }
19056                }
19057            }
19058        }
19059
19060        self.fold_creases(to_fold, true, window, cx);
19061    }
19062
19063    pub fn fold_at(
19064        &mut self,
19065        buffer_row: MultiBufferRow,
19066        window: &mut Window,
19067        cx: &mut Context<Self>,
19068    ) {
19069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19070
19071        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19072            let autoscroll = self
19073                .selections
19074                .all::<Point>(&display_map)
19075                .iter()
19076                .any(|selection| crease.range().overlaps(&selection.range()));
19077
19078            self.fold_creases(vec![crease], autoscroll, window, cx);
19079        }
19080    }
19081
19082    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19083        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19084            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19085            let buffer = display_map.buffer_snapshot();
19086            let selections = self.selections.all::<Point>(&display_map);
19087            let ranges = selections
19088                .iter()
19089                .map(|s| {
19090                    let range = s.display_range(&display_map).sorted();
19091                    let mut start = range.start.to_point(&display_map);
19092                    let mut end = range.end.to_point(&display_map);
19093                    start.column = 0;
19094                    end.column = buffer.line_len(MultiBufferRow(end.row));
19095                    start..end
19096                })
19097                .collect::<Vec<_>>();
19098
19099            self.unfold_ranges(&ranges, true, true, cx);
19100        } else {
19101            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19102            let buffer_ids = self
19103                .selections
19104                .disjoint_anchor_ranges()
19105                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19106                .collect::<HashSet<_>>();
19107            for buffer_id in buffer_ids {
19108                self.unfold_buffer(buffer_id, cx);
19109            }
19110        }
19111    }
19112
19113    pub fn unfold_recursive(
19114        &mut self,
19115        _: &UnfoldRecursive,
19116        _window: &mut Window,
19117        cx: &mut Context<Self>,
19118    ) {
19119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19120        let selections = self.selections.all::<Point>(&display_map);
19121        let ranges = selections
19122            .iter()
19123            .map(|s| {
19124                let mut range = s.display_range(&display_map).sorted();
19125                *range.start.column_mut() = 0;
19126                *range.end.column_mut() = display_map.line_len(range.end.row());
19127                let start = range.start.to_point(&display_map);
19128                let end = range.end.to_point(&display_map);
19129                start..end
19130            })
19131            .collect::<Vec<_>>();
19132
19133        self.unfold_ranges(&ranges, true, true, cx);
19134    }
19135
19136    pub fn unfold_at(
19137        &mut self,
19138        buffer_row: MultiBufferRow,
19139        _window: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19143
19144        let intersection_range = Point::new(buffer_row.0, 0)
19145            ..Point::new(
19146                buffer_row.0,
19147                display_map.buffer_snapshot().line_len(buffer_row),
19148            );
19149
19150        let autoscroll = self
19151            .selections
19152            .all::<Point>(&display_map)
19153            .iter()
19154            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19155
19156        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19157    }
19158
19159    pub fn unfold_all(
19160        &mut self,
19161        _: &actions::UnfoldAll,
19162        _window: &mut Window,
19163        cx: &mut Context<Self>,
19164    ) {
19165        if self.buffer.read(cx).is_singleton() {
19166            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19167            self.unfold_ranges(
19168                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19169                true,
19170                true,
19171                cx,
19172            );
19173        } else {
19174            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19175                editor
19176                    .update(cx, |editor, cx| {
19177                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19178                            editor.unfold_buffer(buffer_id, cx);
19179                        }
19180                    })
19181                    .ok();
19182            });
19183        }
19184    }
19185
19186    pub fn fold_selected_ranges(
19187        &mut self,
19188        _: &FoldSelectedRanges,
19189        window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19193        let selections = self.selections.all_adjusted(&display_map);
19194        let ranges = selections
19195            .into_iter()
19196            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19197            .collect::<Vec<_>>();
19198        self.fold_creases(ranges, true, window, cx);
19199    }
19200
19201    pub fn fold_ranges<T: ToOffset + Clone>(
19202        &mut self,
19203        ranges: Vec<Range<T>>,
19204        auto_scroll: bool,
19205        window: &mut Window,
19206        cx: &mut Context<Self>,
19207    ) {
19208        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19209        let ranges = ranges
19210            .into_iter()
19211            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19212            .collect::<Vec<_>>();
19213        self.fold_creases(ranges, auto_scroll, window, cx);
19214    }
19215
19216    pub fn fold_creases<T: ToOffset + Clone>(
19217        &mut self,
19218        creases: Vec<Crease<T>>,
19219        auto_scroll: bool,
19220        _window: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) {
19223        if creases.is_empty() {
19224            return;
19225        }
19226
19227        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19228
19229        if auto_scroll {
19230            self.request_autoscroll(Autoscroll::fit(), cx);
19231        }
19232
19233        cx.notify();
19234
19235        self.scrollbar_marker_state.dirty = true;
19236        self.folds_did_change(cx);
19237    }
19238
19239    /// Removes any folds whose ranges intersect any of the given ranges.
19240    pub fn unfold_ranges<T: ToOffset + Clone>(
19241        &mut self,
19242        ranges: &[Range<T>],
19243        inclusive: bool,
19244        auto_scroll: bool,
19245        cx: &mut Context<Self>,
19246    ) {
19247        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19248            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19249        });
19250        self.folds_did_change(cx);
19251    }
19252
19253    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19254        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19255            return;
19256        }
19257
19258        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19259        self.display_map.update(cx, |display_map, cx| {
19260            display_map.fold_buffers([buffer_id], cx)
19261        });
19262
19263        let snapshot = self.display_snapshot(cx);
19264        self.selections.change_with(&snapshot, |selections| {
19265            selections.remove_selections_from_buffer(buffer_id);
19266        });
19267
19268        cx.emit(EditorEvent::BufferFoldToggled {
19269            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19270            folded: true,
19271        });
19272        cx.notify();
19273    }
19274
19275    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19276        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19277            return;
19278        }
19279        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19280        self.display_map.update(cx, |display_map, cx| {
19281            display_map.unfold_buffers([buffer_id], cx);
19282        });
19283        cx.emit(EditorEvent::BufferFoldToggled {
19284            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19285            folded: false,
19286        });
19287        cx.notify();
19288    }
19289
19290    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19291        self.display_map.read(cx).is_buffer_folded(buffer)
19292    }
19293
19294    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19295        self.display_map.read(cx).folded_buffers()
19296    }
19297
19298    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19299        self.display_map.update(cx, |display_map, cx| {
19300            display_map.disable_header_for_buffer(buffer_id, cx);
19301        });
19302        cx.notify();
19303    }
19304
19305    /// Removes any folds with the given ranges.
19306    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19307        &mut self,
19308        ranges: &[Range<T>],
19309        type_id: TypeId,
19310        auto_scroll: bool,
19311        cx: &mut Context<Self>,
19312    ) {
19313        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19314            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19315        });
19316        self.folds_did_change(cx);
19317    }
19318
19319    fn remove_folds_with<T: ToOffset + Clone>(
19320        &mut self,
19321        ranges: &[Range<T>],
19322        auto_scroll: bool,
19323        cx: &mut Context<Self>,
19324        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19325    ) {
19326        if ranges.is_empty() {
19327            return;
19328        }
19329
19330        let mut buffers_affected = HashSet::default();
19331        let multi_buffer = self.buffer().read(cx);
19332        for range in ranges {
19333            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19334                buffers_affected.insert(buffer.read(cx).remote_id());
19335            };
19336        }
19337
19338        self.display_map.update(cx, update);
19339
19340        if auto_scroll {
19341            self.request_autoscroll(Autoscroll::fit(), cx);
19342        }
19343
19344        cx.notify();
19345        self.scrollbar_marker_state.dirty = true;
19346        self.active_indent_guides_state.dirty = true;
19347    }
19348
19349    pub fn update_renderer_widths(
19350        &mut self,
19351        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19352        cx: &mut Context<Self>,
19353    ) -> bool {
19354        self.display_map
19355            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19356    }
19357
19358    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19359        self.display_map.read(cx).fold_placeholder.clone()
19360    }
19361
19362    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19363        self.use_base_text_line_numbers = show;
19364    }
19365
19366    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19367        self.buffer.update(cx, |buffer, cx| {
19368            buffer.set_all_diff_hunks_expanded(cx);
19369        });
19370    }
19371
19372    pub fn expand_all_diff_hunks(
19373        &mut self,
19374        _: &ExpandAllDiffHunks,
19375        _window: &mut Window,
19376        cx: &mut Context<Self>,
19377    ) {
19378        self.buffer.update(cx, |buffer, cx| {
19379            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19380        });
19381    }
19382
19383    pub fn collapse_all_diff_hunks(
19384        &mut self,
19385        _: &CollapseAllDiffHunks,
19386        _window: &mut Window,
19387        cx: &mut Context<Self>,
19388    ) {
19389        self.buffer.update(cx, |buffer, cx| {
19390            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19391        });
19392    }
19393
19394    pub fn toggle_selected_diff_hunks(
19395        &mut self,
19396        _: &ToggleSelectedDiffHunks,
19397        _window: &mut Window,
19398        cx: &mut Context<Self>,
19399    ) {
19400        let ranges: Vec<_> = self
19401            .selections
19402            .disjoint_anchors()
19403            .iter()
19404            .map(|s| s.range())
19405            .collect();
19406        self.toggle_diff_hunks_in_ranges(ranges, cx);
19407    }
19408
19409    pub fn diff_hunks_in_ranges<'a>(
19410        &'a self,
19411        ranges: &'a [Range<Anchor>],
19412        buffer: &'a MultiBufferSnapshot,
19413    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19414        ranges.iter().flat_map(move |range| {
19415            let end_excerpt_id = range.end.excerpt_id;
19416            let range = range.to_point(buffer);
19417            let mut peek_end = range.end;
19418            if range.end.row < buffer.max_row().0 {
19419                peek_end = Point::new(range.end.row + 1, 0);
19420            }
19421            buffer
19422                .diff_hunks_in_range(range.start..peek_end)
19423                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19424        })
19425    }
19426
19427    pub fn has_stageable_diff_hunks_in_ranges(
19428        &self,
19429        ranges: &[Range<Anchor>],
19430        snapshot: &MultiBufferSnapshot,
19431    ) -> bool {
19432        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19433        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19434    }
19435
19436    pub fn toggle_staged_selected_diff_hunks(
19437        &mut self,
19438        _: &::git::ToggleStaged,
19439        _: &mut Window,
19440        cx: &mut Context<Self>,
19441    ) {
19442        let snapshot = self.buffer.read(cx).snapshot(cx);
19443        let ranges: Vec<_> = self
19444            .selections
19445            .disjoint_anchors()
19446            .iter()
19447            .map(|s| s.range())
19448            .collect();
19449        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19450        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19451    }
19452
19453    pub fn set_render_diff_hunk_controls(
19454        &mut self,
19455        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19456        cx: &mut Context<Self>,
19457    ) {
19458        self.render_diff_hunk_controls = render_diff_hunk_controls;
19459        cx.notify();
19460    }
19461
19462    pub fn stage_and_next(
19463        &mut self,
19464        _: &::git::StageAndNext,
19465        window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        self.do_stage_or_unstage_and_next(true, window, cx);
19469    }
19470
19471    pub fn unstage_and_next(
19472        &mut self,
19473        _: &::git::UnstageAndNext,
19474        window: &mut Window,
19475        cx: &mut Context<Self>,
19476    ) {
19477        self.do_stage_or_unstage_and_next(false, window, cx);
19478    }
19479
19480    pub fn stage_or_unstage_diff_hunks(
19481        &mut self,
19482        stage: bool,
19483        ranges: Vec<Range<Anchor>>,
19484        cx: &mut Context<Self>,
19485    ) {
19486        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19487        cx.spawn(async move |this, cx| {
19488            task.await?;
19489            this.update(cx, |this, cx| {
19490                let snapshot = this.buffer.read(cx).snapshot(cx);
19491                let chunk_by = this
19492                    .diff_hunks_in_ranges(&ranges, &snapshot)
19493                    .chunk_by(|hunk| hunk.buffer_id);
19494                for (buffer_id, hunks) in &chunk_by {
19495                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19496                }
19497            })
19498        })
19499        .detach_and_log_err(cx);
19500    }
19501
19502    fn save_buffers_for_ranges_if_needed(
19503        &mut self,
19504        ranges: &[Range<Anchor>],
19505        cx: &mut Context<Editor>,
19506    ) -> Task<Result<()>> {
19507        let multibuffer = self.buffer.read(cx);
19508        let snapshot = multibuffer.read(cx);
19509        let buffer_ids: HashSet<_> = ranges
19510            .iter()
19511            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19512            .collect();
19513        drop(snapshot);
19514
19515        let mut buffers = HashSet::default();
19516        for buffer_id in buffer_ids {
19517            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19518                let buffer = buffer_entity.read(cx);
19519                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19520                {
19521                    buffers.insert(buffer_entity);
19522                }
19523            }
19524        }
19525
19526        if let Some(project) = &self.project {
19527            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19528        } else {
19529            Task::ready(Ok(()))
19530        }
19531    }
19532
19533    fn do_stage_or_unstage_and_next(
19534        &mut self,
19535        stage: bool,
19536        window: &mut Window,
19537        cx: &mut Context<Self>,
19538    ) {
19539        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19540
19541        if ranges.iter().any(|range| range.start != range.end) {
19542            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19543            return;
19544        }
19545
19546        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19547        let snapshot = self.snapshot(window, cx);
19548        let position = self
19549            .selections
19550            .newest::<Point>(&snapshot.display_snapshot)
19551            .head();
19552        let mut row = snapshot
19553            .buffer_snapshot()
19554            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19555            .find(|hunk| hunk.row_range.start.0 > position.row)
19556            .map(|hunk| hunk.row_range.start);
19557
19558        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19559        // Outside of the project diff editor, wrap around to the beginning.
19560        if !all_diff_hunks_expanded {
19561            row = row.or_else(|| {
19562                snapshot
19563                    .buffer_snapshot()
19564                    .diff_hunks_in_range(Point::zero()..position)
19565                    .find(|hunk| hunk.row_range.end.0 < position.row)
19566                    .map(|hunk| hunk.row_range.start)
19567            });
19568        }
19569
19570        if let Some(row) = row {
19571            let destination = Point::new(row.0, 0);
19572            let autoscroll = Autoscroll::center();
19573
19574            self.unfold_ranges(&[destination..destination], false, false, cx);
19575            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19576                s.select_ranges([destination..destination]);
19577            });
19578        }
19579    }
19580
19581    fn do_stage_or_unstage(
19582        &self,
19583        stage: bool,
19584        buffer_id: BufferId,
19585        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19586        cx: &mut App,
19587    ) -> Option<()> {
19588        let project = self.project()?;
19589        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19590        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19591        let buffer_snapshot = buffer.read(cx).snapshot();
19592        let file_exists = buffer_snapshot
19593            .file()
19594            .is_some_and(|file| file.disk_state().exists());
19595        diff.update(cx, |diff, cx| {
19596            diff.stage_or_unstage_hunks(
19597                stage,
19598                &hunks
19599                    .map(|hunk| buffer_diff::DiffHunk {
19600                        buffer_range: hunk.buffer_range,
19601                        // We don't need to pass in word diffs here because they're only used for rendering and
19602                        // this function changes internal state
19603                        base_word_diffs: Vec::default(),
19604                        buffer_word_diffs: Vec::default(),
19605                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19606                            ..hunk.diff_base_byte_range.end.0,
19607                        secondary_status: hunk.secondary_status,
19608                        range: Point::zero()..Point::zero(), // unused
19609                    })
19610                    .collect::<Vec<_>>(),
19611                &buffer_snapshot,
19612                file_exists,
19613                cx,
19614            )
19615        });
19616        None
19617    }
19618
19619    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19620        let ranges: Vec<_> = self
19621            .selections
19622            .disjoint_anchors()
19623            .iter()
19624            .map(|s| s.range())
19625            .collect();
19626        self.buffer
19627            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19628    }
19629
19630    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19631        self.buffer.update(cx, |buffer, cx| {
19632            let ranges = vec![Anchor::min()..Anchor::max()];
19633            if !buffer.all_diff_hunks_expanded()
19634                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19635            {
19636                buffer.collapse_diff_hunks(ranges, cx);
19637                true
19638            } else {
19639                false
19640            }
19641        })
19642    }
19643
19644    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19645        if self.buffer.read(cx).all_diff_hunks_expanded() {
19646            return true;
19647        }
19648        let ranges = vec![Anchor::min()..Anchor::max()];
19649        self.buffer
19650            .read(cx)
19651            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19652    }
19653
19654    fn toggle_diff_hunks_in_ranges(
19655        &mut self,
19656        ranges: Vec<Range<Anchor>>,
19657        cx: &mut Context<Editor>,
19658    ) {
19659        self.buffer.update(cx, |buffer, cx| {
19660            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19661            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19662        })
19663    }
19664
19665    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19666        self.buffer.update(cx, |buffer, cx| {
19667            let snapshot = buffer.snapshot(cx);
19668            let excerpt_id = range.end.excerpt_id;
19669            let point_range = range.to_point(&snapshot);
19670            let expand = !buffer.single_hunk_is_expanded(range, cx);
19671            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19672        })
19673    }
19674
19675    pub(crate) fn apply_all_diff_hunks(
19676        &mut self,
19677        _: &ApplyAllDiffHunks,
19678        window: &mut Window,
19679        cx: &mut Context<Self>,
19680    ) {
19681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19682
19683        let buffers = self.buffer.read(cx).all_buffers();
19684        for branch_buffer in buffers {
19685            branch_buffer.update(cx, |branch_buffer, cx| {
19686                branch_buffer.merge_into_base(Vec::new(), cx);
19687            });
19688        }
19689
19690        if let Some(project) = self.project.clone() {
19691            self.save(
19692                SaveOptions {
19693                    format: true,
19694                    autosave: false,
19695                },
19696                project,
19697                window,
19698                cx,
19699            )
19700            .detach_and_log_err(cx);
19701        }
19702    }
19703
19704    pub(crate) fn apply_selected_diff_hunks(
19705        &mut self,
19706        _: &ApplyDiffHunk,
19707        window: &mut Window,
19708        cx: &mut Context<Self>,
19709    ) {
19710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19711        let snapshot = self.snapshot(window, cx);
19712        let hunks = snapshot.hunks_for_ranges(
19713            self.selections
19714                .all(&snapshot.display_snapshot)
19715                .into_iter()
19716                .map(|selection| selection.range()),
19717        );
19718        let mut ranges_by_buffer = HashMap::default();
19719        self.transact(window, cx, |editor, _window, cx| {
19720            for hunk in hunks {
19721                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19722                    ranges_by_buffer
19723                        .entry(buffer.clone())
19724                        .or_insert_with(Vec::new)
19725                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19726                }
19727            }
19728
19729            for (buffer, ranges) in ranges_by_buffer {
19730                buffer.update(cx, |buffer, cx| {
19731                    buffer.merge_into_base(ranges, cx);
19732                });
19733            }
19734        });
19735
19736        if let Some(project) = self.project.clone() {
19737            self.save(
19738                SaveOptions {
19739                    format: true,
19740                    autosave: false,
19741                },
19742                project,
19743                window,
19744                cx,
19745            )
19746            .detach_and_log_err(cx);
19747        }
19748    }
19749
19750    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19751        if hovered != self.gutter_hovered {
19752            self.gutter_hovered = hovered;
19753            cx.notify();
19754        }
19755    }
19756
19757    pub fn insert_blocks(
19758        &mut self,
19759        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19760        autoscroll: Option<Autoscroll>,
19761        cx: &mut Context<Self>,
19762    ) -> Vec<CustomBlockId> {
19763        let blocks = self
19764            .display_map
19765            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19766        if let Some(autoscroll) = autoscroll {
19767            self.request_autoscroll(autoscroll, cx);
19768        }
19769        cx.notify();
19770        blocks
19771    }
19772
19773    pub fn resize_blocks(
19774        &mut self,
19775        heights: HashMap<CustomBlockId, u32>,
19776        autoscroll: Option<Autoscroll>,
19777        cx: &mut Context<Self>,
19778    ) {
19779        self.display_map
19780            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19781        if let Some(autoscroll) = autoscroll {
19782            self.request_autoscroll(autoscroll, cx);
19783        }
19784        cx.notify();
19785    }
19786
19787    pub fn replace_blocks(
19788        &mut self,
19789        renderers: HashMap<CustomBlockId, RenderBlock>,
19790        autoscroll: Option<Autoscroll>,
19791        cx: &mut Context<Self>,
19792    ) {
19793        self.display_map
19794            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19795        if let Some(autoscroll) = autoscroll {
19796            self.request_autoscroll(autoscroll, cx);
19797        }
19798        cx.notify();
19799    }
19800
19801    pub fn remove_blocks(
19802        &mut self,
19803        block_ids: HashSet<CustomBlockId>,
19804        autoscroll: Option<Autoscroll>,
19805        cx: &mut Context<Self>,
19806    ) {
19807        self.display_map.update(cx, |display_map, cx| {
19808            display_map.remove_blocks(block_ids, cx)
19809        });
19810        if let Some(autoscroll) = autoscroll {
19811            self.request_autoscroll(autoscroll, cx);
19812        }
19813        cx.notify();
19814    }
19815
19816    pub fn row_for_block(
19817        &self,
19818        block_id: CustomBlockId,
19819        cx: &mut Context<Self>,
19820    ) -> Option<DisplayRow> {
19821        self.display_map
19822            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19823    }
19824
19825    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19826        self.focused_block = Some(focused_block);
19827    }
19828
19829    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19830        self.focused_block.take()
19831    }
19832
19833    pub fn insert_creases(
19834        &mut self,
19835        creases: impl IntoIterator<Item = Crease<Anchor>>,
19836        cx: &mut Context<Self>,
19837    ) -> Vec<CreaseId> {
19838        self.display_map
19839            .update(cx, |map, cx| map.insert_creases(creases, cx))
19840    }
19841
19842    pub fn remove_creases(
19843        &mut self,
19844        ids: impl IntoIterator<Item = CreaseId>,
19845        cx: &mut Context<Self>,
19846    ) -> Vec<(CreaseId, Range<Anchor>)> {
19847        self.display_map
19848            .update(cx, |map, cx| map.remove_creases(ids, cx))
19849    }
19850
19851    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19852        self.display_map
19853            .update(cx, |map, cx| map.snapshot(cx))
19854            .longest_row()
19855    }
19856
19857    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19858        self.display_map
19859            .update(cx, |map, cx| map.snapshot(cx))
19860            .max_point()
19861    }
19862
19863    pub fn text(&self, cx: &App) -> String {
19864        self.buffer.read(cx).read(cx).text()
19865    }
19866
19867    pub fn is_empty(&self, cx: &App) -> bool {
19868        self.buffer.read(cx).read(cx).is_empty()
19869    }
19870
19871    pub fn text_option(&self, cx: &App) -> Option<String> {
19872        let text = self.text(cx);
19873        let text = text.trim();
19874
19875        if text.is_empty() {
19876            return None;
19877        }
19878
19879        Some(text.to_string())
19880    }
19881
19882    pub fn set_text(
19883        &mut self,
19884        text: impl Into<Arc<str>>,
19885        window: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) {
19888        self.transact(window, cx, |this, _, cx| {
19889            this.buffer
19890                .read(cx)
19891                .as_singleton()
19892                .expect("you can only call set_text on editors for singleton buffers")
19893                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19894        });
19895    }
19896
19897    pub fn display_text(&self, cx: &mut App) -> String {
19898        self.display_map
19899            .update(cx, |map, cx| map.snapshot(cx))
19900            .text()
19901    }
19902
19903    fn create_minimap(
19904        &self,
19905        minimap_settings: MinimapSettings,
19906        window: &mut Window,
19907        cx: &mut Context<Self>,
19908    ) -> Option<Entity<Self>> {
19909        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19910            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19911    }
19912
19913    fn initialize_new_minimap(
19914        &self,
19915        minimap_settings: MinimapSettings,
19916        window: &mut Window,
19917        cx: &mut Context<Self>,
19918    ) -> Entity<Self> {
19919        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19920
19921        let mut minimap = Editor::new_internal(
19922            EditorMode::Minimap {
19923                parent: cx.weak_entity(),
19924            },
19925            self.buffer.clone(),
19926            None,
19927            Some(self.display_map.clone()),
19928            window,
19929            cx,
19930        );
19931        minimap.scroll_manager.clone_state(&self.scroll_manager);
19932        minimap.set_text_style_refinement(TextStyleRefinement {
19933            font_size: Some(MINIMAP_FONT_SIZE),
19934            font_weight: Some(MINIMAP_FONT_WEIGHT),
19935            ..Default::default()
19936        });
19937        minimap.update_minimap_configuration(minimap_settings, cx);
19938        cx.new(|_| minimap)
19939    }
19940
19941    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19942        let current_line_highlight = minimap_settings
19943            .current_line_highlight
19944            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19945        self.set_current_line_highlight(Some(current_line_highlight));
19946    }
19947
19948    pub fn minimap(&self) -> Option<&Entity<Self>> {
19949        self.minimap
19950            .as_ref()
19951            .filter(|_| self.minimap_visibility.visible())
19952    }
19953
19954    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19955        let mut wrap_guides = smallvec![];
19956
19957        if self.show_wrap_guides == Some(false) {
19958            return wrap_guides;
19959        }
19960
19961        let settings = self.buffer.read(cx).language_settings(cx);
19962        if settings.show_wrap_guides {
19963            match self.soft_wrap_mode(cx) {
19964                SoftWrap::Column(soft_wrap) => {
19965                    wrap_guides.push((soft_wrap as usize, true));
19966                }
19967                SoftWrap::Bounded(soft_wrap) => {
19968                    wrap_guides.push((soft_wrap as usize, true));
19969                }
19970                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19971            }
19972            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19973        }
19974
19975        wrap_guides
19976    }
19977
19978    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19979        let settings = self.buffer.read(cx).language_settings(cx);
19980        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19981        match mode {
19982            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19983                SoftWrap::None
19984            }
19985            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19986            language_settings::SoftWrap::PreferredLineLength => {
19987                SoftWrap::Column(settings.preferred_line_length)
19988            }
19989            language_settings::SoftWrap::Bounded => {
19990                SoftWrap::Bounded(settings.preferred_line_length)
19991            }
19992        }
19993    }
19994
19995    pub fn set_soft_wrap_mode(
19996        &mut self,
19997        mode: language_settings::SoftWrap,
19998
19999        cx: &mut Context<Self>,
20000    ) {
20001        self.soft_wrap_mode_override = Some(mode);
20002        cx.notify();
20003    }
20004
20005    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20006        self.hard_wrap = hard_wrap;
20007        cx.notify();
20008    }
20009
20010    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20011        self.text_style_refinement = Some(style);
20012    }
20013
20014    /// called by the Element so we know what style we were most recently rendered with.
20015    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20016        // We intentionally do not inform the display map about the minimap style
20017        // so that wrapping is not recalculated and stays consistent for the editor
20018        // and its linked minimap.
20019        if !self.mode.is_minimap() {
20020            let font = style.text.font();
20021            let font_size = style.text.font_size.to_pixels(window.rem_size());
20022            let display_map = self
20023                .placeholder_display_map
20024                .as_ref()
20025                .filter(|_| self.is_empty(cx))
20026                .unwrap_or(&self.display_map);
20027
20028            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20029        }
20030        self.style = Some(style);
20031    }
20032
20033    pub fn style(&self) -> Option<&EditorStyle> {
20034        self.style.as_ref()
20035    }
20036
20037    // Called by the element. This method is not designed to be called outside of the editor
20038    // element's layout code because it does not notify when rewrapping is computed synchronously.
20039    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20040        if self.is_empty(cx) {
20041            self.placeholder_display_map
20042                .as_ref()
20043                .map_or(false, |display_map| {
20044                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20045                })
20046        } else {
20047            self.display_map
20048                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20049        }
20050    }
20051
20052    pub fn set_soft_wrap(&mut self) {
20053        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20054    }
20055
20056    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20057        if self.soft_wrap_mode_override.is_some() {
20058            self.soft_wrap_mode_override.take();
20059        } else {
20060            let soft_wrap = match self.soft_wrap_mode(cx) {
20061                SoftWrap::GitDiff => return,
20062                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20063                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20064                    language_settings::SoftWrap::None
20065                }
20066            };
20067            self.soft_wrap_mode_override = Some(soft_wrap);
20068        }
20069        cx.notify();
20070    }
20071
20072    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20073        let Some(workspace) = self.workspace() else {
20074            return;
20075        };
20076        let fs = workspace.read(cx).app_state().fs.clone();
20077        let current_show = TabBarSettings::get_global(cx).show;
20078        update_settings_file(fs, cx, move |setting, _| {
20079            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20080        });
20081    }
20082
20083    pub fn toggle_indent_guides(
20084        &mut self,
20085        _: &ToggleIndentGuides,
20086        _: &mut Window,
20087        cx: &mut Context<Self>,
20088    ) {
20089        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20090            self.buffer
20091                .read(cx)
20092                .language_settings(cx)
20093                .indent_guides
20094                .enabled
20095        });
20096        self.show_indent_guides = Some(!currently_enabled);
20097        cx.notify();
20098    }
20099
20100    fn should_show_indent_guides(&self) -> Option<bool> {
20101        self.show_indent_guides
20102    }
20103
20104    pub fn disable_indent_guides_for_buffer(
20105        &mut self,
20106        buffer_id: BufferId,
20107        cx: &mut Context<Self>,
20108    ) {
20109        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20110        cx.notify();
20111    }
20112
20113    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20114        self.buffers_with_disabled_indent_guides
20115            .contains(&buffer_id)
20116    }
20117
20118    pub fn toggle_line_numbers(
20119        &mut self,
20120        _: &ToggleLineNumbers,
20121        _: &mut Window,
20122        cx: &mut Context<Self>,
20123    ) {
20124        let mut editor_settings = EditorSettings::get_global(cx).clone();
20125        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20126        EditorSettings::override_global(editor_settings, cx);
20127    }
20128
20129    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20130        if let Some(show_line_numbers) = self.show_line_numbers {
20131            return show_line_numbers;
20132        }
20133        EditorSettings::get_global(cx).gutter.line_numbers
20134    }
20135
20136    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20137        match (
20138            self.use_relative_line_numbers,
20139            EditorSettings::get_global(cx).relative_line_numbers,
20140        ) {
20141            (None, setting) => setting,
20142            (Some(false), _) => RelativeLineNumbers::Disabled,
20143            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20144            (Some(true), _) => RelativeLineNumbers::Enabled,
20145        }
20146    }
20147
20148    pub fn toggle_relative_line_numbers(
20149        &mut self,
20150        _: &ToggleRelativeLineNumbers,
20151        _: &mut Window,
20152        cx: &mut Context<Self>,
20153    ) {
20154        let is_relative = self.relative_line_numbers(cx);
20155        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20156    }
20157
20158    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20159        self.use_relative_line_numbers = is_relative;
20160        cx.notify();
20161    }
20162
20163    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20164        self.show_gutter = show_gutter;
20165        cx.notify();
20166    }
20167
20168    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20169        self.show_scrollbars = ScrollbarAxes {
20170            horizontal: show,
20171            vertical: show,
20172        };
20173        cx.notify();
20174    }
20175
20176    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20177        self.show_scrollbars.vertical = show;
20178        cx.notify();
20179    }
20180
20181    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20182        self.show_scrollbars.horizontal = show;
20183        cx.notify();
20184    }
20185
20186    pub fn set_minimap_visibility(
20187        &mut self,
20188        minimap_visibility: MinimapVisibility,
20189        window: &mut Window,
20190        cx: &mut Context<Self>,
20191    ) {
20192        if self.minimap_visibility != minimap_visibility {
20193            if minimap_visibility.visible() && self.minimap.is_none() {
20194                let minimap_settings = EditorSettings::get_global(cx).minimap;
20195                self.minimap =
20196                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20197            }
20198            self.minimap_visibility = minimap_visibility;
20199            cx.notify();
20200        }
20201    }
20202
20203    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20204        self.set_show_scrollbars(false, cx);
20205        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20206    }
20207
20208    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20209        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20210    }
20211
20212    /// Normally the text in full mode and auto height editors is padded on the
20213    /// left side by roughly half a character width for improved hit testing.
20214    ///
20215    /// Use this method to disable this for cases where this is not wanted (e.g.
20216    /// if you want to align the editor text with some other text above or below)
20217    /// or if you want to add this padding to single-line editors.
20218    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20219        self.offset_content = offset_content;
20220        cx.notify();
20221    }
20222
20223    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20224        self.show_line_numbers = Some(show_line_numbers);
20225        cx.notify();
20226    }
20227
20228    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20229        self.disable_expand_excerpt_buttons = true;
20230        cx.notify();
20231    }
20232
20233    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20234        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20235        cx.notify();
20236    }
20237
20238    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20239        self.show_code_actions = Some(show_code_actions);
20240        cx.notify();
20241    }
20242
20243    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20244        self.show_runnables = Some(show_runnables);
20245        cx.notify();
20246    }
20247
20248    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20249        self.show_breakpoints = Some(show_breakpoints);
20250        cx.notify();
20251    }
20252
20253    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20254        if self.display_map.read(cx).masked != masked {
20255            self.display_map.update(cx, |map, _| map.masked = masked);
20256        }
20257        cx.notify()
20258    }
20259
20260    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20261        self.show_wrap_guides = Some(show_wrap_guides);
20262        cx.notify();
20263    }
20264
20265    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20266        self.show_indent_guides = Some(show_indent_guides);
20267        cx.notify();
20268    }
20269
20270    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20271        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20272            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20273                && let Some(dir) = file.abs_path(cx).parent()
20274            {
20275                return Some(dir.to_owned());
20276            }
20277        }
20278
20279        None
20280    }
20281
20282    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20283        self.active_excerpt(cx)?
20284            .1
20285            .read(cx)
20286            .file()
20287            .and_then(|f| f.as_local())
20288    }
20289
20290    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20291        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20292            let buffer = buffer.read(cx);
20293            if let Some(project_path) = buffer.project_path(cx) {
20294                let project = self.project()?.read(cx);
20295                project.absolute_path(&project_path, cx)
20296            } else {
20297                buffer
20298                    .file()
20299                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20300            }
20301        })
20302    }
20303
20304    pub fn reveal_in_finder(
20305        &mut self,
20306        _: &RevealInFileManager,
20307        _window: &mut Window,
20308        cx: &mut Context<Self>,
20309    ) {
20310        if let Some(target) = self.target_file(cx) {
20311            cx.reveal_path(&target.abs_path(cx));
20312        }
20313    }
20314
20315    pub fn copy_path(
20316        &mut self,
20317        _: &zed_actions::workspace::CopyPath,
20318        _window: &mut Window,
20319        cx: &mut Context<Self>,
20320    ) {
20321        if let Some(path) = self.target_file_abs_path(cx)
20322            && let Some(path) = path.to_str()
20323        {
20324            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20325        } else {
20326            cx.propagate();
20327        }
20328    }
20329
20330    pub fn copy_relative_path(
20331        &mut self,
20332        _: &zed_actions::workspace::CopyRelativePath,
20333        _window: &mut Window,
20334        cx: &mut Context<Self>,
20335    ) {
20336        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20337            let project = self.project()?.read(cx);
20338            let path = buffer.read(cx).file()?.path();
20339            let path = path.display(project.path_style(cx));
20340            Some(path)
20341        }) {
20342            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20343        } else {
20344            cx.propagate();
20345        }
20346    }
20347
20348    /// Returns the project path for the editor's buffer, if any buffer is
20349    /// opened in the editor.
20350    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20351        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20352            buffer.read(cx).project_path(cx)
20353        } else {
20354            None
20355        }
20356    }
20357
20358    // Returns true if the editor handled a go-to-line request
20359    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20360        maybe!({
20361            let breakpoint_store = self.breakpoint_store.as_ref()?;
20362
20363            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20364            else {
20365                self.clear_row_highlights::<ActiveDebugLine>();
20366                return None;
20367            };
20368
20369            let position = active_stack_frame.position;
20370            let buffer_id = position.buffer_id?;
20371            let snapshot = self
20372                .project
20373                .as_ref()?
20374                .read(cx)
20375                .buffer_for_id(buffer_id, cx)?
20376                .read(cx)
20377                .snapshot();
20378
20379            let mut handled = false;
20380            for (id, ExcerptRange { context, .. }) in
20381                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20382            {
20383                if context.start.cmp(&position, &snapshot).is_ge()
20384                    || context.end.cmp(&position, &snapshot).is_lt()
20385                {
20386                    continue;
20387                }
20388                let snapshot = self.buffer.read(cx).snapshot(cx);
20389                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20390
20391                handled = true;
20392                self.clear_row_highlights::<ActiveDebugLine>();
20393
20394                self.go_to_line::<ActiveDebugLine>(
20395                    multibuffer_anchor,
20396                    Some(cx.theme().colors().editor_debugger_active_line_background),
20397                    window,
20398                    cx,
20399                );
20400
20401                cx.notify();
20402            }
20403
20404            handled.then_some(())
20405        })
20406        .is_some()
20407    }
20408
20409    pub fn copy_file_name_without_extension(
20410        &mut self,
20411        _: &CopyFileNameWithoutExtension,
20412        _: &mut Window,
20413        cx: &mut Context<Self>,
20414    ) {
20415        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20416            let file = buffer.read(cx).file()?;
20417            file.path().file_stem()
20418        }) {
20419            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20420        }
20421    }
20422
20423    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20424        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20425            let file = buffer.read(cx).file()?;
20426            Some(file.file_name(cx))
20427        }) {
20428            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20429        }
20430    }
20431
20432    pub fn toggle_git_blame(
20433        &mut self,
20434        _: &::git::Blame,
20435        window: &mut Window,
20436        cx: &mut Context<Self>,
20437    ) {
20438        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20439
20440        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20441            self.start_git_blame(true, window, cx);
20442        }
20443
20444        cx.notify();
20445    }
20446
20447    pub fn toggle_git_blame_inline(
20448        &mut self,
20449        _: &ToggleGitBlameInline,
20450        window: &mut Window,
20451        cx: &mut Context<Self>,
20452    ) {
20453        self.toggle_git_blame_inline_internal(true, window, cx);
20454        cx.notify();
20455    }
20456
20457    pub fn open_git_blame_commit(
20458        &mut self,
20459        _: &OpenGitBlameCommit,
20460        window: &mut Window,
20461        cx: &mut Context<Self>,
20462    ) {
20463        self.open_git_blame_commit_internal(window, cx);
20464    }
20465
20466    fn open_git_blame_commit_internal(
20467        &mut self,
20468        window: &mut Window,
20469        cx: &mut Context<Self>,
20470    ) -> Option<()> {
20471        let blame = self.blame.as_ref()?;
20472        let snapshot = self.snapshot(window, cx);
20473        let cursor = self
20474            .selections
20475            .newest::<Point>(&snapshot.display_snapshot)
20476            .head();
20477        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20478        let (_, blame_entry) = blame
20479            .update(cx, |blame, cx| {
20480                blame
20481                    .blame_for_rows(
20482                        &[RowInfo {
20483                            buffer_id: Some(buffer.remote_id()),
20484                            buffer_row: Some(point.row),
20485                            ..Default::default()
20486                        }],
20487                        cx,
20488                    )
20489                    .next()
20490            })
20491            .flatten()?;
20492        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20493        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20494        let workspace = self.workspace()?.downgrade();
20495        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20496        None
20497    }
20498
20499    pub fn git_blame_inline_enabled(&self) -> bool {
20500        self.git_blame_inline_enabled
20501    }
20502
20503    pub fn toggle_selection_menu(
20504        &mut self,
20505        _: &ToggleSelectionMenu,
20506        _: &mut Window,
20507        cx: &mut Context<Self>,
20508    ) {
20509        self.show_selection_menu = self
20510            .show_selection_menu
20511            .map(|show_selections_menu| !show_selections_menu)
20512            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20513
20514        cx.notify();
20515    }
20516
20517    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20518        self.show_selection_menu
20519            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20520    }
20521
20522    fn start_git_blame(
20523        &mut self,
20524        user_triggered: bool,
20525        window: &mut Window,
20526        cx: &mut Context<Self>,
20527    ) {
20528        if let Some(project) = self.project() {
20529            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20530                && buffer.read(cx).file().is_none()
20531            {
20532                return;
20533            }
20534
20535            let focused = self.focus_handle(cx).contains_focused(window, cx);
20536
20537            let project = project.clone();
20538            let blame = cx
20539                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20540            self.blame_subscription =
20541                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20542            self.blame = Some(blame);
20543        }
20544    }
20545
20546    fn toggle_git_blame_inline_internal(
20547        &mut self,
20548        user_triggered: bool,
20549        window: &mut Window,
20550        cx: &mut Context<Self>,
20551    ) {
20552        if self.git_blame_inline_enabled {
20553            self.git_blame_inline_enabled = false;
20554            self.show_git_blame_inline = false;
20555            self.show_git_blame_inline_delay_task.take();
20556        } else {
20557            self.git_blame_inline_enabled = true;
20558            self.start_git_blame_inline(user_triggered, window, cx);
20559        }
20560
20561        cx.notify();
20562    }
20563
20564    fn start_git_blame_inline(
20565        &mut self,
20566        user_triggered: bool,
20567        window: &mut Window,
20568        cx: &mut Context<Self>,
20569    ) {
20570        self.start_git_blame(user_triggered, window, cx);
20571
20572        if ProjectSettings::get_global(cx)
20573            .git
20574            .inline_blame_delay()
20575            .is_some()
20576        {
20577            self.start_inline_blame_timer(window, cx);
20578        } else {
20579            self.show_git_blame_inline = true
20580        }
20581    }
20582
20583    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20584        self.blame.as_ref()
20585    }
20586
20587    pub fn show_git_blame_gutter(&self) -> bool {
20588        self.show_git_blame_gutter
20589    }
20590
20591    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20592        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20593    }
20594
20595    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20596        self.show_git_blame_inline
20597            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20598            && !self.newest_selection_head_on_empty_line(cx)
20599            && self.has_blame_entries(cx)
20600    }
20601
20602    fn has_blame_entries(&self, cx: &App) -> bool {
20603        self.blame()
20604            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20605    }
20606
20607    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20608        let cursor_anchor = self.selections.newest_anchor().head();
20609
20610        let snapshot = self.buffer.read(cx).snapshot(cx);
20611        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20612
20613        snapshot.line_len(buffer_row) == 0
20614    }
20615
20616    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20617        let buffer_and_selection = maybe!({
20618            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20619            let selection_range = selection.range();
20620
20621            let multi_buffer = self.buffer().read(cx);
20622            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20623            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20624
20625            let (buffer, range, _) = if selection.reversed {
20626                buffer_ranges.first()
20627            } else {
20628                buffer_ranges.last()
20629            }?;
20630
20631            let selection = text::ToPoint::to_point(&range.start, buffer).row
20632                ..text::ToPoint::to_point(&range.end, buffer).row;
20633            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20634        });
20635
20636        let Some((buffer, selection)) = buffer_and_selection else {
20637            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20638        };
20639
20640        let Some(project) = self.project() else {
20641            return Task::ready(Err(anyhow!("editor does not have project")));
20642        };
20643
20644        project.update(cx, |project, cx| {
20645            project.get_permalink_to_line(&buffer, selection, cx)
20646        })
20647    }
20648
20649    pub fn copy_permalink_to_line(
20650        &mut self,
20651        _: &CopyPermalinkToLine,
20652        window: &mut Window,
20653        cx: &mut Context<Self>,
20654    ) {
20655        let permalink_task = self.get_permalink_to_line(cx);
20656        let workspace = self.workspace();
20657
20658        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20659            Ok(permalink) => {
20660                cx.update(|_, cx| {
20661                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20662                })
20663                .ok();
20664            }
20665            Err(err) => {
20666                let message = format!("Failed to copy permalink: {err}");
20667
20668                anyhow::Result::<()>::Err(err).log_err();
20669
20670                if let Some(workspace) = workspace {
20671                    workspace
20672                        .update_in(cx, |workspace, _, cx| {
20673                            struct CopyPermalinkToLine;
20674
20675                            workspace.show_toast(
20676                                Toast::new(
20677                                    NotificationId::unique::<CopyPermalinkToLine>(),
20678                                    message,
20679                                ),
20680                                cx,
20681                            )
20682                        })
20683                        .ok();
20684                }
20685            }
20686        })
20687        .detach();
20688    }
20689
20690    pub fn copy_file_location(
20691        &mut self,
20692        _: &CopyFileLocation,
20693        _: &mut Window,
20694        cx: &mut Context<Self>,
20695    ) {
20696        let selection = self
20697            .selections
20698            .newest::<Point>(&self.display_snapshot(cx))
20699            .start
20700            .row
20701            + 1;
20702        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20703            let project = self.project()?.read(cx);
20704            let file = buffer.read(cx).file()?;
20705            let path = file.path().display(project.path_style(cx));
20706
20707            Some(format!("{path}:{selection}"))
20708        }) {
20709            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20710        }
20711    }
20712
20713    pub fn open_permalink_to_line(
20714        &mut self,
20715        _: &OpenPermalinkToLine,
20716        window: &mut Window,
20717        cx: &mut Context<Self>,
20718    ) {
20719        let permalink_task = self.get_permalink_to_line(cx);
20720        let workspace = self.workspace();
20721
20722        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20723            Ok(permalink) => {
20724                cx.update(|_, cx| {
20725                    cx.open_url(permalink.as_ref());
20726                })
20727                .ok();
20728            }
20729            Err(err) => {
20730                let message = format!("Failed to open permalink: {err}");
20731
20732                anyhow::Result::<()>::Err(err).log_err();
20733
20734                if let Some(workspace) = workspace {
20735                    workspace
20736                        .update(cx, |workspace, cx| {
20737                            struct OpenPermalinkToLine;
20738
20739                            workspace.show_toast(
20740                                Toast::new(
20741                                    NotificationId::unique::<OpenPermalinkToLine>(),
20742                                    message,
20743                                ),
20744                                cx,
20745                            )
20746                        })
20747                        .ok();
20748                }
20749            }
20750        })
20751        .detach();
20752    }
20753
20754    pub fn insert_uuid_v4(
20755        &mut self,
20756        _: &InsertUuidV4,
20757        window: &mut Window,
20758        cx: &mut Context<Self>,
20759    ) {
20760        self.insert_uuid(UuidVersion::V4, window, cx);
20761    }
20762
20763    pub fn insert_uuid_v7(
20764        &mut self,
20765        _: &InsertUuidV7,
20766        window: &mut Window,
20767        cx: &mut Context<Self>,
20768    ) {
20769        self.insert_uuid(UuidVersion::V7, window, cx);
20770    }
20771
20772    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20774        self.transact(window, cx, |this, window, cx| {
20775            let edits = this
20776                .selections
20777                .all::<Point>(&this.display_snapshot(cx))
20778                .into_iter()
20779                .map(|selection| {
20780                    let uuid = match version {
20781                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20782                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20783                    };
20784
20785                    (selection.range(), uuid.to_string())
20786                });
20787            this.edit(edits, cx);
20788            this.refresh_edit_prediction(true, false, window, cx);
20789        });
20790    }
20791
20792    pub fn open_selections_in_multibuffer(
20793        &mut self,
20794        _: &OpenSelectionsInMultibuffer,
20795        window: &mut Window,
20796        cx: &mut Context<Self>,
20797    ) {
20798        let multibuffer = self.buffer.read(cx);
20799
20800        let Some(buffer) = multibuffer.as_singleton() else {
20801            return;
20802        };
20803
20804        let Some(workspace) = self.workspace() else {
20805            return;
20806        };
20807
20808        let title = multibuffer.title(cx).to_string();
20809
20810        let locations = self
20811            .selections
20812            .all_anchors(&self.display_snapshot(cx))
20813            .iter()
20814            .map(|selection| {
20815                (
20816                    buffer.clone(),
20817                    (selection.start.text_anchor..selection.end.text_anchor)
20818                        .to_point(buffer.read(cx)),
20819                )
20820            })
20821            .into_group_map();
20822
20823        cx.spawn_in(window, async move |_, cx| {
20824            workspace.update_in(cx, |workspace, window, cx| {
20825                Self::open_locations_in_multibuffer(
20826                    workspace,
20827                    locations,
20828                    format!("Selections for '{title}'"),
20829                    false,
20830                    false,
20831                    MultibufferSelectionMode::All,
20832                    window,
20833                    cx,
20834                );
20835            })
20836        })
20837        .detach();
20838    }
20839
20840    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20841    /// last highlight added will be used.
20842    ///
20843    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20844    pub fn highlight_rows<T: 'static>(
20845        &mut self,
20846        range: Range<Anchor>,
20847        color: Hsla,
20848        options: RowHighlightOptions,
20849        cx: &mut Context<Self>,
20850    ) {
20851        let snapshot = self.buffer().read(cx).snapshot(cx);
20852        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20853        let ix = row_highlights.binary_search_by(|highlight| {
20854            Ordering::Equal
20855                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20856                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20857        });
20858
20859        if let Err(mut ix) = ix {
20860            let index = post_inc(&mut self.highlight_order);
20861
20862            // If this range intersects with the preceding highlight, then merge it with
20863            // the preceding highlight. Otherwise insert a new highlight.
20864            let mut merged = false;
20865            if ix > 0 {
20866                let prev_highlight = &mut row_highlights[ix - 1];
20867                if prev_highlight
20868                    .range
20869                    .end
20870                    .cmp(&range.start, &snapshot)
20871                    .is_ge()
20872                {
20873                    ix -= 1;
20874                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20875                        prev_highlight.range.end = range.end;
20876                    }
20877                    merged = true;
20878                    prev_highlight.index = index;
20879                    prev_highlight.color = color;
20880                    prev_highlight.options = options;
20881                }
20882            }
20883
20884            if !merged {
20885                row_highlights.insert(
20886                    ix,
20887                    RowHighlight {
20888                        range,
20889                        index,
20890                        color,
20891                        options,
20892                        type_id: TypeId::of::<T>(),
20893                    },
20894                );
20895            }
20896
20897            // If any of the following highlights intersect with this one, merge them.
20898            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20899                let highlight = &row_highlights[ix];
20900                if next_highlight
20901                    .range
20902                    .start
20903                    .cmp(&highlight.range.end, &snapshot)
20904                    .is_le()
20905                {
20906                    if next_highlight
20907                        .range
20908                        .end
20909                        .cmp(&highlight.range.end, &snapshot)
20910                        .is_gt()
20911                    {
20912                        row_highlights[ix].range.end = next_highlight.range.end;
20913                    }
20914                    row_highlights.remove(ix + 1);
20915                } else {
20916                    break;
20917                }
20918            }
20919        }
20920    }
20921
20922    /// Remove any highlighted row ranges of the given type that intersect the
20923    /// given ranges.
20924    pub fn remove_highlighted_rows<T: 'static>(
20925        &mut self,
20926        ranges_to_remove: Vec<Range<Anchor>>,
20927        cx: &mut Context<Self>,
20928    ) {
20929        let snapshot = self.buffer().read(cx).snapshot(cx);
20930        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20931        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20932        row_highlights.retain(|highlight| {
20933            while let Some(range_to_remove) = ranges_to_remove.peek() {
20934                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20935                    Ordering::Less | Ordering::Equal => {
20936                        ranges_to_remove.next();
20937                    }
20938                    Ordering::Greater => {
20939                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20940                            Ordering::Less | Ordering::Equal => {
20941                                return false;
20942                            }
20943                            Ordering::Greater => break,
20944                        }
20945                    }
20946                }
20947            }
20948
20949            true
20950        })
20951    }
20952
20953    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20954    pub fn clear_row_highlights<T: 'static>(&mut self) {
20955        self.highlighted_rows.remove(&TypeId::of::<T>());
20956    }
20957
20958    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20959    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20960        self.highlighted_rows
20961            .get(&TypeId::of::<T>())
20962            .map_or(&[] as &[_], |vec| vec.as_slice())
20963            .iter()
20964            .map(|highlight| (highlight.range.clone(), highlight.color))
20965    }
20966
20967    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20968    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20969    /// Allows to ignore certain kinds of highlights.
20970    pub fn highlighted_display_rows(
20971        &self,
20972        window: &mut Window,
20973        cx: &mut App,
20974    ) -> BTreeMap<DisplayRow, LineHighlight> {
20975        let snapshot = self.snapshot(window, cx);
20976        let mut used_highlight_orders = HashMap::default();
20977        self.highlighted_rows
20978            .iter()
20979            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20980            .fold(
20981                BTreeMap::<DisplayRow, LineHighlight>::new(),
20982                |mut unique_rows, highlight| {
20983                    let start = highlight.range.start.to_display_point(&snapshot);
20984                    let end = highlight.range.end.to_display_point(&snapshot);
20985                    let start_row = start.row().0;
20986                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20987                    {
20988                        end.row().0.saturating_sub(1)
20989                    } else {
20990                        end.row().0
20991                    };
20992                    for row in start_row..=end_row {
20993                        let used_index =
20994                            used_highlight_orders.entry(row).or_insert(highlight.index);
20995                        if highlight.index >= *used_index {
20996                            *used_index = highlight.index;
20997                            unique_rows.insert(
20998                                DisplayRow(row),
20999                                LineHighlight {
21000                                    include_gutter: highlight.options.include_gutter,
21001                                    border: None,
21002                                    background: highlight.color.into(),
21003                                    type_id: Some(highlight.type_id),
21004                                },
21005                            );
21006                        }
21007                    }
21008                    unique_rows
21009                },
21010            )
21011    }
21012
21013    pub fn highlighted_display_row_for_autoscroll(
21014        &self,
21015        snapshot: &DisplaySnapshot,
21016    ) -> Option<DisplayRow> {
21017        self.highlighted_rows
21018            .values()
21019            .flat_map(|highlighted_rows| highlighted_rows.iter())
21020            .filter_map(|highlight| {
21021                if highlight.options.autoscroll {
21022                    Some(highlight.range.start.to_display_point(snapshot).row())
21023                } else {
21024                    None
21025                }
21026            })
21027            .min()
21028    }
21029
21030    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21031        self.highlight_background::<SearchWithinRange>(
21032            ranges,
21033            |_, colors| colors.colors().editor_document_highlight_read_background,
21034            cx,
21035        )
21036    }
21037
21038    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21039        self.breadcrumb_header = Some(new_header);
21040    }
21041
21042    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21043        self.clear_background_highlights::<SearchWithinRange>(cx);
21044    }
21045
21046    pub fn highlight_background<T: 'static>(
21047        &mut self,
21048        ranges: &[Range<Anchor>],
21049        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21050        cx: &mut Context<Self>,
21051    ) {
21052        self.background_highlights.insert(
21053            HighlightKey::Type(TypeId::of::<T>()),
21054            (Arc::new(color_fetcher), Arc::from(ranges)),
21055        );
21056        self.scrollbar_marker_state.dirty = true;
21057        cx.notify();
21058    }
21059
21060    pub fn highlight_background_key<T: 'static>(
21061        &mut self,
21062        key: usize,
21063        ranges: &[Range<Anchor>],
21064        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21065        cx: &mut Context<Self>,
21066    ) {
21067        self.background_highlights.insert(
21068            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21069            (Arc::new(color_fetcher), Arc::from(ranges)),
21070        );
21071        self.scrollbar_marker_state.dirty = true;
21072        cx.notify();
21073    }
21074
21075    pub fn clear_background_highlights<T: 'static>(
21076        &mut self,
21077        cx: &mut Context<Self>,
21078    ) -> Option<BackgroundHighlight> {
21079        let text_highlights = self
21080            .background_highlights
21081            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21082        if !text_highlights.1.is_empty() {
21083            self.scrollbar_marker_state.dirty = true;
21084            cx.notify();
21085        }
21086        Some(text_highlights)
21087    }
21088
21089    pub fn highlight_gutter<T: 'static>(
21090        &mut self,
21091        ranges: impl Into<Vec<Range<Anchor>>>,
21092        color_fetcher: fn(&App) -> Hsla,
21093        cx: &mut Context<Self>,
21094    ) {
21095        self.gutter_highlights
21096            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21097        cx.notify();
21098    }
21099
21100    pub fn clear_gutter_highlights<T: 'static>(
21101        &mut self,
21102        cx: &mut Context<Self>,
21103    ) -> Option<GutterHighlight> {
21104        cx.notify();
21105        self.gutter_highlights.remove(&TypeId::of::<T>())
21106    }
21107
21108    pub fn insert_gutter_highlight<T: 'static>(
21109        &mut self,
21110        range: Range<Anchor>,
21111        color_fetcher: fn(&App) -> Hsla,
21112        cx: &mut Context<Self>,
21113    ) {
21114        let snapshot = self.buffer().read(cx).snapshot(cx);
21115        let mut highlights = self
21116            .gutter_highlights
21117            .remove(&TypeId::of::<T>())
21118            .map(|(_, highlights)| highlights)
21119            .unwrap_or_default();
21120        let ix = highlights.binary_search_by(|highlight| {
21121            Ordering::Equal
21122                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21123                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21124        });
21125        if let Err(ix) = ix {
21126            highlights.insert(ix, range);
21127        }
21128        self.gutter_highlights
21129            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21130    }
21131
21132    pub fn remove_gutter_highlights<T: 'static>(
21133        &mut self,
21134        ranges_to_remove: Vec<Range<Anchor>>,
21135        cx: &mut Context<Self>,
21136    ) {
21137        let snapshot = self.buffer().read(cx).snapshot(cx);
21138        let Some((color_fetcher, mut gutter_highlights)) =
21139            self.gutter_highlights.remove(&TypeId::of::<T>())
21140        else {
21141            return;
21142        };
21143        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21144        gutter_highlights.retain(|highlight| {
21145            while let Some(range_to_remove) = ranges_to_remove.peek() {
21146                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21147                    Ordering::Less | Ordering::Equal => {
21148                        ranges_to_remove.next();
21149                    }
21150                    Ordering::Greater => {
21151                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21152                            Ordering::Less | Ordering::Equal => {
21153                                return false;
21154                            }
21155                            Ordering::Greater => break,
21156                        }
21157                    }
21158                }
21159            }
21160
21161            true
21162        });
21163        self.gutter_highlights
21164            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21165    }
21166
21167    #[cfg(feature = "test-support")]
21168    pub fn all_text_highlights(
21169        &self,
21170        window: &mut Window,
21171        cx: &mut Context<Self>,
21172    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21173        let snapshot = self.snapshot(window, cx);
21174        self.display_map.update(cx, |display_map, _| {
21175            display_map
21176                .all_text_highlights()
21177                .map(|highlight| {
21178                    let (style, ranges) = highlight.as_ref();
21179                    (
21180                        *style,
21181                        ranges
21182                            .iter()
21183                            .map(|range| range.clone().to_display_points(&snapshot))
21184                            .collect(),
21185                    )
21186                })
21187                .collect()
21188        })
21189    }
21190
21191    #[cfg(feature = "test-support")]
21192    pub fn all_text_background_highlights(
21193        &self,
21194        window: &mut Window,
21195        cx: &mut Context<Self>,
21196    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21197        let snapshot = self.snapshot(window, cx);
21198        let buffer = &snapshot.buffer_snapshot();
21199        let start = buffer.anchor_before(MultiBufferOffset(0));
21200        let end = buffer.anchor_after(buffer.len());
21201        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21202    }
21203
21204    #[cfg(any(test, feature = "test-support"))]
21205    pub fn sorted_background_highlights_in_range(
21206        &self,
21207        search_range: Range<Anchor>,
21208        display_snapshot: &DisplaySnapshot,
21209        theme: &Theme,
21210    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21211        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21212        res.sort_by(|a, b| {
21213            a.0.start
21214                .cmp(&b.0.start)
21215                .then_with(|| a.0.end.cmp(&b.0.end))
21216                .then_with(|| a.1.cmp(&b.1))
21217        });
21218        res
21219    }
21220
21221    #[cfg(feature = "test-support")]
21222    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21223        let snapshot = self.buffer().read(cx).snapshot(cx);
21224
21225        let highlights = self
21226            .background_highlights
21227            .get(&HighlightKey::Type(TypeId::of::<
21228                items::BufferSearchHighlights,
21229            >()));
21230
21231        if let Some((_color, ranges)) = highlights {
21232            ranges
21233                .iter()
21234                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21235                .collect_vec()
21236        } else {
21237            vec![]
21238        }
21239    }
21240
21241    fn document_highlights_for_position<'a>(
21242        &'a self,
21243        position: Anchor,
21244        buffer: &'a MultiBufferSnapshot,
21245    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21246        let read_highlights = self
21247            .background_highlights
21248            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21249            .map(|h| &h.1);
21250        let write_highlights = self
21251            .background_highlights
21252            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21253            .map(|h| &h.1);
21254        let left_position = position.bias_left(buffer);
21255        let right_position = position.bias_right(buffer);
21256        read_highlights
21257            .into_iter()
21258            .chain(write_highlights)
21259            .flat_map(move |ranges| {
21260                let start_ix = match ranges.binary_search_by(|probe| {
21261                    let cmp = probe.end.cmp(&left_position, buffer);
21262                    if cmp.is_ge() {
21263                        Ordering::Greater
21264                    } else {
21265                        Ordering::Less
21266                    }
21267                }) {
21268                    Ok(i) | Err(i) => i,
21269                };
21270
21271                ranges[start_ix..]
21272                    .iter()
21273                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21274            })
21275    }
21276
21277    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21278        self.background_highlights
21279            .get(&HighlightKey::Type(TypeId::of::<T>()))
21280            .is_some_and(|(_, highlights)| !highlights.is_empty())
21281    }
21282
21283    /// Returns all background highlights for a given range.
21284    ///
21285    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21286    pub fn background_highlights_in_range(
21287        &self,
21288        search_range: Range<Anchor>,
21289        display_snapshot: &DisplaySnapshot,
21290        theme: &Theme,
21291    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21292        let mut results = Vec::new();
21293        for (color_fetcher, ranges) in self.background_highlights.values() {
21294            let start_ix = match ranges.binary_search_by(|probe| {
21295                let cmp = probe
21296                    .end
21297                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21298                if cmp.is_gt() {
21299                    Ordering::Greater
21300                } else {
21301                    Ordering::Less
21302                }
21303            }) {
21304                Ok(i) | Err(i) => i,
21305            };
21306            for (index, range) in ranges[start_ix..].iter().enumerate() {
21307                if range
21308                    .start
21309                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21310                    .is_ge()
21311                {
21312                    break;
21313                }
21314
21315                let color = color_fetcher(&(start_ix + index), theme);
21316                let start = range.start.to_display_point(display_snapshot);
21317                let end = range.end.to_display_point(display_snapshot);
21318                results.push((start..end, color))
21319            }
21320        }
21321        results
21322    }
21323
21324    pub fn gutter_highlights_in_range(
21325        &self,
21326        search_range: Range<Anchor>,
21327        display_snapshot: &DisplaySnapshot,
21328        cx: &App,
21329    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21330        let mut results = Vec::new();
21331        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21332            let color = color_fetcher(cx);
21333            let start_ix = match ranges.binary_search_by(|probe| {
21334                let cmp = probe
21335                    .end
21336                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21337                if cmp.is_gt() {
21338                    Ordering::Greater
21339                } else {
21340                    Ordering::Less
21341                }
21342            }) {
21343                Ok(i) | Err(i) => i,
21344            };
21345            for range in &ranges[start_ix..] {
21346                if range
21347                    .start
21348                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21349                    .is_ge()
21350                {
21351                    break;
21352                }
21353
21354                let start = range.start.to_display_point(display_snapshot);
21355                let end = range.end.to_display_point(display_snapshot);
21356                results.push((start..end, color))
21357            }
21358        }
21359        results
21360    }
21361
21362    /// Get the text ranges corresponding to the redaction query
21363    pub fn redacted_ranges(
21364        &self,
21365        search_range: Range<Anchor>,
21366        display_snapshot: &DisplaySnapshot,
21367        cx: &App,
21368    ) -> Vec<Range<DisplayPoint>> {
21369        display_snapshot
21370            .buffer_snapshot()
21371            .redacted_ranges(search_range, |file| {
21372                if let Some(file) = file {
21373                    file.is_private()
21374                        && EditorSettings::get(
21375                            Some(SettingsLocation {
21376                                worktree_id: file.worktree_id(cx),
21377                                path: file.path().as_ref(),
21378                            }),
21379                            cx,
21380                        )
21381                        .redact_private_values
21382                } else {
21383                    false
21384                }
21385            })
21386            .map(|range| {
21387                range.start.to_display_point(display_snapshot)
21388                    ..range.end.to_display_point(display_snapshot)
21389            })
21390            .collect()
21391    }
21392
21393    pub fn highlight_text_key<T: 'static>(
21394        &mut self,
21395        key: usize,
21396        ranges: Vec<Range<Anchor>>,
21397        style: HighlightStyle,
21398        merge: bool,
21399        cx: &mut Context<Self>,
21400    ) {
21401        self.display_map.update(cx, |map, cx| {
21402            map.highlight_text(
21403                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21404                ranges,
21405                style,
21406                merge,
21407                cx,
21408            );
21409        });
21410        cx.notify();
21411    }
21412
21413    pub fn highlight_text<T: 'static>(
21414        &mut self,
21415        ranges: Vec<Range<Anchor>>,
21416        style: HighlightStyle,
21417        cx: &mut Context<Self>,
21418    ) {
21419        self.display_map.update(cx, |map, cx| {
21420            map.highlight_text(
21421                HighlightKey::Type(TypeId::of::<T>()),
21422                ranges,
21423                style,
21424                false,
21425                cx,
21426            )
21427        });
21428        cx.notify();
21429    }
21430
21431    pub fn text_highlights<'a, T: 'static>(
21432        &'a self,
21433        cx: &'a App,
21434    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21435        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21436    }
21437
21438    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21439        let cleared = self
21440            .display_map
21441            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21442        if cleared {
21443            cx.notify();
21444        }
21445    }
21446
21447    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21448        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21449            && self.focus_handle.is_focused(window)
21450    }
21451
21452    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21453        self.show_cursor_when_unfocused = is_enabled;
21454        cx.notify();
21455    }
21456
21457    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21458        cx.notify();
21459    }
21460
21461    fn on_debug_session_event(
21462        &mut self,
21463        _session: Entity<Session>,
21464        event: &SessionEvent,
21465        cx: &mut Context<Self>,
21466    ) {
21467        if let SessionEvent::InvalidateInlineValue = event {
21468            self.refresh_inline_values(cx);
21469        }
21470    }
21471
21472    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21473        let Some(project) = self.project.clone() else {
21474            return;
21475        };
21476
21477        if !self.inline_value_cache.enabled {
21478            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21479            self.splice_inlays(&inlays, Vec::new(), cx);
21480            return;
21481        }
21482
21483        let current_execution_position = self
21484            .highlighted_rows
21485            .get(&TypeId::of::<ActiveDebugLine>())
21486            .and_then(|lines| lines.last().map(|line| line.range.end));
21487
21488        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21489            let inline_values = editor
21490                .update(cx, |editor, cx| {
21491                    let Some(current_execution_position) = current_execution_position else {
21492                        return Some(Task::ready(Ok(Vec::new())));
21493                    };
21494
21495                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21496                        let snapshot = buffer.snapshot(cx);
21497
21498                        let excerpt = snapshot.excerpt_containing(
21499                            current_execution_position..current_execution_position,
21500                        )?;
21501
21502                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21503                    })?;
21504
21505                    let range =
21506                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21507
21508                    project.inline_values(buffer, range, cx)
21509                })
21510                .ok()
21511                .flatten()?
21512                .await
21513                .context("refreshing debugger inlays")
21514                .log_err()?;
21515
21516            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21517
21518            for (buffer_id, inline_value) in inline_values
21519                .into_iter()
21520                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21521            {
21522                buffer_inline_values
21523                    .entry(buffer_id)
21524                    .or_default()
21525                    .push(inline_value);
21526            }
21527
21528            editor
21529                .update(cx, |editor, cx| {
21530                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21531                    let mut new_inlays = Vec::default();
21532
21533                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21534                        let buffer_id = buffer_snapshot.remote_id();
21535                        buffer_inline_values
21536                            .get(&buffer_id)
21537                            .into_iter()
21538                            .flatten()
21539                            .for_each(|hint| {
21540                                let inlay = Inlay::debugger(
21541                                    post_inc(&mut editor.next_inlay_id),
21542                                    Anchor::in_buffer(excerpt_id, hint.position),
21543                                    hint.text(),
21544                                );
21545                                if !inlay.text().chars().contains(&'\n') {
21546                                    new_inlays.push(inlay);
21547                                }
21548                            });
21549                    }
21550
21551                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21552                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21553
21554                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21555                })
21556                .ok()?;
21557            Some(())
21558        });
21559    }
21560
21561    fn on_buffer_event(
21562        &mut self,
21563        multibuffer: &Entity<MultiBuffer>,
21564        event: &multi_buffer::Event,
21565        window: &mut Window,
21566        cx: &mut Context<Self>,
21567    ) {
21568        match event {
21569            multi_buffer::Event::Edited { edited_buffer } => {
21570                self.scrollbar_marker_state.dirty = true;
21571                self.active_indent_guides_state.dirty = true;
21572                self.refresh_active_diagnostics(cx);
21573                self.refresh_code_actions(window, cx);
21574                self.refresh_single_line_folds(window, cx);
21575                self.refresh_matching_bracket_highlights(window, cx);
21576                if self.has_active_edit_prediction() {
21577                    self.update_visible_edit_prediction(window, cx);
21578                }
21579
21580                if let Some(buffer) = edited_buffer {
21581                    if buffer.read(cx).file().is_none() {
21582                        cx.emit(EditorEvent::TitleChanged);
21583                    }
21584
21585                    if self.project.is_some() {
21586                        let buffer_id = buffer.read(cx).remote_id();
21587                        self.register_buffer(buffer_id, cx);
21588                        self.update_lsp_data(Some(buffer_id), window, cx);
21589                        self.refresh_inlay_hints(
21590                            InlayHintRefreshReason::BufferEdited(buffer_id),
21591                            cx,
21592                        );
21593                    }
21594                }
21595
21596                cx.emit(EditorEvent::BufferEdited);
21597                cx.emit(SearchEvent::MatchesInvalidated);
21598
21599                let Some(project) = &self.project else { return };
21600                let (telemetry, is_via_ssh) = {
21601                    let project = project.read(cx);
21602                    let telemetry = project.client().telemetry().clone();
21603                    let is_via_ssh = project.is_via_remote_server();
21604                    (telemetry, is_via_ssh)
21605                };
21606                telemetry.log_edit_event("editor", is_via_ssh);
21607            }
21608            multi_buffer::Event::ExcerptsAdded {
21609                buffer,
21610                predecessor,
21611                excerpts,
21612            } => {
21613                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21614                let buffer_id = buffer.read(cx).remote_id();
21615                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21616                    && let Some(project) = &self.project
21617                {
21618                    update_uncommitted_diff_for_buffer(
21619                        cx.entity(),
21620                        project,
21621                        [buffer.clone()],
21622                        self.buffer.clone(),
21623                        cx,
21624                    )
21625                    .detach();
21626                }
21627                self.update_lsp_data(Some(buffer_id), window, cx);
21628                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21629                self.colorize_brackets(false, cx);
21630                cx.emit(EditorEvent::ExcerptsAdded {
21631                    buffer: buffer.clone(),
21632                    predecessor: *predecessor,
21633                    excerpts: excerpts.clone(),
21634                });
21635            }
21636            multi_buffer::Event::ExcerptsRemoved {
21637                ids,
21638                removed_buffer_ids,
21639            } => {
21640                if let Some(inlay_hints) = &mut self.inlay_hints {
21641                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21642                }
21643                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21644                for buffer_id in removed_buffer_ids {
21645                    self.registered_buffers.remove(buffer_id);
21646                }
21647                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21648                cx.emit(EditorEvent::ExcerptsRemoved {
21649                    ids: ids.clone(),
21650                    removed_buffer_ids: removed_buffer_ids.clone(),
21651                });
21652            }
21653            multi_buffer::Event::ExcerptsEdited {
21654                excerpt_ids,
21655                buffer_ids,
21656            } => {
21657                self.display_map.update(cx, |map, cx| {
21658                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21659                });
21660                cx.emit(EditorEvent::ExcerptsEdited {
21661                    ids: excerpt_ids.clone(),
21662                });
21663            }
21664            multi_buffer::Event::ExcerptsExpanded { ids } => {
21665                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21666                self.refresh_document_highlights(cx);
21667                for id in ids {
21668                    self.fetched_tree_sitter_chunks.remove(id);
21669                }
21670                self.colorize_brackets(false, cx);
21671                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21672            }
21673            multi_buffer::Event::Reparsed(buffer_id) => {
21674                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21675                self.refresh_selected_text_highlights(true, window, cx);
21676                self.colorize_brackets(true, cx);
21677                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21678
21679                cx.emit(EditorEvent::Reparsed(*buffer_id));
21680            }
21681            multi_buffer::Event::DiffHunksToggled => {
21682                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21683            }
21684            multi_buffer::Event::LanguageChanged(buffer_id) => {
21685                self.registered_buffers.remove(&buffer_id);
21686                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21687                cx.emit(EditorEvent::Reparsed(*buffer_id));
21688                cx.notify();
21689            }
21690            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21691            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21692            multi_buffer::Event::FileHandleChanged
21693            | multi_buffer::Event::Reloaded
21694            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21695            multi_buffer::Event::DiagnosticsUpdated => {
21696                self.update_diagnostics_state(window, cx);
21697            }
21698            _ => {}
21699        };
21700    }
21701
21702    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21703        if !self.diagnostics_enabled() {
21704            return;
21705        }
21706        self.refresh_active_diagnostics(cx);
21707        self.refresh_inline_diagnostics(true, window, cx);
21708        self.scrollbar_marker_state.dirty = true;
21709        cx.notify();
21710    }
21711
21712    pub fn start_temporary_diff_override(&mut self) {
21713        self.load_diff_task.take();
21714        self.temporary_diff_override = true;
21715    }
21716
21717    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21718        self.temporary_diff_override = false;
21719        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21720        self.buffer.update(cx, |buffer, cx| {
21721            buffer.set_all_diff_hunks_collapsed(cx);
21722        });
21723
21724        if let Some(project) = self.project.clone() {
21725            self.load_diff_task = Some(
21726                update_uncommitted_diff_for_buffer(
21727                    cx.entity(),
21728                    &project,
21729                    self.buffer.read(cx).all_buffers(),
21730                    self.buffer.clone(),
21731                    cx,
21732                )
21733                .shared(),
21734            );
21735        }
21736    }
21737
21738    fn on_display_map_changed(
21739        &mut self,
21740        _: Entity<DisplayMap>,
21741        _: &mut Window,
21742        cx: &mut Context<Self>,
21743    ) {
21744        cx.notify();
21745    }
21746
21747    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
21748        if !self.mode.is_full() {
21749            return None;
21750        }
21751
21752        let theme_settings = theme::ThemeSettings::get_global(cx);
21753        let theme = cx.theme();
21754        let accent_colors = theme.accents().clone();
21755
21756        let accent_overrides = theme_settings
21757            .theme_overrides
21758            .get(theme.name.as_ref())
21759            .map(|theme_style| &theme_style.accents)
21760            .into_iter()
21761            .flatten()
21762            .chain(
21763                theme_settings
21764                    .experimental_theme_overrides
21765                    .as_ref()
21766                    .map(|overrides| &overrides.accents)
21767                    .into_iter()
21768                    .flatten(),
21769            )
21770            .flat_map(|accent| accent.0.clone())
21771            .collect();
21772
21773        Some(AccentData {
21774            colors: accent_colors,
21775            overrides: accent_overrides,
21776        })
21777    }
21778
21779    fn fetch_applicable_language_settings(
21780        &self,
21781        cx: &App,
21782    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21783        if !self.mode.is_full() {
21784            return HashMap::default();
21785        }
21786
21787        self.buffer().read(cx).all_buffers().into_iter().fold(
21788            HashMap::default(),
21789            |mut acc, buffer| {
21790                let buffer = buffer.read(cx);
21791                let language = buffer.language().map(|language| language.name());
21792                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21793                    let file = buffer.file();
21794                    v.insert(language_settings(language, file, cx).into_owned());
21795                }
21796                acc
21797            },
21798        )
21799    }
21800
21801    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21802        let new_language_settings = self.fetch_applicable_language_settings(cx);
21803        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21804        self.applicable_language_settings = new_language_settings;
21805
21806        let new_accents = self.fetch_accent_data(cx);
21807        let accents_changed = new_accents != self.accent_data;
21808        self.accent_data = new_accents;
21809
21810        if self.diagnostics_enabled() {
21811            let new_severity = EditorSettings::get_global(cx)
21812                .diagnostics_max_severity
21813                .unwrap_or(DiagnosticSeverity::Hint);
21814            self.set_max_diagnostics_severity(new_severity, cx);
21815        }
21816        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21817        self.update_edit_prediction_settings(cx);
21818        self.refresh_edit_prediction(true, false, window, cx);
21819        self.refresh_inline_values(cx);
21820        self.refresh_inlay_hints(
21821            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21822                self.selections.newest_anchor().head(),
21823                &self.buffer.read(cx).snapshot(cx),
21824                cx,
21825            )),
21826            cx,
21827        );
21828
21829        let old_cursor_shape = self.cursor_shape;
21830        let old_show_breadcrumbs = self.show_breadcrumbs;
21831
21832        {
21833            let editor_settings = EditorSettings::get_global(cx);
21834            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21835            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21836            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21837            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21838        }
21839
21840        if old_cursor_shape != self.cursor_shape {
21841            cx.emit(EditorEvent::CursorShapeChanged);
21842        }
21843
21844        if old_show_breadcrumbs != self.show_breadcrumbs {
21845            cx.emit(EditorEvent::BreadcrumbsChanged);
21846        }
21847
21848        let project_settings = ProjectSettings::get_global(cx);
21849        self.buffer_serialization = self
21850            .should_serialize_buffer()
21851            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21852
21853        if self.mode.is_full() {
21854            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21855            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21856            if self.show_inline_diagnostics != show_inline_diagnostics {
21857                self.show_inline_diagnostics = show_inline_diagnostics;
21858                self.refresh_inline_diagnostics(false, window, cx);
21859            }
21860
21861            if self.git_blame_inline_enabled != inline_blame_enabled {
21862                self.toggle_git_blame_inline_internal(false, window, cx);
21863            }
21864
21865            let minimap_settings = EditorSettings::get_global(cx).minimap;
21866            if self.minimap_visibility != MinimapVisibility::Disabled {
21867                if self.minimap_visibility.settings_visibility()
21868                    != minimap_settings.minimap_enabled()
21869                {
21870                    self.set_minimap_visibility(
21871                        MinimapVisibility::for_mode(self.mode(), cx),
21872                        window,
21873                        cx,
21874                    );
21875                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21876                    minimap_entity.update(cx, |minimap_editor, cx| {
21877                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21878                    })
21879                }
21880            }
21881
21882            if language_settings_changed || accents_changed {
21883                self.colorize_brackets(true, cx);
21884            }
21885
21886            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21887                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21888            }) {
21889                if !inlay_splice.is_empty() {
21890                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21891                }
21892                self.refresh_colors_for_visible_range(None, window, cx);
21893            }
21894        }
21895
21896        cx.notify();
21897    }
21898
21899    pub fn set_searchable(&mut self, searchable: bool) {
21900        self.searchable = searchable;
21901    }
21902
21903    pub fn searchable(&self) -> bool {
21904        self.searchable
21905    }
21906
21907    pub fn open_excerpts_in_split(
21908        &mut self,
21909        _: &OpenExcerptsSplit,
21910        window: &mut Window,
21911        cx: &mut Context<Self>,
21912    ) {
21913        self.open_excerpts_common(None, true, window, cx)
21914    }
21915
21916    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21917        self.open_excerpts_common(None, false, window, cx)
21918    }
21919
21920    fn open_excerpts_common(
21921        &mut self,
21922        jump_data: Option<JumpData>,
21923        split: bool,
21924        window: &mut Window,
21925        cx: &mut Context<Self>,
21926    ) {
21927        let Some(workspace) = self.workspace() else {
21928            cx.propagate();
21929            return;
21930        };
21931
21932        if self.buffer.read(cx).is_singleton() {
21933            cx.propagate();
21934            return;
21935        }
21936
21937        let mut new_selections_by_buffer = HashMap::default();
21938        match &jump_data {
21939            Some(JumpData::MultiBufferPoint {
21940                excerpt_id,
21941                position,
21942                anchor,
21943                line_offset_from_top,
21944            }) => {
21945                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21946                if let Some(buffer) = multi_buffer_snapshot
21947                    .buffer_id_for_excerpt(*excerpt_id)
21948                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21949                {
21950                    let buffer_snapshot = buffer.read(cx).snapshot();
21951                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21952                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21953                    } else {
21954                        buffer_snapshot.clip_point(*position, Bias::Left)
21955                    };
21956                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21957                    new_selections_by_buffer.insert(
21958                        buffer,
21959                        (
21960                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21961                            Some(*line_offset_from_top),
21962                        ),
21963                    );
21964                }
21965            }
21966            Some(JumpData::MultiBufferRow {
21967                row,
21968                line_offset_from_top,
21969            }) => {
21970                let point = MultiBufferPoint::new(row.0, 0);
21971                if let Some((buffer, buffer_point, _)) =
21972                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21973                {
21974                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21975                    new_selections_by_buffer
21976                        .entry(buffer)
21977                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21978                        .0
21979                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21980                }
21981            }
21982            None => {
21983                let selections = self
21984                    .selections
21985                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21986                let multi_buffer = self.buffer.read(cx);
21987                for selection in selections {
21988                    for (snapshot, range, _, anchor) in multi_buffer
21989                        .snapshot(cx)
21990                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21991                    {
21992                        if let Some(anchor) = anchor {
21993                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21994                            else {
21995                                continue;
21996                            };
21997                            let offset = text::ToOffset::to_offset(
21998                                &anchor.text_anchor,
21999                                &buffer_handle.read(cx).snapshot(),
22000                            );
22001                            let range = BufferOffset(offset)..BufferOffset(offset);
22002                            new_selections_by_buffer
22003                                .entry(buffer_handle)
22004                                .or_insert((Vec::new(), None))
22005                                .0
22006                                .push(range)
22007                        } else {
22008                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22009                            else {
22010                                continue;
22011                            };
22012                            new_selections_by_buffer
22013                                .entry(buffer_handle)
22014                                .or_insert((Vec::new(), None))
22015                                .0
22016                                .push(range)
22017                        }
22018                    }
22019                }
22020            }
22021        }
22022
22023        new_selections_by_buffer
22024            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22025
22026        if new_selections_by_buffer.is_empty() {
22027            return;
22028        }
22029
22030        // We defer the pane interaction because we ourselves are a workspace item
22031        // and activating a new item causes the pane to call a method on us reentrantly,
22032        // which panics if we're on the stack.
22033        window.defer(cx, move |window, cx| {
22034            workspace.update(cx, |workspace, cx| {
22035                let pane = if split {
22036                    workspace.adjacent_pane(window, cx)
22037                } else {
22038                    workspace.active_pane().clone()
22039                };
22040
22041                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22042                    let buffer_read = buffer.read(cx);
22043                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22044                        (true, project::File::from_dyn(Some(file)).is_some())
22045                    } else {
22046                        (false, false)
22047                    };
22048
22049                    // If project file is none workspace.open_project_item will fail to open the excerpt
22050                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22051                    // so we check if there's a tab match in that case first
22052                    let editor = (!has_file || !is_project_file)
22053                        .then(|| {
22054                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22055                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22056                            // Instead, we try to activate the existing editor in the pane first.
22057                            let (editor, pane_item_index, pane_item_id) =
22058                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22059                                    let editor = item.downcast::<Editor>()?;
22060                                    let singleton_buffer =
22061                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22062                                    if singleton_buffer == buffer {
22063                                        Some((editor, i, item.item_id()))
22064                                    } else {
22065                                        None
22066                                    }
22067                                })?;
22068                            pane.update(cx, |pane, cx| {
22069                                pane.activate_item(pane_item_index, true, true, window, cx);
22070                                if !PreviewTabsSettings::get_global(cx)
22071                                    .enable_preview_from_multibuffer
22072                                {
22073                                    pane.unpreview_item_if_preview(pane_item_id);
22074                                }
22075                            });
22076                            Some(editor)
22077                        })
22078                        .flatten()
22079                        .unwrap_or_else(|| {
22080                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22081                                .enable_keep_preview_on_code_navigation;
22082                            let allow_new_preview =
22083                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22084                            workspace.open_project_item::<Self>(
22085                                pane.clone(),
22086                                buffer,
22087                                true,
22088                                true,
22089                                keep_old_preview,
22090                                allow_new_preview,
22091                                window,
22092                                cx,
22093                            )
22094                        });
22095
22096                    editor.update(cx, |editor, cx| {
22097                        if has_file && !is_project_file {
22098                            editor.set_read_only(true);
22099                        }
22100                        let autoscroll = match scroll_offset {
22101                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22102                            None => Autoscroll::newest(),
22103                        };
22104                        let nav_history = editor.nav_history.take();
22105                        editor.change_selections(
22106                            SelectionEffects::scroll(autoscroll),
22107                            window,
22108                            cx,
22109                            |s| {
22110                                s.select_ranges(ranges.into_iter().map(|range| {
22111                                    // we checked that the editor is a singleton editor so the offsets are valid
22112                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
22113                                }));
22114                            },
22115                        );
22116                        editor.nav_history = nav_history;
22117                    });
22118                }
22119            })
22120        });
22121    }
22122
22123    // Allow opening excerpts for buffers that either belong to the current project
22124    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22125    // are also supported so tests and other in-memory views keep working.
22126    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22127        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22128    }
22129
22130    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22131        let snapshot = self.buffer.read(cx).read(cx);
22132        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22133        Some(
22134            ranges
22135                .iter()
22136                .map(move |range| {
22137                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22138                })
22139                .collect(),
22140        )
22141    }
22142
22143    fn selection_replacement_ranges(
22144        &self,
22145        range: Range<MultiBufferOffsetUtf16>,
22146        cx: &mut App,
22147    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22148        let selections = self
22149            .selections
22150            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22151        let newest_selection = selections
22152            .iter()
22153            .max_by_key(|selection| selection.id)
22154            .unwrap();
22155        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22156        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22157        let snapshot = self.buffer.read(cx).read(cx);
22158        selections
22159            .into_iter()
22160            .map(|mut selection| {
22161                selection.start.0.0 =
22162                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22163                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22164                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22165                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22166            })
22167            .collect()
22168    }
22169
22170    fn report_editor_event(
22171        &self,
22172        reported_event: ReportEditorEvent,
22173        file_extension: Option<String>,
22174        cx: &App,
22175    ) {
22176        if cfg!(any(test, feature = "test-support")) {
22177            return;
22178        }
22179
22180        let Some(project) = &self.project else { return };
22181
22182        // If None, we are in a file without an extension
22183        let file = self
22184            .buffer
22185            .read(cx)
22186            .as_singleton()
22187            .and_then(|b| b.read(cx).file());
22188        let file_extension = file_extension.or(file
22189            .as_ref()
22190            .and_then(|file| Path::new(file.file_name(cx)).extension())
22191            .and_then(|e| e.to_str())
22192            .map(|a| a.to_string()));
22193
22194        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22195            .map(|vim_mode| vim_mode.0)
22196            .unwrap_or(false);
22197
22198        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22199        let copilot_enabled = edit_predictions_provider
22200            == language::language_settings::EditPredictionProvider::Copilot;
22201        let copilot_enabled_for_language = self
22202            .buffer
22203            .read(cx)
22204            .language_settings(cx)
22205            .show_edit_predictions;
22206
22207        let project = project.read(cx);
22208        let event_type = reported_event.event_type();
22209
22210        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22211            telemetry::event!(
22212                event_type,
22213                type = if auto_saved {"autosave"} else {"manual"},
22214                file_extension,
22215                vim_mode,
22216                copilot_enabled,
22217                copilot_enabled_for_language,
22218                edit_predictions_provider,
22219                is_via_ssh = project.is_via_remote_server(),
22220            );
22221        } else {
22222            telemetry::event!(
22223                event_type,
22224                file_extension,
22225                vim_mode,
22226                copilot_enabled,
22227                copilot_enabled_for_language,
22228                edit_predictions_provider,
22229                is_via_ssh = project.is_via_remote_server(),
22230            );
22231        };
22232    }
22233
22234    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22235    /// with each line being an array of {text, highlight} objects.
22236    fn copy_highlight_json(
22237        &mut self,
22238        _: &CopyHighlightJson,
22239        window: &mut Window,
22240        cx: &mut Context<Self>,
22241    ) {
22242        #[derive(Serialize)]
22243        struct Chunk<'a> {
22244            text: String,
22245            highlight: Option<&'a str>,
22246        }
22247
22248        let snapshot = self.buffer.read(cx).snapshot(cx);
22249        let range = self
22250            .selected_text_range(false, window, cx)
22251            .and_then(|selection| {
22252                if selection.range.is_empty() {
22253                    None
22254                } else {
22255                    Some(
22256                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22257                            selection.range.start,
22258                        )))
22259                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22260                                selection.range.end,
22261                            ))),
22262                    )
22263                }
22264            })
22265            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22266
22267        let chunks = snapshot.chunks(range, true);
22268        let mut lines = Vec::new();
22269        let mut line: VecDeque<Chunk> = VecDeque::new();
22270
22271        let Some(style) = self.style.as_ref() else {
22272            return;
22273        };
22274
22275        for chunk in chunks {
22276            let highlight = chunk
22277                .syntax_highlight_id
22278                .and_then(|id| id.name(&style.syntax));
22279            let mut chunk_lines = chunk.text.split('\n').peekable();
22280            while let Some(text) = chunk_lines.next() {
22281                let mut merged_with_last_token = false;
22282                if let Some(last_token) = line.back_mut()
22283                    && last_token.highlight == highlight
22284                {
22285                    last_token.text.push_str(text);
22286                    merged_with_last_token = true;
22287                }
22288
22289                if !merged_with_last_token {
22290                    line.push_back(Chunk {
22291                        text: text.into(),
22292                        highlight,
22293                    });
22294                }
22295
22296                if chunk_lines.peek().is_some() {
22297                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22298                        line.pop_front();
22299                    }
22300                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22301                        line.pop_back();
22302                    }
22303
22304                    lines.push(mem::take(&mut line));
22305                }
22306            }
22307        }
22308
22309        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22310            return;
22311        };
22312        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22313    }
22314
22315    pub fn open_context_menu(
22316        &mut self,
22317        _: &OpenContextMenu,
22318        window: &mut Window,
22319        cx: &mut Context<Self>,
22320    ) {
22321        self.request_autoscroll(Autoscroll::newest(), cx);
22322        let position = self
22323            .selections
22324            .newest_display(&self.display_snapshot(cx))
22325            .start;
22326        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22327    }
22328
22329    pub fn replay_insert_event(
22330        &mut self,
22331        text: &str,
22332        relative_utf16_range: Option<Range<isize>>,
22333        window: &mut Window,
22334        cx: &mut Context<Self>,
22335    ) {
22336        if !self.input_enabled {
22337            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22338            return;
22339        }
22340        if let Some(relative_utf16_range) = relative_utf16_range {
22341            let selections = self
22342                .selections
22343                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22344            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22345                let new_ranges = selections.into_iter().map(|range| {
22346                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22347                        range
22348                            .head()
22349                            .0
22350                            .0
22351                            .saturating_add_signed(relative_utf16_range.start),
22352                    ));
22353                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22354                        range
22355                            .head()
22356                            .0
22357                            .0
22358                            .saturating_add_signed(relative_utf16_range.end),
22359                    ));
22360                    start..end
22361                });
22362                s.select_ranges(new_ranges);
22363            });
22364        }
22365
22366        self.handle_input(text, window, cx);
22367    }
22368
22369    pub fn is_focused(&self, window: &Window) -> bool {
22370        self.focus_handle.is_focused(window)
22371    }
22372
22373    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22374        cx.emit(EditorEvent::Focused);
22375
22376        if let Some(descendant) = self
22377            .last_focused_descendant
22378            .take()
22379            .and_then(|descendant| descendant.upgrade())
22380        {
22381            window.focus(&descendant);
22382        } else {
22383            if let Some(blame) = self.blame.as_ref() {
22384                blame.update(cx, GitBlame::focus)
22385            }
22386
22387            self.blink_manager.update(cx, BlinkManager::enable);
22388            self.show_cursor_names(window, cx);
22389            self.buffer.update(cx, |buffer, cx| {
22390                buffer.finalize_last_transaction(cx);
22391                if self.leader_id.is_none() {
22392                    buffer.set_active_selections(
22393                        &self.selections.disjoint_anchors_arc(),
22394                        self.selections.line_mode(),
22395                        self.cursor_shape,
22396                        cx,
22397                    );
22398                }
22399            });
22400
22401            if let Some(position_map) = self.last_position_map.clone() {
22402                EditorElement::mouse_moved(
22403                    self,
22404                    &MouseMoveEvent {
22405                        position: window.mouse_position(),
22406                        pressed_button: None,
22407                        modifiers: window.modifiers(),
22408                    },
22409                    &position_map,
22410                    window,
22411                    cx,
22412                );
22413            }
22414        }
22415    }
22416
22417    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22418        cx.emit(EditorEvent::FocusedIn)
22419    }
22420
22421    fn handle_focus_out(
22422        &mut self,
22423        event: FocusOutEvent,
22424        _window: &mut Window,
22425        cx: &mut Context<Self>,
22426    ) {
22427        if event.blurred != self.focus_handle {
22428            self.last_focused_descendant = Some(event.blurred);
22429        }
22430        self.selection_drag_state = SelectionDragState::None;
22431        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22432    }
22433
22434    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22435        self.blink_manager.update(cx, BlinkManager::disable);
22436        self.buffer
22437            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22438
22439        if let Some(blame) = self.blame.as_ref() {
22440            blame.update(cx, GitBlame::blur)
22441        }
22442        if !self.hover_state.focused(window, cx) {
22443            hide_hover(self, cx);
22444        }
22445        if !self
22446            .context_menu
22447            .borrow()
22448            .as_ref()
22449            .is_some_and(|context_menu| context_menu.focused(window, cx))
22450        {
22451            self.hide_context_menu(window, cx);
22452        }
22453        self.take_active_edit_prediction(cx);
22454        cx.emit(EditorEvent::Blurred);
22455        cx.notify();
22456    }
22457
22458    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22459        let mut pending: String = window
22460            .pending_input_keystrokes()
22461            .into_iter()
22462            .flatten()
22463            .filter_map(|keystroke| keystroke.key_char.clone())
22464            .collect();
22465
22466        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22467            pending = "".to_string();
22468        }
22469
22470        let existing_pending = self
22471            .text_highlights::<PendingInput>(cx)
22472            .map(|(_, ranges)| ranges.to_vec());
22473        if existing_pending.is_none() && pending.is_empty() {
22474            return;
22475        }
22476        let transaction =
22477            self.transact(window, cx, |this, window, cx| {
22478                let selections = this
22479                    .selections
22480                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22481                let edits = selections
22482                    .iter()
22483                    .map(|selection| (selection.end..selection.end, pending.clone()));
22484                this.edit(edits, cx);
22485                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22486                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22487                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22488                    }));
22489                });
22490                if let Some(existing_ranges) = existing_pending {
22491                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22492                    this.edit(edits, cx);
22493                }
22494            });
22495
22496        let snapshot = self.snapshot(window, cx);
22497        let ranges = self
22498            .selections
22499            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22500            .into_iter()
22501            .map(|selection| {
22502                snapshot.buffer_snapshot().anchor_after(selection.end)
22503                    ..snapshot
22504                        .buffer_snapshot()
22505                        .anchor_before(selection.end + pending.len())
22506            })
22507            .collect();
22508
22509        if pending.is_empty() {
22510            self.clear_highlights::<PendingInput>(cx);
22511        } else {
22512            self.highlight_text::<PendingInput>(
22513                ranges,
22514                HighlightStyle {
22515                    underline: Some(UnderlineStyle {
22516                        thickness: px(1.),
22517                        color: None,
22518                        wavy: false,
22519                    }),
22520                    ..Default::default()
22521                },
22522                cx,
22523            );
22524        }
22525
22526        self.ime_transaction = self.ime_transaction.or(transaction);
22527        if let Some(transaction) = self.ime_transaction {
22528            self.buffer.update(cx, |buffer, cx| {
22529                buffer.group_until_transaction(transaction, cx);
22530            });
22531        }
22532
22533        if self.text_highlights::<PendingInput>(cx).is_none() {
22534            self.ime_transaction.take();
22535        }
22536    }
22537
22538    pub fn register_action_renderer(
22539        &mut self,
22540        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22541    ) -> Subscription {
22542        let id = self.next_editor_action_id.post_inc();
22543        self.editor_actions
22544            .borrow_mut()
22545            .insert(id, Box::new(listener));
22546
22547        let editor_actions = self.editor_actions.clone();
22548        Subscription::new(move || {
22549            editor_actions.borrow_mut().remove(&id);
22550        })
22551    }
22552
22553    pub fn register_action<A: Action>(
22554        &mut self,
22555        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22556    ) -> Subscription {
22557        let id = self.next_editor_action_id.post_inc();
22558        let listener = Arc::new(listener);
22559        self.editor_actions.borrow_mut().insert(
22560            id,
22561            Box::new(move |_, window, _| {
22562                let listener = listener.clone();
22563                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22564                    let action = action.downcast_ref().unwrap();
22565                    if phase == DispatchPhase::Bubble {
22566                        listener(action, window, cx)
22567                    }
22568                })
22569            }),
22570        );
22571
22572        let editor_actions = self.editor_actions.clone();
22573        Subscription::new(move || {
22574            editor_actions.borrow_mut().remove(&id);
22575        })
22576    }
22577
22578    pub fn file_header_size(&self) -> u32 {
22579        FILE_HEADER_HEIGHT
22580    }
22581
22582    pub fn restore(
22583        &mut self,
22584        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22585        window: &mut Window,
22586        cx: &mut Context<Self>,
22587    ) {
22588        let workspace = self.workspace();
22589        let project = self.project();
22590        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22591            let mut tasks = Vec::new();
22592            for (buffer_id, changes) in revert_changes {
22593                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22594                    buffer.update(cx, |buffer, cx| {
22595                        buffer.edit(
22596                            changes
22597                                .into_iter()
22598                                .map(|(range, text)| (range, text.to_string())),
22599                            None,
22600                            cx,
22601                        );
22602                    });
22603
22604                    if let Some(project) =
22605                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22606                    {
22607                        project.update(cx, |project, cx| {
22608                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22609                        })
22610                    }
22611                }
22612            }
22613            tasks
22614        });
22615        cx.spawn_in(window, async move |_, cx| {
22616            for (buffer, task) in save_tasks {
22617                let result = task.await;
22618                if result.is_err() {
22619                    let Some(path) = buffer
22620                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22621                        .ok()
22622                    else {
22623                        continue;
22624                    };
22625                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22626                        let Some(task) = cx
22627                            .update_window_entity(workspace, |workspace, window, cx| {
22628                                workspace
22629                                    .open_path_preview(path, None, false, false, false, window, cx)
22630                            })
22631                            .ok()
22632                        else {
22633                            continue;
22634                        };
22635                        task.await.log_err();
22636                    }
22637                }
22638            }
22639        })
22640        .detach();
22641        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22642            selections.refresh()
22643        });
22644    }
22645
22646    pub fn to_pixel_point(
22647        &self,
22648        source: multi_buffer::Anchor,
22649        editor_snapshot: &EditorSnapshot,
22650        window: &mut Window,
22651    ) -> Option<gpui::Point<Pixels>> {
22652        let source_point = source.to_display_point(editor_snapshot);
22653        self.display_to_pixel_point(source_point, editor_snapshot, window)
22654    }
22655
22656    pub fn display_to_pixel_point(
22657        &self,
22658        source: DisplayPoint,
22659        editor_snapshot: &EditorSnapshot,
22660        window: &mut Window,
22661    ) -> Option<gpui::Point<Pixels>> {
22662        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22663        let text_layout_details = self.text_layout_details(window);
22664        let scroll_top = text_layout_details
22665            .scroll_anchor
22666            .scroll_position(editor_snapshot)
22667            .y;
22668
22669        if source.row().as_f64() < scroll_top.floor() {
22670            return None;
22671        }
22672        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22673        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22674        Some(gpui::Point::new(source_x, source_y))
22675    }
22676
22677    pub fn has_visible_completions_menu(&self) -> bool {
22678        !self.edit_prediction_preview_is_active()
22679            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22680                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22681            })
22682    }
22683
22684    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22685        if self.mode.is_minimap() {
22686            return;
22687        }
22688        self.addons
22689            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22690    }
22691
22692    pub fn unregister_addon<T: Addon>(&mut self) {
22693        self.addons.remove(&std::any::TypeId::of::<T>());
22694    }
22695
22696    pub fn addon<T: Addon>(&self) -> Option<&T> {
22697        let type_id = std::any::TypeId::of::<T>();
22698        self.addons
22699            .get(&type_id)
22700            .and_then(|item| item.to_any().downcast_ref::<T>())
22701    }
22702
22703    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22704        let type_id = std::any::TypeId::of::<T>();
22705        self.addons
22706            .get_mut(&type_id)
22707            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22708    }
22709
22710    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22711        let text_layout_details = self.text_layout_details(window);
22712        let style = &text_layout_details.editor_style;
22713        let font_id = window.text_system().resolve_font(&style.text.font());
22714        let font_size = style.text.font_size.to_pixels(window.rem_size());
22715        let line_height = style.text.line_height_in_pixels(window.rem_size());
22716        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22717        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22718
22719        CharacterDimensions {
22720            em_width,
22721            em_advance,
22722            line_height,
22723        }
22724    }
22725
22726    pub fn last_gutter_dimensions(&self) -> &GutterDimensions {
22727        &self.gutter_dimensions
22728    }
22729
22730    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22731        self.load_diff_task.clone()
22732    }
22733
22734    fn read_metadata_from_db(
22735        &mut self,
22736        item_id: u64,
22737        workspace_id: WorkspaceId,
22738        window: &mut Window,
22739        cx: &mut Context<Editor>,
22740    ) {
22741        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22742            && !self.mode.is_minimap()
22743            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22744        {
22745            let buffer_snapshot = OnceCell::new();
22746
22747            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22748                && !folds.is_empty()
22749            {
22750                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22751                self.fold_ranges(
22752                    folds
22753                        .into_iter()
22754                        .map(|(start, end)| {
22755                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22756                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22757                        })
22758                        .collect(),
22759                    false,
22760                    window,
22761                    cx,
22762                );
22763            }
22764
22765            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22766                && !selections.is_empty()
22767            {
22768                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22769                // skip adding the initial selection to selection history
22770                self.selection_history.mode = SelectionHistoryMode::Skipping;
22771                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22772                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22773                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22774                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22775                    }));
22776                });
22777                self.selection_history.mode = SelectionHistoryMode::Normal;
22778            };
22779        }
22780
22781        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22782    }
22783
22784    fn update_lsp_data(
22785        &mut self,
22786        for_buffer: Option<BufferId>,
22787        window: &mut Window,
22788        cx: &mut Context<'_, Self>,
22789    ) {
22790        self.pull_diagnostics(for_buffer, window, cx);
22791        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22792    }
22793
22794    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22795        if self.ignore_lsp_data() {
22796            return;
22797        }
22798        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22799            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22800        }
22801    }
22802
22803    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22804        if self.ignore_lsp_data() {
22805            return;
22806        }
22807
22808        if !self.registered_buffers.contains_key(&buffer_id)
22809            && let Some(project) = self.project.as_ref()
22810        {
22811            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22812                project.update(cx, |project, cx| {
22813                    self.registered_buffers.insert(
22814                        buffer_id,
22815                        project.register_buffer_with_language_servers(&buffer, cx),
22816                    );
22817                });
22818            } else {
22819                self.registered_buffers.remove(&buffer_id);
22820            }
22821        }
22822    }
22823
22824    fn ignore_lsp_data(&self) -> bool {
22825        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22826        // skip any LSP updates for it.
22827        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22828    }
22829}
22830
22831fn edit_for_markdown_paste<'a>(
22832    buffer: &MultiBufferSnapshot,
22833    range: Range<MultiBufferOffset>,
22834    to_insert: &'a str,
22835    url: Option<url::Url>,
22836) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22837    if url.is_none() {
22838        return (range, Cow::Borrowed(to_insert));
22839    };
22840
22841    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22842
22843    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22844        Cow::Borrowed(to_insert)
22845    } else {
22846        Cow::Owned(format!("[{old_text}]({to_insert})"))
22847    };
22848    (range, new_text)
22849}
22850
22851fn process_completion_for_edit(
22852    completion: &Completion,
22853    intent: CompletionIntent,
22854    buffer: &Entity<Buffer>,
22855    cursor_position: &text::Anchor,
22856    cx: &mut Context<Editor>,
22857) -> CompletionEdit {
22858    let buffer = buffer.read(cx);
22859    let buffer_snapshot = buffer.snapshot();
22860    let (snippet, new_text) = if completion.is_snippet() {
22861        let mut snippet_source = completion.new_text.clone();
22862        // Workaround for typescript language server issues so that methods don't expand within
22863        // strings and functions with type expressions. The previous point is used because the query
22864        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22865        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22866        let previous_point = if previous_point.column > 0 {
22867            cursor_position.to_previous_offset(&buffer_snapshot)
22868        } else {
22869            cursor_position.to_offset(&buffer_snapshot)
22870        };
22871        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22872            && scope.prefers_label_for_snippet_in_completion()
22873            && let Some(label) = completion.label()
22874            && matches!(
22875                completion.kind(),
22876                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22877            )
22878        {
22879            snippet_source = label;
22880        }
22881        match Snippet::parse(&snippet_source).log_err() {
22882            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22883            None => (None, completion.new_text.clone()),
22884        }
22885    } else {
22886        (None, completion.new_text.clone())
22887    };
22888
22889    let mut range_to_replace = {
22890        let replace_range = &completion.replace_range;
22891        if let CompletionSource::Lsp {
22892            insert_range: Some(insert_range),
22893            ..
22894        } = &completion.source
22895        {
22896            debug_assert_eq!(
22897                insert_range.start, replace_range.start,
22898                "insert_range and replace_range should start at the same position"
22899            );
22900            debug_assert!(
22901                insert_range
22902                    .start
22903                    .cmp(cursor_position, &buffer_snapshot)
22904                    .is_le(),
22905                "insert_range should start before or at cursor position"
22906            );
22907            debug_assert!(
22908                replace_range
22909                    .start
22910                    .cmp(cursor_position, &buffer_snapshot)
22911                    .is_le(),
22912                "replace_range should start before or at cursor position"
22913            );
22914
22915            let should_replace = match intent {
22916                CompletionIntent::CompleteWithInsert => false,
22917                CompletionIntent::CompleteWithReplace => true,
22918                CompletionIntent::Complete | CompletionIntent::Compose => {
22919                    let insert_mode =
22920                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22921                            .completions
22922                            .lsp_insert_mode;
22923                    match insert_mode {
22924                        LspInsertMode::Insert => false,
22925                        LspInsertMode::Replace => true,
22926                        LspInsertMode::ReplaceSubsequence => {
22927                            let mut text_to_replace = buffer.chars_for_range(
22928                                buffer.anchor_before(replace_range.start)
22929                                    ..buffer.anchor_after(replace_range.end),
22930                            );
22931                            let mut current_needle = text_to_replace.next();
22932                            for haystack_ch in completion.label.text.chars() {
22933                                if let Some(needle_ch) = current_needle
22934                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22935                                {
22936                                    current_needle = text_to_replace.next();
22937                                }
22938                            }
22939                            current_needle.is_none()
22940                        }
22941                        LspInsertMode::ReplaceSuffix => {
22942                            if replace_range
22943                                .end
22944                                .cmp(cursor_position, &buffer_snapshot)
22945                                .is_gt()
22946                            {
22947                                let range_after_cursor = *cursor_position..replace_range.end;
22948                                let text_after_cursor = buffer
22949                                    .text_for_range(
22950                                        buffer.anchor_before(range_after_cursor.start)
22951                                            ..buffer.anchor_after(range_after_cursor.end),
22952                                    )
22953                                    .collect::<String>()
22954                                    .to_ascii_lowercase();
22955                                completion
22956                                    .label
22957                                    .text
22958                                    .to_ascii_lowercase()
22959                                    .ends_with(&text_after_cursor)
22960                            } else {
22961                                true
22962                            }
22963                        }
22964                    }
22965                }
22966            };
22967
22968            if should_replace {
22969                replace_range.clone()
22970            } else {
22971                insert_range.clone()
22972            }
22973        } else {
22974            replace_range.clone()
22975        }
22976    };
22977
22978    if range_to_replace
22979        .end
22980        .cmp(cursor_position, &buffer_snapshot)
22981        .is_lt()
22982    {
22983        range_to_replace.end = *cursor_position;
22984    }
22985
22986    let replace_range = range_to_replace.to_offset(buffer);
22987    CompletionEdit {
22988        new_text,
22989        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22990        snippet,
22991    }
22992}
22993
22994struct CompletionEdit {
22995    new_text: String,
22996    replace_range: Range<BufferOffset>,
22997    snippet: Option<Snippet>,
22998}
22999
23000fn insert_extra_newline_brackets(
23001    buffer: &MultiBufferSnapshot,
23002    range: Range<MultiBufferOffset>,
23003    language: &language::LanguageScope,
23004) -> bool {
23005    let leading_whitespace_len = buffer
23006        .reversed_chars_at(range.start)
23007        .take_while(|c| c.is_whitespace() && *c != '\n')
23008        .map(|c| c.len_utf8())
23009        .sum::<usize>();
23010    let trailing_whitespace_len = buffer
23011        .chars_at(range.end)
23012        .take_while(|c| c.is_whitespace() && *c != '\n')
23013        .map(|c| c.len_utf8())
23014        .sum::<usize>();
23015    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23016
23017    language.brackets().any(|(pair, enabled)| {
23018        let pair_start = pair.start.trim_end();
23019        let pair_end = pair.end.trim_start();
23020
23021        enabled
23022            && pair.newline
23023            && buffer.contains_str_at(range.end, pair_end)
23024            && buffer.contains_str_at(
23025                range.start.saturating_sub_usize(pair_start.len()),
23026                pair_start,
23027            )
23028    })
23029}
23030
23031fn insert_extra_newline_tree_sitter(
23032    buffer: &MultiBufferSnapshot,
23033    range: Range<MultiBufferOffset>,
23034) -> bool {
23035    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23036        [(buffer, range, _)] => (*buffer, range.clone()),
23037        _ => return false,
23038    };
23039    let pair = {
23040        let mut result: Option<BracketMatch<usize>> = None;
23041
23042        for pair in buffer
23043            .all_bracket_ranges(range.start.0..range.end.0)
23044            .filter(move |pair| {
23045                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23046            })
23047        {
23048            let len = pair.close_range.end - pair.open_range.start;
23049
23050            if let Some(existing) = &result {
23051                let existing_len = existing.close_range.end - existing.open_range.start;
23052                if len > existing_len {
23053                    continue;
23054                }
23055            }
23056
23057            result = Some(pair);
23058        }
23059
23060        result
23061    };
23062    let Some(pair) = pair else {
23063        return false;
23064    };
23065    pair.newline_only
23066        && buffer
23067            .chars_for_range(pair.open_range.end..range.start.0)
23068            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23069            .all(|c| c.is_whitespace() && c != '\n')
23070}
23071
23072fn update_uncommitted_diff_for_buffer(
23073    editor: Entity<Editor>,
23074    project: &Entity<Project>,
23075    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23076    buffer: Entity<MultiBuffer>,
23077    cx: &mut App,
23078) -> Task<()> {
23079    let mut tasks = Vec::new();
23080    project.update(cx, |project, cx| {
23081        for buffer in buffers {
23082            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23083                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23084            }
23085        }
23086    });
23087    cx.spawn(async move |cx| {
23088        let diffs = future::join_all(tasks).await;
23089        if editor
23090            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23091            .unwrap_or(false)
23092        {
23093            return;
23094        }
23095
23096        buffer
23097            .update(cx, |buffer, cx| {
23098                for diff in diffs.into_iter().flatten() {
23099                    buffer.add_diff(diff, cx);
23100                }
23101            })
23102            .ok();
23103    })
23104}
23105
23106fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23107    let tab_size = tab_size.get() as usize;
23108    let mut width = offset;
23109
23110    for ch in text.chars() {
23111        width += if ch == '\t' {
23112            tab_size - (width % tab_size)
23113        } else {
23114            1
23115        };
23116    }
23117
23118    width - offset
23119}
23120
23121#[cfg(test)]
23122mod tests {
23123    use super::*;
23124
23125    #[test]
23126    fn test_string_size_with_expanded_tabs() {
23127        let nz = |val| NonZeroU32::new(val).unwrap();
23128        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23129        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23130        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23131        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23132        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23133        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23134        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23135        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23136    }
23137}
23138
23139/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23140struct WordBreakingTokenizer<'a> {
23141    input: &'a str,
23142}
23143
23144impl<'a> WordBreakingTokenizer<'a> {
23145    fn new(input: &'a str) -> Self {
23146        Self { input }
23147    }
23148}
23149
23150fn is_char_ideographic(ch: char) -> bool {
23151    use unicode_script::Script::*;
23152    use unicode_script::UnicodeScript;
23153    matches!(ch.script(), Han | Tangut | Yi)
23154}
23155
23156fn is_grapheme_ideographic(text: &str) -> bool {
23157    text.chars().any(is_char_ideographic)
23158}
23159
23160fn is_grapheme_whitespace(text: &str) -> bool {
23161    text.chars().any(|x| x.is_whitespace())
23162}
23163
23164fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23165    text.chars()
23166        .next()
23167        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23168}
23169
23170#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23171enum WordBreakToken<'a> {
23172    Word { token: &'a str, grapheme_len: usize },
23173    InlineWhitespace { token: &'a str, grapheme_len: usize },
23174    Newline,
23175}
23176
23177impl<'a> Iterator for WordBreakingTokenizer<'a> {
23178    /// Yields a span, the count of graphemes in the token, and whether it was
23179    /// whitespace. Note that it also breaks at word boundaries.
23180    type Item = WordBreakToken<'a>;
23181
23182    fn next(&mut self) -> Option<Self::Item> {
23183        use unicode_segmentation::UnicodeSegmentation;
23184        if self.input.is_empty() {
23185            return None;
23186        }
23187
23188        let mut iter = self.input.graphemes(true).peekable();
23189        let mut offset = 0;
23190        let mut grapheme_len = 0;
23191        if let Some(first_grapheme) = iter.next() {
23192            let is_newline = first_grapheme == "\n";
23193            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23194            offset += first_grapheme.len();
23195            grapheme_len += 1;
23196            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23197                if let Some(grapheme) = iter.peek().copied()
23198                    && should_stay_with_preceding_ideograph(grapheme)
23199                {
23200                    offset += grapheme.len();
23201                    grapheme_len += 1;
23202                }
23203            } else {
23204                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23205                let mut next_word_bound = words.peek().copied();
23206                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23207                    next_word_bound = words.next();
23208                }
23209                while let Some(grapheme) = iter.peek().copied() {
23210                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23211                        break;
23212                    };
23213                    if is_grapheme_whitespace(grapheme) != is_whitespace
23214                        || (grapheme == "\n") != is_newline
23215                    {
23216                        break;
23217                    };
23218                    offset += grapheme.len();
23219                    grapheme_len += 1;
23220                    iter.next();
23221                }
23222            }
23223            let token = &self.input[..offset];
23224            self.input = &self.input[offset..];
23225            if token == "\n" {
23226                Some(WordBreakToken::Newline)
23227            } else if is_whitespace {
23228                Some(WordBreakToken::InlineWhitespace {
23229                    token,
23230                    grapheme_len,
23231                })
23232            } else {
23233                Some(WordBreakToken::Word {
23234                    token,
23235                    grapheme_len,
23236                })
23237            }
23238        } else {
23239            None
23240        }
23241    }
23242}
23243
23244#[test]
23245fn test_word_breaking_tokenizer() {
23246    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23247        ("", &[]),
23248        ("  ", &[whitespace("  ", 2)]),
23249        ("Ʒ", &[word("Ʒ", 1)]),
23250        ("Ǽ", &[word("Ǽ", 1)]),
23251        ("", &[word("", 1)]),
23252        ("⋑⋑", &[word("⋑⋑", 2)]),
23253        (
23254            "原理,进而",
23255            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23256        ),
23257        (
23258            "hello world",
23259            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23260        ),
23261        (
23262            "hello, world",
23263            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23264        ),
23265        (
23266            "  hello world",
23267            &[
23268                whitespace("  ", 2),
23269                word("hello", 5),
23270                whitespace(" ", 1),
23271                word("world", 5),
23272            ],
23273        ),
23274        (
23275            "这是什么 \n 钢笔",
23276            &[
23277                word("", 1),
23278                word("", 1),
23279                word("", 1),
23280                word("", 1),
23281                whitespace(" ", 1),
23282                newline(),
23283                whitespace(" ", 1),
23284                word("", 1),
23285                word("", 1),
23286            ],
23287        ),
23288        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23289    ];
23290
23291    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23292        WordBreakToken::Word {
23293            token,
23294            grapheme_len,
23295        }
23296    }
23297
23298    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23299        WordBreakToken::InlineWhitespace {
23300            token,
23301            grapheme_len,
23302        }
23303    }
23304
23305    fn newline() -> WordBreakToken<'static> {
23306        WordBreakToken::Newline
23307    }
23308
23309    for (input, result) in tests {
23310        assert_eq!(
23311            WordBreakingTokenizer::new(input)
23312                .collect::<Vec<_>>()
23313                .as_slice(),
23314            *result,
23315        );
23316    }
23317}
23318
23319fn wrap_with_prefix(
23320    first_line_prefix: String,
23321    subsequent_lines_prefix: String,
23322    unwrapped_text: String,
23323    wrap_column: usize,
23324    tab_size: NonZeroU32,
23325    preserve_existing_whitespace: bool,
23326) -> String {
23327    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23328    let subsequent_lines_prefix_len =
23329        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23330    let mut wrapped_text = String::new();
23331    let mut current_line = first_line_prefix;
23332    let mut is_first_line = true;
23333
23334    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23335    let mut current_line_len = first_line_prefix_len;
23336    let mut in_whitespace = false;
23337    for token in tokenizer {
23338        let have_preceding_whitespace = in_whitespace;
23339        match token {
23340            WordBreakToken::Word {
23341                token,
23342                grapheme_len,
23343            } => {
23344                in_whitespace = false;
23345                let current_prefix_len = if is_first_line {
23346                    first_line_prefix_len
23347                } else {
23348                    subsequent_lines_prefix_len
23349                };
23350                if current_line_len + grapheme_len > wrap_column
23351                    && current_line_len != current_prefix_len
23352                {
23353                    wrapped_text.push_str(current_line.trim_end());
23354                    wrapped_text.push('\n');
23355                    is_first_line = false;
23356                    current_line = subsequent_lines_prefix.clone();
23357                    current_line_len = subsequent_lines_prefix_len;
23358                }
23359                current_line.push_str(token);
23360                current_line_len += grapheme_len;
23361            }
23362            WordBreakToken::InlineWhitespace {
23363                mut token,
23364                mut grapheme_len,
23365            } => {
23366                in_whitespace = true;
23367                if have_preceding_whitespace && !preserve_existing_whitespace {
23368                    continue;
23369                }
23370                if !preserve_existing_whitespace {
23371                    // Keep a single whitespace grapheme as-is
23372                    if let Some(first) =
23373                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23374                    {
23375                        token = first;
23376                    } else {
23377                        token = " ";
23378                    }
23379                    grapheme_len = 1;
23380                }
23381                let current_prefix_len = if is_first_line {
23382                    first_line_prefix_len
23383                } else {
23384                    subsequent_lines_prefix_len
23385                };
23386                if current_line_len + grapheme_len > wrap_column {
23387                    wrapped_text.push_str(current_line.trim_end());
23388                    wrapped_text.push('\n');
23389                    is_first_line = false;
23390                    current_line = subsequent_lines_prefix.clone();
23391                    current_line_len = subsequent_lines_prefix_len;
23392                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23393                    current_line.push_str(token);
23394                    current_line_len += grapheme_len;
23395                }
23396            }
23397            WordBreakToken::Newline => {
23398                in_whitespace = true;
23399                let current_prefix_len = if is_first_line {
23400                    first_line_prefix_len
23401                } else {
23402                    subsequent_lines_prefix_len
23403                };
23404                if preserve_existing_whitespace {
23405                    wrapped_text.push_str(current_line.trim_end());
23406                    wrapped_text.push('\n');
23407                    is_first_line = false;
23408                    current_line = subsequent_lines_prefix.clone();
23409                    current_line_len = subsequent_lines_prefix_len;
23410                } else if have_preceding_whitespace {
23411                    continue;
23412                } else if current_line_len + 1 > wrap_column
23413                    && current_line_len != current_prefix_len
23414                {
23415                    wrapped_text.push_str(current_line.trim_end());
23416                    wrapped_text.push('\n');
23417                    is_first_line = false;
23418                    current_line = subsequent_lines_prefix.clone();
23419                    current_line_len = subsequent_lines_prefix_len;
23420                } else if current_line_len != current_prefix_len {
23421                    current_line.push(' ');
23422                    current_line_len += 1;
23423                }
23424            }
23425        }
23426    }
23427
23428    if !current_line.is_empty() {
23429        wrapped_text.push_str(&current_line);
23430    }
23431    wrapped_text
23432}
23433
23434#[test]
23435fn test_wrap_with_prefix() {
23436    assert_eq!(
23437        wrap_with_prefix(
23438            "# ".to_string(),
23439            "# ".to_string(),
23440            "abcdefg".to_string(),
23441            4,
23442            NonZeroU32::new(4).unwrap(),
23443            false,
23444        ),
23445        "# abcdefg"
23446    );
23447    assert_eq!(
23448        wrap_with_prefix(
23449            "".to_string(),
23450            "".to_string(),
23451            "\thello world".to_string(),
23452            8,
23453            NonZeroU32::new(4).unwrap(),
23454            false,
23455        ),
23456        "hello\nworld"
23457    );
23458    assert_eq!(
23459        wrap_with_prefix(
23460            "// ".to_string(),
23461            "// ".to_string(),
23462            "xx \nyy zz aa bb cc".to_string(),
23463            12,
23464            NonZeroU32::new(4).unwrap(),
23465            false,
23466        ),
23467        "// xx yy zz\n// aa bb cc"
23468    );
23469    assert_eq!(
23470        wrap_with_prefix(
23471            String::new(),
23472            String::new(),
23473            "这是什么 \n 钢笔".to_string(),
23474            3,
23475            NonZeroU32::new(4).unwrap(),
23476            false,
23477        ),
23478        "这是什\n么 钢\n"
23479    );
23480    assert_eq!(
23481        wrap_with_prefix(
23482            String::new(),
23483            String::new(),
23484            format!("foo{}bar", '\u{2009}'), // thin space
23485            80,
23486            NonZeroU32::new(4).unwrap(),
23487            false,
23488        ),
23489        format!("foo{}bar", '\u{2009}')
23490    );
23491}
23492
23493pub trait CollaborationHub {
23494    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23495    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23496    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23497}
23498
23499impl CollaborationHub for Entity<Project> {
23500    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23501        self.read(cx).collaborators()
23502    }
23503
23504    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23505        self.read(cx).user_store().read(cx).participant_indices()
23506    }
23507
23508    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23509        let this = self.read(cx);
23510        let user_ids = this.collaborators().values().map(|c| c.user_id);
23511        this.user_store().read(cx).participant_names(user_ids, cx)
23512    }
23513}
23514
23515pub trait SemanticsProvider {
23516    fn hover(
23517        &self,
23518        buffer: &Entity<Buffer>,
23519        position: text::Anchor,
23520        cx: &mut App,
23521    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23522
23523    fn inline_values(
23524        &self,
23525        buffer_handle: Entity<Buffer>,
23526        range: Range<text::Anchor>,
23527        cx: &mut App,
23528    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23529
23530    fn applicable_inlay_chunks(
23531        &self,
23532        buffer: &Entity<Buffer>,
23533        ranges: &[Range<text::Anchor>],
23534        cx: &mut App,
23535    ) -> Vec<Range<BufferRow>>;
23536
23537    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23538
23539    fn inlay_hints(
23540        &self,
23541        invalidate: InvalidationStrategy,
23542        buffer: Entity<Buffer>,
23543        ranges: Vec<Range<text::Anchor>>,
23544        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23545        cx: &mut App,
23546    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23547
23548    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23549
23550    fn document_highlights(
23551        &self,
23552        buffer: &Entity<Buffer>,
23553        position: text::Anchor,
23554        cx: &mut App,
23555    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23556
23557    fn definitions(
23558        &self,
23559        buffer: &Entity<Buffer>,
23560        position: text::Anchor,
23561        kind: GotoDefinitionKind,
23562        cx: &mut App,
23563    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23564
23565    fn range_for_rename(
23566        &self,
23567        buffer: &Entity<Buffer>,
23568        position: text::Anchor,
23569        cx: &mut App,
23570    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23571
23572    fn perform_rename(
23573        &self,
23574        buffer: &Entity<Buffer>,
23575        position: text::Anchor,
23576        new_name: String,
23577        cx: &mut App,
23578    ) -> Option<Task<Result<ProjectTransaction>>>;
23579}
23580
23581pub trait CompletionProvider {
23582    fn completions(
23583        &self,
23584        excerpt_id: ExcerptId,
23585        buffer: &Entity<Buffer>,
23586        buffer_position: text::Anchor,
23587        trigger: CompletionContext,
23588        window: &mut Window,
23589        cx: &mut Context<Editor>,
23590    ) -> Task<Result<Vec<CompletionResponse>>>;
23591
23592    fn resolve_completions(
23593        &self,
23594        _buffer: Entity<Buffer>,
23595        _completion_indices: Vec<usize>,
23596        _completions: Rc<RefCell<Box<[Completion]>>>,
23597        _cx: &mut Context<Editor>,
23598    ) -> Task<Result<bool>> {
23599        Task::ready(Ok(false))
23600    }
23601
23602    fn apply_additional_edits_for_completion(
23603        &self,
23604        _buffer: Entity<Buffer>,
23605        _completions: Rc<RefCell<Box<[Completion]>>>,
23606        _completion_index: usize,
23607        _push_to_history: bool,
23608        _cx: &mut Context<Editor>,
23609    ) -> Task<Result<Option<language::Transaction>>> {
23610        Task::ready(Ok(None))
23611    }
23612
23613    fn is_completion_trigger(
23614        &self,
23615        buffer: &Entity<Buffer>,
23616        position: language::Anchor,
23617        text: &str,
23618        trigger_in_words: bool,
23619        cx: &mut Context<Editor>,
23620    ) -> bool;
23621
23622    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23623
23624    fn sort_completions(&self) -> bool {
23625        true
23626    }
23627
23628    fn filter_completions(&self) -> bool {
23629        true
23630    }
23631
23632    fn show_snippets(&self) -> bool {
23633        false
23634    }
23635}
23636
23637pub trait CodeActionProvider {
23638    fn id(&self) -> Arc<str>;
23639
23640    fn code_actions(
23641        &self,
23642        buffer: &Entity<Buffer>,
23643        range: Range<text::Anchor>,
23644        window: &mut Window,
23645        cx: &mut App,
23646    ) -> Task<Result<Vec<CodeAction>>>;
23647
23648    fn apply_code_action(
23649        &self,
23650        buffer_handle: Entity<Buffer>,
23651        action: CodeAction,
23652        excerpt_id: ExcerptId,
23653        push_to_history: bool,
23654        window: &mut Window,
23655        cx: &mut App,
23656    ) -> Task<Result<ProjectTransaction>>;
23657}
23658
23659impl CodeActionProvider for Entity<Project> {
23660    fn id(&self) -> Arc<str> {
23661        "project".into()
23662    }
23663
23664    fn code_actions(
23665        &self,
23666        buffer: &Entity<Buffer>,
23667        range: Range<text::Anchor>,
23668        _window: &mut Window,
23669        cx: &mut App,
23670    ) -> Task<Result<Vec<CodeAction>>> {
23671        self.update(cx, |project, cx| {
23672            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23673            let code_actions = project.code_actions(buffer, range, None, cx);
23674            cx.background_spawn(async move {
23675                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23676                Ok(code_lens_actions
23677                    .context("code lens fetch")?
23678                    .into_iter()
23679                    .flatten()
23680                    .chain(
23681                        code_actions
23682                            .context("code action fetch")?
23683                            .into_iter()
23684                            .flatten(),
23685                    )
23686                    .collect())
23687            })
23688        })
23689    }
23690
23691    fn apply_code_action(
23692        &self,
23693        buffer_handle: Entity<Buffer>,
23694        action: CodeAction,
23695        _excerpt_id: ExcerptId,
23696        push_to_history: bool,
23697        _window: &mut Window,
23698        cx: &mut App,
23699    ) -> Task<Result<ProjectTransaction>> {
23700        self.update(cx, |project, cx| {
23701            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23702        })
23703    }
23704}
23705
23706fn snippet_completions(
23707    project: &Project,
23708    buffer: &Entity<Buffer>,
23709    buffer_anchor: text::Anchor,
23710    classifier: CharClassifier,
23711    cx: &mut App,
23712) -> Task<Result<CompletionResponse>> {
23713    let languages = buffer.read(cx).languages_at(buffer_anchor);
23714    let snippet_store = project.snippets().read(cx);
23715
23716    let scopes: Vec<_> = languages
23717        .iter()
23718        .filter_map(|language| {
23719            let language_name = language.lsp_id();
23720            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23721
23722            if snippets.is_empty() {
23723                None
23724            } else {
23725                Some((language.default_scope(), snippets))
23726            }
23727        })
23728        .collect();
23729
23730    if scopes.is_empty() {
23731        return Task::ready(Ok(CompletionResponse {
23732            completions: vec![],
23733            display_options: CompletionDisplayOptions::default(),
23734            is_incomplete: false,
23735        }));
23736    }
23737
23738    let snapshot = buffer.read(cx).text_snapshot();
23739    let executor = cx.background_executor().clone();
23740
23741    cx.background_spawn(async move {
23742        let is_word_char = |c| classifier.is_word(c);
23743
23744        let mut is_incomplete = false;
23745        let mut completions: Vec<Completion> = Vec::new();
23746
23747        const MAX_PREFIX_LEN: usize = 128;
23748        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23749        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23750        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23751
23752        let max_buffer_window: String = snapshot
23753            .text_for_range(window_start..buffer_offset)
23754            .collect();
23755
23756        if max_buffer_window.is_empty() {
23757            return Ok(CompletionResponse {
23758                completions: vec![],
23759                display_options: CompletionDisplayOptions::default(),
23760                is_incomplete: true,
23761            });
23762        }
23763
23764        for (_scope, snippets) in scopes.into_iter() {
23765            // Sort snippets by word count to match longer snippet prefixes first.
23766            let mut sorted_snippet_candidates = snippets
23767                .iter()
23768                .enumerate()
23769                .flat_map(|(snippet_ix, snippet)| {
23770                    snippet
23771                        .prefix
23772                        .iter()
23773                        .enumerate()
23774                        .map(move |(prefix_ix, prefix)| {
23775                            let word_count =
23776                                snippet_candidate_suffixes(prefix, is_word_char).count();
23777                            ((snippet_ix, prefix_ix), prefix, word_count)
23778                        })
23779                })
23780                .collect_vec();
23781            sorted_snippet_candidates
23782                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23783
23784            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23785
23786            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23787                .take(
23788                    sorted_snippet_candidates
23789                        .first()
23790                        .map(|(_, _, word_count)| *word_count)
23791                        .unwrap_or_default(),
23792                )
23793                .collect_vec();
23794
23795            const MAX_RESULTS: usize = 100;
23796            // Each match also remembers how many characters from the buffer it consumed
23797            let mut matches: Vec<(StringMatch, usize)> = vec![];
23798
23799            let mut snippet_list_cutoff_index = 0;
23800            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23801                let word_count = buffer_index + 1;
23802                // Increase `snippet_list_cutoff_index` until we have all of the
23803                // snippets with sufficiently many words.
23804                while sorted_snippet_candidates
23805                    .get(snippet_list_cutoff_index)
23806                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23807                        *snippet_word_count >= word_count
23808                    })
23809                {
23810                    snippet_list_cutoff_index += 1;
23811                }
23812
23813                // Take only the candidates with at least `word_count` many words
23814                let snippet_candidates_at_word_len =
23815                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23816
23817                let candidates = snippet_candidates_at_word_len
23818                    .iter()
23819                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23820                    .enumerate() // index in `sorted_snippet_candidates`
23821                    // First char must match
23822                    .filter(|(_ix, prefix)| {
23823                        itertools::equal(
23824                            prefix
23825                                .chars()
23826                                .next()
23827                                .into_iter()
23828                                .flat_map(|c| c.to_lowercase()),
23829                            buffer_window
23830                                .chars()
23831                                .next()
23832                                .into_iter()
23833                                .flat_map(|c| c.to_lowercase()),
23834                        )
23835                    })
23836                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23837                    .collect::<Vec<StringMatchCandidate>>();
23838
23839                matches.extend(
23840                    fuzzy::match_strings(
23841                        &candidates,
23842                        &buffer_window,
23843                        buffer_window.chars().any(|c| c.is_uppercase()),
23844                        true,
23845                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23846                        &Default::default(),
23847                        executor.clone(),
23848                    )
23849                    .await
23850                    .into_iter()
23851                    .map(|string_match| (string_match, buffer_window.len())),
23852                );
23853
23854                if matches.len() >= MAX_RESULTS {
23855                    break;
23856                }
23857            }
23858
23859            let to_lsp = |point: &text::Anchor| {
23860                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23861                point_to_lsp(end)
23862            };
23863            let lsp_end = to_lsp(&buffer_anchor);
23864
23865            if matches.len() >= MAX_RESULTS {
23866                is_incomplete = true;
23867            }
23868
23869            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23870                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23871                    sorted_snippet_candidates[string_match.candidate_id];
23872                let snippet = &snippets[snippet_index];
23873                let start = buffer_offset - buffer_window_len;
23874                let start = snapshot.anchor_before(start);
23875                let range = start..buffer_anchor;
23876                let lsp_start = to_lsp(&start);
23877                let lsp_range = lsp::Range {
23878                    start: lsp_start,
23879                    end: lsp_end,
23880                };
23881                Completion {
23882                    replace_range: range,
23883                    new_text: snippet.body.clone(),
23884                    source: CompletionSource::Lsp {
23885                        insert_range: None,
23886                        server_id: LanguageServerId(usize::MAX),
23887                        resolved: true,
23888                        lsp_completion: Box::new(lsp::CompletionItem {
23889                            label: snippet.prefix.first().unwrap().clone(),
23890                            kind: Some(CompletionItemKind::SNIPPET),
23891                            label_details: snippet.description.as_ref().map(|description| {
23892                                lsp::CompletionItemLabelDetails {
23893                                    detail: Some(description.clone()),
23894                                    description: None,
23895                                }
23896                            }),
23897                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23898                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23899                                lsp::InsertReplaceEdit {
23900                                    new_text: snippet.body.clone(),
23901                                    insert: lsp_range,
23902                                    replace: lsp_range,
23903                                },
23904                            )),
23905                            filter_text: Some(snippet.body.clone()),
23906                            sort_text: Some(char::MAX.to_string()),
23907                            ..lsp::CompletionItem::default()
23908                        }),
23909                        lsp_defaults: None,
23910                    },
23911                    label: CodeLabel {
23912                        text: matching_prefix.clone(),
23913                        runs: Vec::new(),
23914                        filter_range: 0..matching_prefix.len(),
23915                    },
23916                    icon_path: None,
23917                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23918                        single_line: snippet.name.clone().into(),
23919                        plain_text: snippet
23920                            .description
23921                            .clone()
23922                            .map(|description| description.into()),
23923                    }),
23924                    insert_text_mode: None,
23925                    confirm: None,
23926                    match_start: Some(start),
23927                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23928                }
23929            }));
23930        }
23931
23932        Ok(CompletionResponse {
23933            completions,
23934            display_options: CompletionDisplayOptions::default(),
23935            is_incomplete,
23936        })
23937    })
23938}
23939
23940impl CompletionProvider for Entity<Project> {
23941    fn completions(
23942        &self,
23943        _excerpt_id: ExcerptId,
23944        buffer: &Entity<Buffer>,
23945        buffer_position: text::Anchor,
23946        options: CompletionContext,
23947        _window: &mut Window,
23948        cx: &mut Context<Editor>,
23949    ) -> Task<Result<Vec<CompletionResponse>>> {
23950        self.update(cx, |project, cx| {
23951            let task = project.completions(buffer, buffer_position, options, cx);
23952            cx.background_spawn(task)
23953        })
23954    }
23955
23956    fn resolve_completions(
23957        &self,
23958        buffer: Entity<Buffer>,
23959        completion_indices: Vec<usize>,
23960        completions: Rc<RefCell<Box<[Completion]>>>,
23961        cx: &mut Context<Editor>,
23962    ) -> Task<Result<bool>> {
23963        self.update(cx, |project, cx| {
23964            project.lsp_store().update(cx, |lsp_store, cx| {
23965                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23966            })
23967        })
23968    }
23969
23970    fn apply_additional_edits_for_completion(
23971        &self,
23972        buffer: Entity<Buffer>,
23973        completions: Rc<RefCell<Box<[Completion]>>>,
23974        completion_index: usize,
23975        push_to_history: bool,
23976        cx: &mut Context<Editor>,
23977    ) -> Task<Result<Option<language::Transaction>>> {
23978        self.update(cx, |project, cx| {
23979            project.lsp_store().update(cx, |lsp_store, cx| {
23980                lsp_store.apply_additional_edits_for_completion(
23981                    buffer,
23982                    completions,
23983                    completion_index,
23984                    push_to_history,
23985                    cx,
23986                )
23987            })
23988        })
23989    }
23990
23991    fn is_completion_trigger(
23992        &self,
23993        buffer: &Entity<Buffer>,
23994        position: language::Anchor,
23995        text: &str,
23996        trigger_in_words: bool,
23997        cx: &mut Context<Editor>,
23998    ) -> bool {
23999        let mut chars = text.chars();
24000        let char = if let Some(char) = chars.next() {
24001            char
24002        } else {
24003            return false;
24004        };
24005        if chars.next().is_some() {
24006            return false;
24007        }
24008
24009        let buffer = buffer.read(cx);
24010        let snapshot = buffer.snapshot();
24011        let classifier = snapshot
24012            .char_classifier_at(position)
24013            .scope_context(Some(CharScopeContext::Completion));
24014        if trigger_in_words && classifier.is_word(char) {
24015            return true;
24016        }
24017
24018        buffer.completion_triggers().contains(text)
24019    }
24020
24021    fn show_snippets(&self) -> bool {
24022        true
24023    }
24024}
24025
24026impl SemanticsProvider for Entity<Project> {
24027    fn hover(
24028        &self,
24029        buffer: &Entity<Buffer>,
24030        position: text::Anchor,
24031        cx: &mut App,
24032    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24033        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24034    }
24035
24036    fn document_highlights(
24037        &self,
24038        buffer: &Entity<Buffer>,
24039        position: text::Anchor,
24040        cx: &mut App,
24041    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24042        Some(self.update(cx, |project, cx| {
24043            project.document_highlights(buffer, position, cx)
24044        }))
24045    }
24046
24047    fn definitions(
24048        &self,
24049        buffer: &Entity<Buffer>,
24050        position: text::Anchor,
24051        kind: GotoDefinitionKind,
24052        cx: &mut App,
24053    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24054        Some(self.update(cx, |project, cx| match kind {
24055            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24056            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24057            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24058            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24059        }))
24060    }
24061
24062    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24063        self.update(cx, |project, cx| {
24064            if project
24065                .active_debug_session(cx)
24066                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24067            {
24068                return true;
24069            }
24070
24071            buffer.update(cx, |buffer, cx| {
24072                project.any_language_server_supports_inlay_hints(buffer, cx)
24073            })
24074        })
24075    }
24076
24077    fn inline_values(
24078        &self,
24079        buffer_handle: Entity<Buffer>,
24080        range: Range<text::Anchor>,
24081        cx: &mut App,
24082    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24083        self.update(cx, |project, cx| {
24084            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24085
24086            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24087        })
24088    }
24089
24090    fn applicable_inlay_chunks(
24091        &self,
24092        buffer: &Entity<Buffer>,
24093        ranges: &[Range<text::Anchor>],
24094        cx: &mut App,
24095    ) -> Vec<Range<BufferRow>> {
24096        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24097            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24098        })
24099    }
24100
24101    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24102        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24103            lsp_store.invalidate_inlay_hints(for_buffers)
24104        });
24105    }
24106
24107    fn inlay_hints(
24108        &self,
24109        invalidate: InvalidationStrategy,
24110        buffer: Entity<Buffer>,
24111        ranges: Vec<Range<text::Anchor>>,
24112        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24113        cx: &mut App,
24114    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24115        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24116            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24117        }))
24118    }
24119
24120    fn range_for_rename(
24121        &self,
24122        buffer: &Entity<Buffer>,
24123        position: text::Anchor,
24124        cx: &mut App,
24125    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24126        Some(self.update(cx, |project, cx| {
24127            let buffer = buffer.clone();
24128            let task = project.prepare_rename(buffer.clone(), position, cx);
24129            cx.spawn(async move |_, cx| {
24130                Ok(match task.await? {
24131                    PrepareRenameResponse::Success(range) => Some(range),
24132                    PrepareRenameResponse::InvalidPosition => None,
24133                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24134                        // Fallback on using TreeSitter info to determine identifier range
24135                        buffer.read_with(cx, |buffer, _| {
24136                            let snapshot = buffer.snapshot();
24137                            let (range, kind) = snapshot.surrounding_word(position, None);
24138                            if kind != Some(CharKind::Word) {
24139                                return None;
24140                            }
24141                            Some(
24142                                snapshot.anchor_before(range.start)
24143                                    ..snapshot.anchor_after(range.end),
24144                            )
24145                        })?
24146                    }
24147                })
24148            })
24149        }))
24150    }
24151
24152    fn perform_rename(
24153        &self,
24154        buffer: &Entity<Buffer>,
24155        position: text::Anchor,
24156        new_name: String,
24157        cx: &mut App,
24158    ) -> Option<Task<Result<ProjectTransaction>>> {
24159        Some(self.update(cx, |project, cx| {
24160            project.perform_rename(buffer.clone(), position, new_name, cx)
24161        }))
24162    }
24163}
24164
24165fn consume_contiguous_rows(
24166    contiguous_row_selections: &mut Vec<Selection<Point>>,
24167    selection: &Selection<Point>,
24168    display_map: &DisplaySnapshot,
24169    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24170) -> (MultiBufferRow, MultiBufferRow) {
24171    contiguous_row_selections.push(selection.clone());
24172    let start_row = starting_row(selection, display_map);
24173    let mut end_row = ending_row(selection, display_map);
24174
24175    while let Some(next_selection) = selections.peek() {
24176        if next_selection.start.row <= end_row.0 {
24177            end_row = ending_row(next_selection, display_map);
24178            contiguous_row_selections.push(selections.next().unwrap().clone());
24179        } else {
24180            break;
24181        }
24182    }
24183    (start_row, end_row)
24184}
24185
24186fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24187    if selection.start.column > 0 {
24188        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24189    } else {
24190        MultiBufferRow(selection.start.row)
24191    }
24192}
24193
24194fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24195    if next_selection.end.column > 0 || next_selection.is_empty() {
24196        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24197    } else {
24198        MultiBufferRow(next_selection.end.row)
24199    }
24200}
24201
24202impl EditorSnapshot {
24203    pub fn remote_selections_in_range<'a>(
24204        &'a self,
24205        range: &'a Range<Anchor>,
24206        collaboration_hub: &dyn CollaborationHub,
24207        cx: &'a App,
24208    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24209        let participant_names = collaboration_hub.user_names(cx);
24210        let participant_indices = collaboration_hub.user_participant_indices(cx);
24211        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24212        let collaborators_by_replica_id = collaborators_by_peer_id
24213            .values()
24214            .map(|collaborator| (collaborator.replica_id, collaborator))
24215            .collect::<HashMap<_, _>>();
24216        self.buffer_snapshot()
24217            .selections_in_range(range, false)
24218            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24219                if replica_id == ReplicaId::AGENT {
24220                    Some(RemoteSelection {
24221                        replica_id,
24222                        selection,
24223                        cursor_shape,
24224                        line_mode,
24225                        collaborator_id: CollaboratorId::Agent,
24226                        user_name: Some("Agent".into()),
24227                        color: cx.theme().players().agent(),
24228                    })
24229                } else {
24230                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24231                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24232                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24233                    Some(RemoteSelection {
24234                        replica_id,
24235                        selection,
24236                        cursor_shape,
24237                        line_mode,
24238                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24239                        user_name,
24240                        color: if let Some(index) = participant_index {
24241                            cx.theme().players().color_for_participant(index.0)
24242                        } else {
24243                            cx.theme().players().absent()
24244                        },
24245                    })
24246                }
24247            })
24248    }
24249
24250    pub fn hunks_for_ranges(
24251        &self,
24252        ranges: impl IntoIterator<Item = Range<Point>>,
24253    ) -> Vec<MultiBufferDiffHunk> {
24254        let mut hunks = Vec::new();
24255        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24256            HashMap::default();
24257        for query_range in ranges {
24258            let query_rows =
24259                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24260            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24261                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24262            ) {
24263                // Include deleted hunks that are adjacent to the query range, because
24264                // otherwise they would be missed.
24265                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24266                if hunk.status().is_deleted() {
24267                    intersects_range |= hunk.row_range.start == query_rows.end;
24268                    intersects_range |= hunk.row_range.end == query_rows.start;
24269                }
24270                if intersects_range {
24271                    if !processed_buffer_rows
24272                        .entry(hunk.buffer_id)
24273                        .or_default()
24274                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24275                    {
24276                        continue;
24277                    }
24278                    hunks.push(hunk);
24279                }
24280            }
24281        }
24282
24283        hunks
24284    }
24285
24286    fn display_diff_hunks_for_rows<'a>(
24287        &'a self,
24288        display_rows: Range<DisplayRow>,
24289        folded_buffers: &'a HashSet<BufferId>,
24290    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24291        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24292        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24293
24294        self.buffer_snapshot()
24295            .diff_hunks_in_range(buffer_start..buffer_end)
24296            .filter_map(|hunk| {
24297                if folded_buffers.contains(&hunk.buffer_id) {
24298                    return None;
24299                }
24300
24301                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24302                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24303
24304                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24305                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24306
24307                let display_hunk = if hunk_display_start.column() != 0 {
24308                    DisplayDiffHunk::Folded {
24309                        display_row: hunk_display_start.row(),
24310                    }
24311                } else {
24312                    let mut end_row = hunk_display_end.row();
24313                    if hunk_display_end.column() > 0 {
24314                        end_row.0 += 1;
24315                    }
24316                    let is_created_file = hunk.is_created_file();
24317
24318                    DisplayDiffHunk::Unfolded {
24319                        status: hunk.status(),
24320                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24321                            ..hunk.diff_base_byte_range.end.0,
24322                        word_diffs: hunk.word_diffs,
24323                        display_row_range: hunk_display_start.row()..end_row,
24324                        multi_buffer_range: Anchor::range_in_buffer(
24325                            hunk.excerpt_id,
24326                            hunk.buffer_range,
24327                        ),
24328                        is_created_file,
24329                    }
24330                };
24331
24332                Some(display_hunk)
24333            })
24334    }
24335
24336    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24337        self.display_snapshot
24338            .buffer_snapshot()
24339            .language_at(position)
24340    }
24341
24342    pub fn is_focused(&self) -> bool {
24343        self.is_focused
24344    }
24345
24346    pub fn placeholder_text(&self) -> Option<String> {
24347        self.placeholder_display_snapshot
24348            .as_ref()
24349            .map(|display_map| display_map.text())
24350    }
24351
24352    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24353        self.scroll_anchor.scroll_position(&self.display_snapshot)
24354    }
24355
24356    fn gutter_dimensions(
24357        &self,
24358        font_id: FontId,
24359        font_size: Pixels,
24360        max_line_number_width: Pixels,
24361        cx: &App,
24362    ) -> Option<GutterDimensions> {
24363        if !self.show_gutter {
24364            return None;
24365        }
24366
24367        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24368        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24369
24370        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24371            matches!(
24372                ProjectSettings::get_global(cx).git.git_gutter,
24373                GitGutterSetting::TrackedFiles
24374            )
24375        });
24376        let gutter_settings = EditorSettings::get_global(cx).gutter;
24377        let show_line_numbers = self
24378            .show_line_numbers
24379            .unwrap_or(gutter_settings.line_numbers);
24380        let line_gutter_width = if show_line_numbers {
24381            // Avoid flicker-like gutter resizes when the line number gains another digit by
24382            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24383            let min_width_for_number_on_gutter =
24384                ch_advance * gutter_settings.min_line_number_digits as f32;
24385            max_line_number_width.max(min_width_for_number_on_gutter)
24386        } else {
24387            0.0.into()
24388        };
24389
24390        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24391        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24392
24393        let git_blame_entries_width =
24394            self.git_blame_gutter_max_author_length
24395                .map(|max_author_length| {
24396                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24397                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24398
24399                    /// The number of characters to dedicate to gaps and margins.
24400                    const SPACING_WIDTH: usize = 4;
24401
24402                    let max_char_count = max_author_length.min(renderer.max_author_length())
24403                        + ::git::SHORT_SHA_LENGTH
24404                        + MAX_RELATIVE_TIMESTAMP.len()
24405                        + SPACING_WIDTH;
24406
24407                    ch_advance * max_char_count
24408                });
24409
24410        let is_singleton = self.buffer_snapshot().is_singleton();
24411
24412        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24413        left_padding += if !is_singleton {
24414            ch_width * 4.0
24415        } else if show_runnables || show_breakpoints {
24416            ch_width * 3.0
24417        } else if show_git_gutter && show_line_numbers {
24418            ch_width * 2.0
24419        } else if show_git_gutter || show_line_numbers {
24420            ch_width
24421        } else {
24422            px(0.)
24423        };
24424
24425        let shows_folds = is_singleton && gutter_settings.folds;
24426
24427        let right_padding = if shows_folds && show_line_numbers {
24428            ch_width * 4.0
24429        } else if shows_folds || (!is_singleton && show_line_numbers) {
24430            ch_width * 3.0
24431        } else if show_line_numbers {
24432            ch_width
24433        } else {
24434            px(0.)
24435        };
24436
24437        Some(GutterDimensions {
24438            left_padding,
24439            right_padding,
24440            width: line_gutter_width + left_padding + right_padding,
24441            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24442            git_blame_entries_width,
24443        })
24444    }
24445
24446    pub fn render_crease_toggle(
24447        &self,
24448        buffer_row: MultiBufferRow,
24449        row_contains_cursor: bool,
24450        editor: Entity<Editor>,
24451        window: &mut Window,
24452        cx: &mut App,
24453    ) -> Option<AnyElement> {
24454        let folded = self.is_line_folded(buffer_row);
24455        let mut is_foldable = false;
24456
24457        if let Some(crease) = self
24458            .crease_snapshot
24459            .query_row(buffer_row, self.buffer_snapshot())
24460        {
24461            is_foldable = true;
24462            match crease {
24463                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24464                    if let Some(render_toggle) = render_toggle {
24465                        let toggle_callback =
24466                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24467                                if folded {
24468                                    editor.update(cx, |editor, cx| {
24469                                        editor.fold_at(buffer_row, window, cx)
24470                                    });
24471                                } else {
24472                                    editor.update(cx, |editor, cx| {
24473                                        editor.unfold_at(buffer_row, window, cx)
24474                                    });
24475                                }
24476                            });
24477                        return Some((render_toggle)(
24478                            buffer_row,
24479                            folded,
24480                            toggle_callback,
24481                            window,
24482                            cx,
24483                        ));
24484                    }
24485                }
24486            }
24487        }
24488
24489        is_foldable |= self.starts_indent(buffer_row);
24490
24491        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24492            Some(
24493                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24494                    .toggle_state(folded)
24495                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24496                        if folded {
24497                            this.unfold_at(buffer_row, window, cx);
24498                        } else {
24499                            this.fold_at(buffer_row, window, cx);
24500                        }
24501                    }))
24502                    .into_any_element(),
24503            )
24504        } else {
24505            None
24506        }
24507    }
24508
24509    pub fn render_crease_trailer(
24510        &self,
24511        buffer_row: MultiBufferRow,
24512        window: &mut Window,
24513        cx: &mut App,
24514    ) -> Option<AnyElement> {
24515        let folded = self.is_line_folded(buffer_row);
24516        if let Crease::Inline { render_trailer, .. } = self
24517            .crease_snapshot
24518            .query_row(buffer_row, self.buffer_snapshot())?
24519        {
24520            let render_trailer = render_trailer.as_ref()?;
24521            Some(render_trailer(buffer_row, folded, window, cx))
24522        } else {
24523            None
24524        }
24525    }
24526}
24527
24528impl Deref for EditorSnapshot {
24529    type Target = DisplaySnapshot;
24530
24531    fn deref(&self) -> &Self::Target {
24532        &self.display_snapshot
24533    }
24534}
24535
24536#[derive(Clone, Debug, PartialEq, Eq)]
24537pub enum EditorEvent {
24538    InputIgnored {
24539        text: Arc<str>,
24540    },
24541    InputHandled {
24542        utf16_range_to_replace: Option<Range<isize>>,
24543        text: Arc<str>,
24544    },
24545    ExcerptsAdded {
24546        buffer: Entity<Buffer>,
24547        predecessor: ExcerptId,
24548        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24549    },
24550    ExcerptsRemoved {
24551        ids: Vec<ExcerptId>,
24552        removed_buffer_ids: Vec<BufferId>,
24553    },
24554    BufferFoldToggled {
24555        ids: Vec<ExcerptId>,
24556        folded: bool,
24557    },
24558    ExcerptsEdited {
24559        ids: Vec<ExcerptId>,
24560    },
24561    ExcerptsExpanded {
24562        ids: Vec<ExcerptId>,
24563    },
24564    BufferEdited,
24565    Edited {
24566        transaction_id: clock::Lamport,
24567    },
24568    Reparsed(BufferId),
24569    Focused,
24570    FocusedIn,
24571    Blurred,
24572    DirtyChanged,
24573    Saved,
24574    TitleChanged,
24575    SelectionsChanged {
24576        local: bool,
24577    },
24578    ScrollPositionChanged {
24579        local: bool,
24580        autoscroll: bool,
24581    },
24582    TransactionUndone {
24583        transaction_id: clock::Lamport,
24584    },
24585    TransactionBegun {
24586        transaction_id: clock::Lamport,
24587    },
24588    CursorShapeChanged,
24589    BreadcrumbsChanged,
24590    PushedToNavHistory {
24591        anchor: Anchor,
24592        is_deactivate: bool,
24593    },
24594}
24595
24596impl EventEmitter<EditorEvent> for Editor {}
24597
24598impl Focusable for Editor {
24599    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24600        self.focus_handle.clone()
24601    }
24602}
24603
24604impl Render for Editor {
24605    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24606        let settings = ThemeSettings::get_global(cx);
24607
24608        let mut text_style = match self.mode {
24609            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24610                color: cx.theme().colors().editor_foreground,
24611                font_family: settings.ui_font.family.clone(),
24612                font_features: settings.ui_font.features.clone(),
24613                font_fallbacks: settings.ui_font.fallbacks.clone(),
24614                font_size: rems(0.875).into(),
24615                font_weight: settings.ui_font.weight,
24616                line_height: relative(settings.buffer_line_height.value()),
24617                ..Default::default()
24618            },
24619            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24620                color: cx.theme().colors().editor_foreground,
24621                font_family: settings.buffer_font.family.clone(),
24622                font_features: settings.buffer_font.features.clone(),
24623                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24624                font_size: settings.buffer_font_size(cx).into(),
24625                font_weight: settings.buffer_font.weight,
24626                line_height: relative(settings.buffer_line_height.value()),
24627                ..Default::default()
24628            },
24629        };
24630        if let Some(text_style_refinement) = &self.text_style_refinement {
24631            text_style.refine(text_style_refinement)
24632        }
24633
24634        let background = match self.mode {
24635            EditorMode::SingleLine => cx.theme().system().transparent,
24636            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24637            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24638            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24639        };
24640
24641        EditorElement::new(
24642            &cx.entity(),
24643            EditorStyle {
24644                background,
24645                border: cx.theme().colors().border,
24646                local_player: cx.theme().players().local(),
24647                text: text_style,
24648                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24649                syntax: cx.theme().syntax().clone(),
24650                status: cx.theme().status().clone(),
24651                inlay_hints_style: make_inlay_hints_style(cx),
24652                edit_prediction_styles: make_suggestion_styles(cx),
24653                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24654                show_underlines: self.diagnostics_enabled(),
24655            },
24656        )
24657    }
24658}
24659
24660impl EntityInputHandler for Editor {
24661    fn text_for_range(
24662        &mut self,
24663        range_utf16: Range<usize>,
24664        adjusted_range: &mut Option<Range<usize>>,
24665        _: &mut Window,
24666        cx: &mut Context<Self>,
24667    ) -> Option<String> {
24668        let snapshot = self.buffer.read(cx).read(cx);
24669        let start = snapshot.clip_offset_utf16(
24670            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24671            Bias::Left,
24672        );
24673        let end = snapshot.clip_offset_utf16(
24674            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24675            Bias::Right,
24676        );
24677        if (start.0.0..end.0.0) != range_utf16 {
24678            adjusted_range.replace(start.0.0..end.0.0);
24679        }
24680        Some(snapshot.text_for_range(start..end).collect())
24681    }
24682
24683    fn selected_text_range(
24684        &mut self,
24685        ignore_disabled_input: bool,
24686        _: &mut Window,
24687        cx: &mut Context<Self>,
24688    ) -> Option<UTF16Selection> {
24689        // Prevent the IME menu from appearing when holding down an alphabetic key
24690        // while input is disabled.
24691        if !ignore_disabled_input && !self.input_enabled {
24692            return None;
24693        }
24694
24695        let selection = self
24696            .selections
24697            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24698        let range = selection.range();
24699
24700        Some(UTF16Selection {
24701            range: range.start.0.0..range.end.0.0,
24702            reversed: selection.reversed,
24703        })
24704    }
24705
24706    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24707        let snapshot = self.buffer.read(cx).read(cx);
24708        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24709        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24710    }
24711
24712    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24713        self.clear_highlights::<InputComposition>(cx);
24714        self.ime_transaction.take();
24715    }
24716
24717    fn replace_text_in_range(
24718        &mut self,
24719        range_utf16: Option<Range<usize>>,
24720        text: &str,
24721        window: &mut Window,
24722        cx: &mut Context<Self>,
24723    ) {
24724        if !self.input_enabled {
24725            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24726            return;
24727        }
24728
24729        self.transact(window, cx, |this, window, cx| {
24730            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24731                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24732                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24733                Some(this.selection_replacement_ranges(range_utf16, cx))
24734            } else {
24735                this.marked_text_ranges(cx)
24736            };
24737
24738            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24739                let newest_selection_id = this.selections.newest_anchor().id;
24740                this.selections
24741                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24742                    .iter()
24743                    .zip(ranges_to_replace.iter())
24744                    .find_map(|(selection, range)| {
24745                        if selection.id == newest_selection_id {
24746                            Some(
24747                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24748                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24749                            )
24750                        } else {
24751                            None
24752                        }
24753                    })
24754            });
24755
24756            cx.emit(EditorEvent::InputHandled {
24757                utf16_range_to_replace: range_to_replace,
24758                text: text.into(),
24759            });
24760
24761            if let Some(new_selected_ranges) = new_selected_ranges {
24762                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24763                    selections.select_ranges(new_selected_ranges)
24764                });
24765                this.backspace(&Default::default(), window, cx);
24766            }
24767
24768            this.handle_input(text, window, cx);
24769        });
24770
24771        if let Some(transaction) = self.ime_transaction {
24772            self.buffer.update(cx, |buffer, cx| {
24773                buffer.group_until_transaction(transaction, cx);
24774            });
24775        }
24776
24777        self.unmark_text(window, cx);
24778    }
24779
24780    fn replace_and_mark_text_in_range(
24781        &mut self,
24782        range_utf16: Option<Range<usize>>,
24783        text: &str,
24784        new_selected_range_utf16: Option<Range<usize>>,
24785        window: &mut Window,
24786        cx: &mut Context<Self>,
24787    ) {
24788        if !self.input_enabled {
24789            return;
24790        }
24791
24792        let transaction = self.transact(window, cx, |this, window, cx| {
24793            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24794                let snapshot = this.buffer.read(cx).read(cx);
24795                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24796                    for marked_range in &mut marked_ranges {
24797                        marked_range.end = marked_range.start + relative_range_utf16.end;
24798                        marked_range.start += relative_range_utf16.start;
24799                        marked_range.start =
24800                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24801                        marked_range.end =
24802                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24803                    }
24804                }
24805                Some(marked_ranges)
24806            } else if let Some(range_utf16) = range_utf16 {
24807                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24808                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24809                Some(this.selection_replacement_ranges(range_utf16, cx))
24810            } else {
24811                None
24812            };
24813
24814            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24815                let newest_selection_id = this.selections.newest_anchor().id;
24816                this.selections
24817                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24818                    .iter()
24819                    .zip(ranges_to_replace.iter())
24820                    .find_map(|(selection, range)| {
24821                        if selection.id == newest_selection_id {
24822                            Some(
24823                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24824                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24825                            )
24826                        } else {
24827                            None
24828                        }
24829                    })
24830            });
24831
24832            cx.emit(EditorEvent::InputHandled {
24833                utf16_range_to_replace: range_to_replace,
24834                text: text.into(),
24835            });
24836
24837            if let Some(ranges) = ranges_to_replace {
24838                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24839                    s.select_ranges(ranges)
24840                });
24841            }
24842
24843            let marked_ranges = {
24844                let snapshot = this.buffer.read(cx).read(cx);
24845                this.selections
24846                    .disjoint_anchors_arc()
24847                    .iter()
24848                    .map(|selection| {
24849                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24850                    })
24851                    .collect::<Vec<_>>()
24852            };
24853
24854            if text.is_empty() {
24855                this.unmark_text(window, cx);
24856            } else {
24857                this.highlight_text::<InputComposition>(
24858                    marked_ranges.clone(),
24859                    HighlightStyle {
24860                        underline: Some(UnderlineStyle {
24861                            thickness: px(1.),
24862                            color: None,
24863                            wavy: false,
24864                        }),
24865                        ..Default::default()
24866                    },
24867                    cx,
24868                );
24869            }
24870
24871            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24872            let use_autoclose = this.use_autoclose;
24873            let use_auto_surround = this.use_auto_surround;
24874            this.set_use_autoclose(false);
24875            this.set_use_auto_surround(false);
24876            this.handle_input(text, window, cx);
24877            this.set_use_autoclose(use_autoclose);
24878            this.set_use_auto_surround(use_auto_surround);
24879
24880            if let Some(new_selected_range) = new_selected_range_utf16 {
24881                let snapshot = this.buffer.read(cx).read(cx);
24882                let new_selected_ranges = marked_ranges
24883                    .into_iter()
24884                    .map(|marked_range| {
24885                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24886                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24887                            insertion_start.0 + new_selected_range.start,
24888                        ));
24889                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24890                            insertion_start.0 + new_selected_range.end,
24891                        ));
24892                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24893                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24894                    })
24895                    .collect::<Vec<_>>();
24896
24897                drop(snapshot);
24898                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24899                    selections.select_ranges(new_selected_ranges)
24900                });
24901            }
24902        });
24903
24904        self.ime_transaction = self.ime_transaction.or(transaction);
24905        if let Some(transaction) = self.ime_transaction {
24906            self.buffer.update(cx, |buffer, cx| {
24907                buffer.group_until_transaction(transaction, cx);
24908            });
24909        }
24910
24911        if self.text_highlights::<InputComposition>(cx).is_none() {
24912            self.ime_transaction.take();
24913        }
24914    }
24915
24916    fn bounds_for_range(
24917        &mut self,
24918        range_utf16: Range<usize>,
24919        element_bounds: gpui::Bounds<Pixels>,
24920        window: &mut Window,
24921        cx: &mut Context<Self>,
24922    ) -> Option<gpui::Bounds<Pixels>> {
24923        let text_layout_details = self.text_layout_details(window);
24924        let CharacterDimensions {
24925            em_width,
24926            em_advance,
24927            line_height,
24928        } = self.character_dimensions(window);
24929
24930        let snapshot = self.snapshot(window, cx);
24931        let scroll_position = snapshot.scroll_position();
24932        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24933
24934        let start =
24935            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24936        let x = Pixels::from(
24937            ScrollOffset::from(
24938                snapshot.x_for_display_point(start, &text_layout_details)
24939                    + self.gutter_dimensions.full_width(),
24940            ) - scroll_left,
24941        );
24942        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24943
24944        Some(Bounds {
24945            origin: element_bounds.origin + point(x, y),
24946            size: size(em_width, line_height),
24947        })
24948    }
24949
24950    fn character_index_for_point(
24951        &mut self,
24952        point: gpui::Point<Pixels>,
24953        _window: &mut Window,
24954        _cx: &mut Context<Self>,
24955    ) -> Option<usize> {
24956        let position_map = self.last_position_map.as_ref()?;
24957        if !position_map.text_hitbox.contains(&point) {
24958            return None;
24959        }
24960        let display_point = position_map.point_for_position(point).previous_valid;
24961        let anchor = position_map
24962            .snapshot
24963            .display_point_to_anchor(display_point, Bias::Left);
24964        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24965        Some(utf16_offset.0.0)
24966    }
24967
24968    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24969        self.input_enabled
24970    }
24971}
24972
24973trait SelectionExt {
24974    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24975    fn spanned_rows(
24976        &self,
24977        include_end_if_at_line_start: bool,
24978        map: &DisplaySnapshot,
24979    ) -> Range<MultiBufferRow>;
24980}
24981
24982impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24983    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24984        let start = self
24985            .start
24986            .to_point(map.buffer_snapshot())
24987            .to_display_point(map);
24988        let end = self
24989            .end
24990            .to_point(map.buffer_snapshot())
24991            .to_display_point(map);
24992        if self.reversed {
24993            end..start
24994        } else {
24995            start..end
24996        }
24997    }
24998
24999    fn spanned_rows(
25000        &self,
25001        include_end_if_at_line_start: bool,
25002        map: &DisplaySnapshot,
25003    ) -> Range<MultiBufferRow> {
25004        let start = self.start.to_point(map.buffer_snapshot());
25005        let mut end = self.end.to_point(map.buffer_snapshot());
25006        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25007            end.row -= 1;
25008        }
25009
25010        let buffer_start = map.prev_line_boundary(start).0;
25011        let buffer_end = map.next_line_boundary(end).0;
25012        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25013    }
25014}
25015
25016impl<T: InvalidationRegion> InvalidationStack<T> {
25017    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25018    where
25019        S: Clone + ToOffset,
25020    {
25021        while let Some(region) = self.last() {
25022            let all_selections_inside_invalidation_ranges =
25023                if selections.len() == region.ranges().len() {
25024                    selections
25025                        .iter()
25026                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25027                        .all(|(selection, invalidation_range)| {
25028                            let head = selection.head().to_offset(buffer);
25029                            invalidation_range.start <= head && invalidation_range.end >= head
25030                        })
25031                } else {
25032                    false
25033                };
25034
25035            if all_selections_inside_invalidation_ranges {
25036                break;
25037            } else {
25038                self.pop();
25039            }
25040        }
25041    }
25042}
25043
25044impl<T> Default for InvalidationStack<T> {
25045    fn default() -> Self {
25046        Self(Default::default())
25047    }
25048}
25049
25050impl<T> Deref for InvalidationStack<T> {
25051    type Target = Vec<T>;
25052
25053    fn deref(&self) -> &Self::Target {
25054        &self.0
25055    }
25056}
25057
25058impl<T> DerefMut for InvalidationStack<T> {
25059    fn deref_mut(&mut self) -> &mut Self::Target {
25060        &mut self.0
25061    }
25062}
25063
25064impl InvalidationRegion for SnippetState {
25065    fn ranges(&self) -> &[Range<Anchor>] {
25066        &self.ranges[self.active_index]
25067    }
25068}
25069
25070fn edit_prediction_edit_text(
25071    current_snapshot: &BufferSnapshot,
25072    edits: &[(Range<Anchor>, impl AsRef<str>)],
25073    edit_preview: &EditPreview,
25074    include_deletions: bool,
25075    cx: &App,
25076) -> HighlightedText {
25077    let edits = edits
25078        .iter()
25079        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25080        .collect::<Vec<_>>();
25081
25082    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25083}
25084
25085fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25086    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25087    // Just show the raw edit text with basic styling
25088    let mut text = String::new();
25089    let mut highlights = Vec::new();
25090
25091    let insertion_highlight_style = HighlightStyle {
25092        color: Some(cx.theme().colors().text),
25093        ..Default::default()
25094    };
25095
25096    for (_, edit_text) in edits {
25097        let start_offset = text.len();
25098        text.push_str(edit_text);
25099        let end_offset = text.len();
25100
25101        if start_offset < end_offset {
25102            highlights.push((start_offset..end_offset, insertion_highlight_style));
25103        }
25104    }
25105
25106    HighlightedText {
25107        text: text.into(),
25108        highlights,
25109    }
25110}
25111
25112pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25113    match severity {
25114        lsp::DiagnosticSeverity::ERROR => colors.error,
25115        lsp::DiagnosticSeverity::WARNING => colors.warning,
25116        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25117        lsp::DiagnosticSeverity::HINT => colors.info,
25118        _ => colors.ignored,
25119    }
25120}
25121
25122pub fn styled_runs_for_code_label<'a>(
25123    label: &'a CodeLabel,
25124    syntax_theme: &'a theme::SyntaxTheme,
25125    local_player: &'a theme::PlayerColor,
25126) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25127    let fade_out = HighlightStyle {
25128        fade_out: Some(0.35),
25129        ..Default::default()
25130    };
25131
25132    let mut prev_end = label.filter_range.end;
25133    label
25134        .runs
25135        .iter()
25136        .enumerate()
25137        .flat_map(move |(ix, (range, highlight_id))| {
25138            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25139                HighlightStyle {
25140                    color: Some(local_player.cursor),
25141                    ..Default::default()
25142                }
25143            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25144                HighlightStyle {
25145                    background_color: Some(local_player.selection),
25146                    ..Default::default()
25147                }
25148            } else if let Some(style) = highlight_id.style(syntax_theme) {
25149                style
25150            } else {
25151                return Default::default();
25152            };
25153            let muted_style = style.highlight(fade_out);
25154
25155            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25156            if range.start >= label.filter_range.end {
25157                if range.start > prev_end {
25158                    runs.push((prev_end..range.start, fade_out));
25159                }
25160                runs.push((range.clone(), muted_style));
25161            } else if range.end <= label.filter_range.end {
25162                runs.push((range.clone(), style));
25163            } else {
25164                runs.push((range.start..label.filter_range.end, style));
25165                runs.push((label.filter_range.end..range.end, muted_style));
25166            }
25167            prev_end = cmp::max(prev_end, range.end);
25168
25169            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25170                runs.push((prev_end..label.text.len(), fade_out));
25171            }
25172
25173            runs
25174        })
25175}
25176
25177pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25178    let mut prev_index = 0;
25179    let mut prev_codepoint: Option<char> = None;
25180    text.char_indices()
25181        .chain([(text.len(), '\0')])
25182        .filter_map(move |(index, codepoint)| {
25183            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25184            let is_boundary = index == text.len()
25185                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25186                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25187            if is_boundary {
25188                let chunk = &text[prev_index..index];
25189                prev_index = index;
25190                Some(chunk)
25191            } else {
25192                None
25193            }
25194        })
25195}
25196
25197/// Given a string of text immediately before the cursor, iterates over possible
25198/// strings a snippet could match to. More precisely: returns an iterator over
25199/// suffixes of `text` created by splitting at word boundaries (before & after
25200/// every non-word character).
25201///
25202/// Shorter suffixes are returned first.
25203pub(crate) fn snippet_candidate_suffixes(
25204    text: &str,
25205    is_word_char: impl Fn(char) -> bool,
25206) -> impl std::iter::Iterator<Item = &str> {
25207    let mut prev_index = text.len();
25208    let mut prev_codepoint = None;
25209    text.char_indices()
25210        .rev()
25211        .chain([(0, '\0')])
25212        .filter_map(move |(index, codepoint)| {
25213            let prev_index = std::mem::replace(&mut prev_index, index);
25214            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25215            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25216                None
25217            } else {
25218                let chunk = &text[prev_index..]; // go to end of string
25219                Some(chunk)
25220            }
25221        })
25222}
25223
25224pub trait RangeToAnchorExt: Sized {
25225    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25226
25227    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25228        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25229        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25230    }
25231}
25232
25233impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25234    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25235        let start_offset = self.start.to_offset(snapshot);
25236        let end_offset = self.end.to_offset(snapshot);
25237        if start_offset == end_offset {
25238            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25239        } else {
25240            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25241        }
25242    }
25243}
25244
25245pub trait RowExt {
25246    fn as_f64(&self) -> f64;
25247
25248    fn next_row(&self) -> Self;
25249
25250    fn previous_row(&self) -> Self;
25251
25252    fn minus(&self, other: Self) -> u32;
25253}
25254
25255impl RowExt for DisplayRow {
25256    fn as_f64(&self) -> f64 {
25257        self.0 as _
25258    }
25259
25260    fn next_row(&self) -> Self {
25261        Self(self.0 + 1)
25262    }
25263
25264    fn previous_row(&self) -> Self {
25265        Self(self.0.saturating_sub(1))
25266    }
25267
25268    fn minus(&self, other: Self) -> u32 {
25269        self.0 - other.0
25270    }
25271}
25272
25273impl RowExt for MultiBufferRow {
25274    fn as_f64(&self) -> f64 {
25275        self.0 as _
25276    }
25277
25278    fn next_row(&self) -> Self {
25279        Self(self.0 + 1)
25280    }
25281
25282    fn previous_row(&self) -> Self {
25283        Self(self.0.saturating_sub(1))
25284    }
25285
25286    fn minus(&self, other: Self) -> u32 {
25287        self.0 - other.0
25288    }
25289}
25290
25291trait RowRangeExt {
25292    type Row;
25293
25294    fn len(&self) -> usize;
25295
25296    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25297}
25298
25299impl RowRangeExt for Range<MultiBufferRow> {
25300    type Row = MultiBufferRow;
25301
25302    fn len(&self) -> usize {
25303        (self.end.0 - self.start.0) as usize
25304    }
25305
25306    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25307        (self.start.0..self.end.0).map(MultiBufferRow)
25308    }
25309}
25310
25311impl RowRangeExt for Range<DisplayRow> {
25312    type Row = DisplayRow;
25313
25314    fn len(&self) -> usize {
25315        (self.end.0 - self.start.0) as usize
25316    }
25317
25318    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25319        (self.start.0..self.end.0).map(DisplayRow)
25320    }
25321}
25322
25323/// If select range has more than one line, we
25324/// just point the cursor to range.start.
25325fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25326    if range.start.row == range.end.row {
25327        range
25328    } else {
25329        range.start..range.start
25330    }
25331}
25332pub struct KillRing(ClipboardItem);
25333impl Global for KillRing {}
25334
25335const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25336
25337enum BreakpointPromptEditAction {
25338    Log,
25339    Condition,
25340    HitCondition,
25341}
25342
25343struct BreakpointPromptEditor {
25344    pub(crate) prompt: Entity<Editor>,
25345    editor: WeakEntity<Editor>,
25346    breakpoint_anchor: Anchor,
25347    breakpoint: Breakpoint,
25348    edit_action: BreakpointPromptEditAction,
25349    block_ids: HashSet<CustomBlockId>,
25350    editor_margins: Arc<Mutex<EditorMargins>>,
25351    _subscriptions: Vec<Subscription>,
25352}
25353
25354impl BreakpointPromptEditor {
25355    const MAX_LINES: u8 = 4;
25356
25357    fn new(
25358        editor: WeakEntity<Editor>,
25359        breakpoint_anchor: Anchor,
25360        breakpoint: Breakpoint,
25361        edit_action: BreakpointPromptEditAction,
25362        window: &mut Window,
25363        cx: &mut Context<Self>,
25364    ) -> Self {
25365        let base_text = match edit_action {
25366            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25367            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25368            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25369        }
25370        .map(|msg| msg.to_string())
25371        .unwrap_or_default();
25372
25373        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25374        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25375
25376        let prompt = cx.new(|cx| {
25377            let mut prompt = Editor::new(
25378                EditorMode::AutoHeight {
25379                    min_lines: 1,
25380                    max_lines: Some(Self::MAX_LINES as usize),
25381                },
25382                buffer,
25383                None,
25384                window,
25385                cx,
25386            );
25387            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25388            prompt.set_show_cursor_when_unfocused(false, cx);
25389            prompt.set_placeholder_text(
25390                match edit_action {
25391                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25392                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25393                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25394                },
25395                window,
25396                cx,
25397            );
25398
25399            prompt
25400        });
25401
25402        Self {
25403            prompt,
25404            editor,
25405            breakpoint_anchor,
25406            breakpoint,
25407            edit_action,
25408            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25409            block_ids: Default::default(),
25410            _subscriptions: vec![],
25411        }
25412    }
25413
25414    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25415        self.block_ids.extend(block_ids)
25416    }
25417
25418    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25419        if let Some(editor) = self.editor.upgrade() {
25420            let message = self
25421                .prompt
25422                .read(cx)
25423                .buffer
25424                .read(cx)
25425                .as_singleton()
25426                .expect("A multi buffer in breakpoint prompt isn't possible")
25427                .read(cx)
25428                .as_rope()
25429                .to_string();
25430
25431            editor.update(cx, |editor, cx| {
25432                editor.edit_breakpoint_at_anchor(
25433                    self.breakpoint_anchor,
25434                    self.breakpoint.clone(),
25435                    match self.edit_action {
25436                        BreakpointPromptEditAction::Log => {
25437                            BreakpointEditAction::EditLogMessage(message.into())
25438                        }
25439                        BreakpointPromptEditAction::Condition => {
25440                            BreakpointEditAction::EditCondition(message.into())
25441                        }
25442                        BreakpointPromptEditAction::HitCondition => {
25443                            BreakpointEditAction::EditHitCondition(message.into())
25444                        }
25445                    },
25446                    cx,
25447                );
25448
25449                editor.remove_blocks(self.block_ids.clone(), None, cx);
25450                cx.focus_self(window);
25451            });
25452        }
25453    }
25454
25455    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25456        self.editor
25457            .update(cx, |editor, cx| {
25458                editor.remove_blocks(self.block_ids.clone(), None, cx);
25459                window.focus(&editor.focus_handle);
25460            })
25461            .log_err();
25462    }
25463
25464    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25465        let settings = ThemeSettings::get_global(cx);
25466        let text_style = TextStyle {
25467            color: if self.prompt.read(cx).read_only(cx) {
25468                cx.theme().colors().text_disabled
25469            } else {
25470                cx.theme().colors().text
25471            },
25472            font_family: settings.buffer_font.family.clone(),
25473            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25474            font_size: settings.buffer_font_size(cx).into(),
25475            font_weight: settings.buffer_font.weight,
25476            line_height: relative(settings.buffer_line_height.value()),
25477            ..Default::default()
25478        };
25479        EditorElement::new(
25480            &self.prompt,
25481            EditorStyle {
25482                background: cx.theme().colors().editor_background,
25483                local_player: cx.theme().players().local(),
25484                text: text_style,
25485                ..Default::default()
25486            },
25487        )
25488    }
25489}
25490
25491impl Render for BreakpointPromptEditor {
25492    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25493        let editor_margins = *self.editor_margins.lock();
25494        let gutter_dimensions = editor_margins.gutter;
25495        h_flex()
25496            .key_context("Editor")
25497            .bg(cx.theme().colors().editor_background)
25498            .border_y_1()
25499            .border_color(cx.theme().status().info_border)
25500            .size_full()
25501            .py(window.line_height() / 2.5)
25502            .on_action(cx.listener(Self::confirm))
25503            .on_action(cx.listener(Self::cancel))
25504            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25505            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25506    }
25507}
25508
25509impl Focusable for BreakpointPromptEditor {
25510    fn focus_handle(&self, cx: &App) -> FocusHandle {
25511        self.prompt.focus_handle(cx)
25512    }
25513}
25514
25515fn all_edits_insertions_or_deletions(
25516    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25517    snapshot: &MultiBufferSnapshot,
25518) -> bool {
25519    let mut all_insertions = true;
25520    let mut all_deletions = true;
25521
25522    for (range, new_text) in edits.iter() {
25523        let range_is_empty = range.to_offset(snapshot).is_empty();
25524        let text_is_empty = new_text.is_empty();
25525
25526        if range_is_empty != text_is_empty {
25527            if range_is_empty {
25528                all_deletions = false;
25529            } else {
25530                all_insertions = false;
25531            }
25532        } else {
25533            return false;
25534        }
25535
25536        if !all_insertions && !all_deletions {
25537            return false;
25538        }
25539    }
25540    all_insertions || all_deletions
25541}
25542
25543struct MissingEditPredictionKeybindingTooltip;
25544
25545impl Render for MissingEditPredictionKeybindingTooltip {
25546    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25547        ui::tooltip_container(cx, |container, cx| {
25548            container
25549                .flex_shrink_0()
25550                .max_w_80()
25551                .min_h(rems_from_px(124.))
25552                .justify_between()
25553                .child(
25554                    v_flex()
25555                        .flex_1()
25556                        .text_ui_sm(cx)
25557                        .child(Label::new("Conflict with Accept Keybinding"))
25558                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25559                )
25560                .child(
25561                    h_flex()
25562                        .pb_1()
25563                        .gap_1()
25564                        .items_end()
25565                        .w_full()
25566                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25567                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25568                        }))
25569                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25570                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25571                        })),
25572                )
25573        })
25574    }
25575}
25576
25577#[derive(Debug, Clone, Copy, PartialEq)]
25578pub struct LineHighlight {
25579    pub background: Background,
25580    pub border: Option<gpui::Hsla>,
25581    pub include_gutter: bool,
25582    pub type_id: Option<TypeId>,
25583}
25584
25585struct LineManipulationResult {
25586    pub new_text: String,
25587    pub line_count_before: usize,
25588    pub line_count_after: usize,
25589}
25590
25591fn render_diff_hunk_controls(
25592    row: u32,
25593    status: &DiffHunkStatus,
25594    hunk_range: Range<Anchor>,
25595    is_created_file: bool,
25596    line_height: Pixels,
25597    editor: &Entity<Editor>,
25598    _window: &mut Window,
25599    cx: &mut App,
25600) -> AnyElement {
25601    h_flex()
25602        .h(line_height)
25603        .mr_1()
25604        .gap_1()
25605        .px_0p5()
25606        .pb_1()
25607        .border_x_1()
25608        .border_b_1()
25609        .border_color(cx.theme().colors().border_variant)
25610        .rounded_b_lg()
25611        .bg(cx.theme().colors().editor_background)
25612        .gap_1()
25613        .block_mouse_except_scroll()
25614        .shadow_md()
25615        .child(if status.has_secondary_hunk() {
25616            Button::new(("stage", row as u64), "Stage")
25617                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25618                .tooltip({
25619                    let focus_handle = editor.focus_handle(cx);
25620                    move |_window, cx| {
25621                        Tooltip::for_action_in(
25622                            "Stage Hunk",
25623                            &::git::ToggleStaged,
25624                            &focus_handle,
25625                            cx,
25626                        )
25627                    }
25628                })
25629                .on_click({
25630                    let editor = editor.clone();
25631                    move |_event, _window, cx| {
25632                        editor.update(cx, |editor, cx| {
25633                            editor.stage_or_unstage_diff_hunks(
25634                                true,
25635                                vec![hunk_range.start..hunk_range.start],
25636                                cx,
25637                            );
25638                        });
25639                    }
25640                })
25641        } else {
25642            Button::new(("unstage", row as u64), "Unstage")
25643                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25644                .tooltip({
25645                    let focus_handle = editor.focus_handle(cx);
25646                    move |_window, cx| {
25647                        Tooltip::for_action_in(
25648                            "Unstage Hunk",
25649                            &::git::ToggleStaged,
25650                            &focus_handle,
25651                            cx,
25652                        )
25653                    }
25654                })
25655                .on_click({
25656                    let editor = editor.clone();
25657                    move |_event, _window, cx| {
25658                        editor.update(cx, |editor, cx| {
25659                            editor.stage_or_unstage_diff_hunks(
25660                                false,
25661                                vec![hunk_range.start..hunk_range.start],
25662                                cx,
25663                            );
25664                        });
25665                    }
25666                })
25667        })
25668        .child(
25669            Button::new(("restore", row as u64), "Restore")
25670                .tooltip({
25671                    let focus_handle = editor.focus_handle(cx);
25672                    move |_window, cx| {
25673                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25674                    }
25675                })
25676                .on_click({
25677                    let editor = editor.clone();
25678                    move |_event, window, cx| {
25679                        editor.update(cx, |editor, cx| {
25680                            let snapshot = editor.snapshot(window, cx);
25681                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25682                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25683                        });
25684                    }
25685                })
25686                .disabled(is_created_file),
25687        )
25688        .when(
25689            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25690            |el| {
25691                el.child(
25692                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25693                        .shape(IconButtonShape::Square)
25694                        .icon_size(IconSize::Small)
25695                        // .disabled(!has_multiple_hunks)
25696                        .tooltip({
25697                            let focus_handle = editor.focus_handle(cx);
25698                            move |_window, cx| {
25699                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25700                            }
25701                        })
25702                        .on_click({
25703                            let editor = editor.clone();
25704                            move |_event, window, cx| {
25705                                editor.update(cx, |editor, cx| {
25706                                    let snapshot = editor.snapshot(window, cx);
25707                                    let position =
25708                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25709                                    editor.go_to_hunk_before_or_after_position(
25710                                        &snapshot,
25711                                        position,
25712                                        Direction::Next,
25713                                        window,
25714                                        cx,
25715                                    );
25716                                    editor.expand_selected_diff_hunks(cx);
25717                                });
25718                            }
25719                        }),
25720                )
25721                .child(
25722                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25723                        .shape(IconButtonShape::Square)
25724                        .icon_size(IconSize::Small)
25725                        // .disabled(!has_multiple_hunks)
25726                        .tooltip({
25727                            let focus_handle = editor.focus_handle(cx);
25728                            move |_window, cx| {
25729                                Tooltip::for_action_in(
25730                                    "Previous Hunk",
25731                                    &GoToPreviousHunk,
25732                                    &focus_handle,
25733                                    cx,
25734                                )
25735                            }
25736                        })
25737                        .on_click({
25738                            let editor = editor.clone();
25739                            move |_event, window, cx| {
25740                                editor.update(cx, |editor, cx| {
25741                                    let snapshot = editor.snapshot(window, cx);
25742                                    let point =
25743                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25744                                    editor.go_to_hunk_before_or_after_position(
25745                                        &snapshot,
25746                                        point,
25747                                        Direction::Prev,
25748                                        window,
25749                                        cx,
25750                                    );
25751                                    editor.expand_selected_diff_hunks(cx);
25752                                });
25753                            }
25754                        }),
25755                )
25756            },
25757        )
25758        .into_any_element()
25759}
25760
25761pub fn multibuffer_context_lines(cx: &App) -> u32 {
25762    EditorSettings::try_get(cx)
25763        .map(|settings| settings.excerpt_context_lines)
25764        .unwrap_or(2)
25765        .min(32)
25766}